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 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isTouch = (function() {
68 document.createEvent("TouchEvent");
75 // remove css image flicker
78 document.execCommand("BackgroundImageCache", false, true);
84 * True if the browser is in strict mode
89 * True if the page is running over SSL
94 * True when the document is fully initialized and ready for action
99 * Turn on debugging output (currently only the factory uses this)
106 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
109 enableGarbageCollector : true,
112 * True to automatically purge event listeners after uncaching an element (defaults to false).
113 * Note: this only happens if enableGarbageCollector is true.
116 enableListenerCollection:false,
119 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
120 * the IE insecure content warning (defaults to javascript:false).
123 SSL_SECURE_URL : "javascript:false",
126 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
127 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
130 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
132 emptyFn : function(){},
135 * Copies all the properties of config to obj if they don't already exist.
136 * @param {Object} obj The receiver of the properties
137 * @param {Object} config The source of the properties
138 * @return {Object} returns obj
140 applyIf : function(o, c){
143 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
150 * Applies event listeners to elements by selectors when the document is ready.
151 * The event name is specified with an @ suffix.
154 // add a listener for click on all anchors in element with id foo
155 '#foo a@click' : function(e, t){
159 // add the same listener to multiple selectors (separated by comma BEFORE the @)
160 '#foo a, #bar span.some-class@mouseover' : function(){
165 * @param {Object} obj The list of behaviors to apply
167 addBehaviors : function(o){
169 Roo.onReady(function(){
174 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
176 var parts = b.split('@');
177 if(parts[1]){ // for Object prototype breakers
180 cache[s] = Roo.select(s);
182 cache[s].on(parts[1], o[b]);
189 * Generates unique ids. If the element already has an id, it is unchanged
190 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
191 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
192 * @return {String} The generated Id.
194 id : function(el, prefix){
195 prefix = prefix || "roo-gen";
197 var id = prefix + (++idSeed);
198 return el ? (el.id ? el.id : (el.id = id)) : id;
203 * Extends one class with another class and optionally overrides members with the passed literal. This class
204 * also adds the function "override()" to the class that can be used to override
205 * members on an instance.
206 * @param {Object} subclass The class inheriting the functionality
207 * @param {Object} superclass The class being extended
208 * @param {Object} overrides (optional) A literal with members
213 var io = function(o){
218 return function(sb, sp, overrides){
219 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
222 sb = function(){sp.apply(this, arguments);};
224 var F = function(){}, sbp, spp = sp.prototype;
226 sbp = sb.prototype = new F();
230 if(spp.constructor == Object.prototype.constructor){
235 sb.override = function(o){
239 Roo.override(sb, overrides);
245 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
247 Roo.override(MyClass, {
248 newMethod1: function(){
251 newMethod2: function(foo){
256 * @param {Object} origclass The class to override
257 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
258 * containing one or more methods.
261 override : function(origclass, overrides){
263 var p = origclass.prototype;
264 for(var method in overrides){
265 p[method] = overrides[method];
270 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
272 Roo.namespace('Company', 'Company.data');
273 Company.Widget = function() { ... }
274 Company.data.CustomStore = function(config) { ... }
276 * @param {String} namespace1
277 * @param {String} namespace2
278 * @param {String} etc
281 namespace : function(){
282 var a=arguments, o=null, i, j, d, rt;
283 for (i=0; i<a.length; ++i) {
287 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
288 for (j=1; j<d.length; ++j) {
289 o[d[j]]=o[d[j]] || {};
295 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
297 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
298 Roo.factory(conf, Roo.data);
300 * @param {String} classname
301 * @param {String} namespace (optional)
305 factory : function(c, ns)
307 // no xtype, no ns or c.xns - or forced off by c.xns
308 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
311 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
312 if (c.constructor == ns[c.xtype]) {// already created...
316 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
317 var ret = new ns[c.xtype](c);
321 c.xns = false; // prevent recursion..
325 * Logs to console if it can.
327 * @param {String|Object} string
332 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
339 * 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.
343 urlEncode : function(o){
349 var ov = o[key], k = Roo.encodeURIComponent(key);
350 var type = typeof ov;
351 if(type == 'undefined'){
353 }else if(type != "function" && type != "object"){
354 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
355 }else if(ov instanceof Array){
357 for(var i = 0, len = ov.length; i < len; i++) {
358 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369 * Safe version of encodeURIComponent
370 * @param {String} data
374 encodeURIComponent : function (data)
377 return encodeURIComponent(data);
378 } catch(e) {} // should be an uri encode error.
380 if (data == '' || data == null){
383 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
384 function nibble_to_hex(nibble){
385 var chars = '0123456789ABCDEF';
386 return chars.charAt(nibble);
388 data = data.toString();
390 for(var i=0; i<data.length; i++){
391 var c = data.charCodeAt(i);
392 var bs = new Array();
395 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
396 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
397 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
398 bs[3] = 0x80 | (c & 0x3F);
399 }else if (c > 0x800){
401 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
402 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
403 bs[2] = 0x80 | (c & 0x3F);
406 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
407 bs[1] = 0x80 | (c & 0x3F);
412 for(var j=0; j<bs.length; j++){
414 var hex = nibble_to_hex((b & 0xF0) >>> 4)
415 + nibble_to_hex(b &0x0F);
424 * 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]}.
425 * @param {String} string
426 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
427 * @return {Object} A literal with members
429 urlDecode : function(string, overwrite){
430 if(!string || !string.length){
434 var pairs = string.split('&');
435 var pair, name, value;
436 for(var i = 0, len = pairs.length; i < len; i++){
437 pair = pairs[i].split('=');
438 name = decodeURIComponent(pair[0]);
439 value = decodeURIComponent(pair[1]);
440 if(overwrite !== true){
441 if(typeof obj[name] == "undefined"){
443 }else if(typeof obj[name] == "string"){
444 obj[name] = [obj[name]];
445 obj[name].push(value);
447 obj[name].push(value);
457 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
458 * passed array is not really an array, your function is called once with it.
459 * The supplied function is called with (Object item, Number index, Array allItems).
460 * @param {Array/NodeList/Mixed} array
461 * @param {Function} fn
462 * @param {Object} scope
464 each : function(array, fn, scope){
465 if(typeof array.length == "undefined" || typeof array == "string"){
468 for(var i = 0, len = array.length; i < len; i++){
469 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
474 combine : function(){
475 var as = arguments, l = as.length, r = [];
476 for(var i = 0; i < l; i++){
478 if(a instanceof Array){
480 }else if(a.length !== undefined && !a.substr){
481 r = r.concat(Array.prototype.slice.call(a, 0));
490 * Escapes the passed string for use in a regular expression
491 * @param {String} str
494 escapeRe : function(s) {
495 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
499 callback : function(cb, scope, args, delay){
500 if(typeof cb == "function"){
502 cb.defer(delay, scope, args || []);
504 cb.apply(scope, args || []);
510 * Return the dom node for the passed string (id), dom node, or Roo.Element
511 * @param {String/HTMLElement/Roo.Element} el
512 * @return HTMLElement
514 getDom : function(el){
518 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
522 * Shorthand for {@link Roo.ComponentMgr#get}
524 * @return Roo.Component
526 getCmp : function(id){
527 return Roo.ComponentMgr.get(id);
530 num : function(v, defaultValue){
531 if(typeof v != 'number'){
537 destroy : function(){
538 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
542 as.removeAllListeners();
546 if(typeof as.purgeListeners == 'function'){
549 if(typeof as.destroy == 'function'){
556 // inpired by a similar function in mootools library
558 * Returns the type of object that is passed in. If the object passed in is null or undefined it
559 * return false otherwise it returns one of the following values:<ul>
560 * <li><b>string</b>: If the object passed is a string</li>
561 * <li><b>number</b>: If the object passed is a number</li>
562 * <li><b>boolean</b>: If the object passed is a boolean value</li>
563 * <li><b>function</b>: If the object passed is a function reference</li>
564 * <li><b>object</b>: If the object passed is an object</li>
565 * <li><b>array</b>: If the object passed is an array</li>
566 * <li><b>regexp</b>: If the object passed is a regular expression</li>
567 * <li><b>element</b>: If the object passed is a DOM Element</li>
568 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
569 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
570 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
571 * @param {Mixed} object
575 if(o === undefined || o === null){
582 if(t == 'object' && o.nodeName) {
584 case 1: return 'element';
585 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
588 if(t == 'object' || t == 'function') {
589 switch(o.constructor) {
590 case Array: return 'array';
591 case RegExp: return 'regexp';
593 if(typeof o.length == 'number' && typeof o.item == 'function') {
601 * Returns true if the passed value is null, undefined or an empty string (optional).
602 * @param {Mixed} value The value to test
603 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
606 isEmpty : function(v, allowBlank){
607 return v === null || v === undefined || (!allowBlank ? v === '' : false);
615 isFirefox : isFirefox,
625 isBorderBox : isBorderBox,
627 isWindows : isWindows,
636 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
637 * you may want to set this to true.
640 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
645 * Selects a single element as a Roo Element
646 * This is about as close as you can get to jQuery's $('do crazy stuff')
647 * @param {String} selector The selector/xpath query
648 * @param {Node} root (optional) The start of the query (defaults to document).
649 * @return {Roo.Element}
651 selectNode : function(selector, root)
653 var node = Roo.DomQuery.selectNode(selector,root);
654 return node ? Roo.get(node) : new Roo.Element(false);
662 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
663 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
666 "Roo.bootstrap.dash");
669 * Ext JS Library 1.1.1
670 * Copyright(c) 2006-2007, Ext JS, LLC.
672 * Originally Released Under LGPL - original licence link has changed is not relivant.
675 * <script type="text/javascript">
679 // wrappedn so fnCleanup is not in global scope...
681 function fnCleanUp() {
682 var p = Function.prototype;
683 delete p.createSequence;
685 delete p.createDelegate;
686 delete p.createCallback;
687 delete p.createInterceptor;
689 window.detachEvent("onunload", fnCleanUp);
691 window.attachEvent("onunload", fnCleanUp);
698 * These functions are available on every Function object (any JavaScript function).
700 Roo.apply(Function.prototype, {
702 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
703 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
704 * Will create a function that is bound to those 2 args.
705 * @return {Function} The new function
707 createCallback : function(/*args...*/){
708 // make args available, in function below
709 var args = arguments;
712 return method.apply(window, args);
717 * Creates a delegate (callback) that sets the scope to obj.
718 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
719 * Will create a function that is automatically scoped to this.
720 * @param {Object} obj (optional) The object for which the scope is set
721 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
722 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
723 * if a number the args are inserted at the specified position
724 * @return {Function} The new function
726 createDelegate : function(obj, args, appendArgs){
729 var callArgs = args || arguments;
730 if(appendArgs === true){
731 callArgs = Array.prototype.slice.call(arguments, 0);
732 callArgs = callArgs.concat(args);
733 }else if(typeof appendArgs == "number"){
734 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
735 var applyArgs = [appendArgs, 0].concat(args); // create method call params
736 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
738 return method.apply(obj || window, callArgs);
743 * Calls this function after the number of millseconds specified.
744 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
745 * @param {Object} obj (optional) The object for which the scope is set
746 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
747 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
748 * if a number the args are inserted at the specified position
749 * @return {Number} The timeout id that can be used with clearTimeout
751 defer : function(millis, obj, args, appendArgs){
752 var fn = this.createDelegate(obj, args, appendArgs);
754 return setTimeout(fn, millis);
760 * Create a combined function call sequence of the original function + the passed function.
761 * The resulting function returns the results of the original function.
762 * The passed fcn is called with the parameters of the original function
763 * @param {Function} fcn The function to sequence
764 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
765 * @return {Function} The new function
767 createSequence : function(fcn, scope){
768 if(typeof fcn != "function"){
773 var retval = method.apply(this || window, arguments);
774 fcn.apply(scope || this || window, arguments);
780 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
781 * The resulting function returns the results of the original function.
782 * The passed fcn is called with the parameters of the original function.
784 * @param {Function} fcn The function to call before the original
785 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
786 * @return {Function} The new function
788 createInterceptor : function(fcn, scope){
789 if(typeof fcn != "function"){
796 if(fcn.apply(scope || this || window, arguments) === false){
799 return method.apply(this || window, arguments);
805 * Ext JS Library 1.1.1
806 * Copyright(c) 2006-2007, Ext JS, LLC.
808 * Originally Released Under LGPL - original licence link has changed is not relivant.
811 * <script type="text/javascript">
814 Roo.applyIf(String, {
819 * Escapes the passed string for ' and \
820 * @param {String} string The string to escape
821 * @return {String} The escaped string
824 escape : function(string) {
825 return string.replace(/('|\\)/g, "\\$1");
829 * Pads the left side of a string with a specified character. This is especially useful
830 * for normalizing number and date strings. Example usage:
832 var s = String.leftPad('123', 5, '0');
833 // s now contains the string: '00123'
835 * @param {String} string The original string
836 * @param {Number} size The total length of the output string
837 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
838 * @return {String} The padded string
841 leftPad : function (val, size, ch) {
842 var result = new String(val);
843 if(ch === null || ch === undefined || ch === '') {
846 while (result.length < size) {
847 result = ch + result;
853 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
854 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
856 var cls = 'my-class', text = 'Some text';
857 var s = String.format('<div class="{0}">{1}</div>', cls, text);
858 // s now contains the string: '<div class="my-class">Some text</div>'
860 * @param {String} string The tokenized string to be formatted
861 * @param {String} value1 The value to replace token {0}
862 * @param {String} value2 Etc...
863 * @return {String} The formatted string
866 format : function(format){
867 var args = Array.prototype.slice.call(arguments, 1);
868 return format.replace(/\{(\d+)\}/g, function(m, i){
869 return Roo.util.Format.htmlEncode(args[i]);
875 * Utility function that allows you to easily switch a string between two alternating values. The passed value
876 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
877 * they are already different, the first value passed in is returned. Note that this method returns the new value
878 * but does not change the current string.
880 // alternate sort directions
881 sort = sort.toggle('ASC', 'DESC');
883 // instead of conditional logic:
884 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
886 * @param {String} value The value to compare to the current string
887 * @param {String} other The new value to use if the string already equals the first value passed in
888 * @return {String} The new value
891 String.prototype.toggle = function(value, other){
892 return this == value ? other : value;
895 * Ext JS Library 1.1.1
896 * Copyright(c) 2006-2007, Ext JS, LLC.
898 * Originally Released Under LGPL - original licence link has changed is not relivant.
901 * <script type="text/javascript">
907 Roo.applyIf(Number.prototype, {
909 * Checks whether or not the current number is within a desired range. If the number is already within the
910 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
911 * exceeded. Note that this method returns the constrained value but does not change the current number.
912 * @param {Number} min The minimum number in the range
913 * @param {Number} max The maximum number in the range
914 * @return {Number} The constrained value if outside the range, otherwise the current value
916 constrain : function(min, max){
917 return Math.min(Math.max(this, min), max);
921 * Ext JS Library 1.1.1
922 * Copyright(c) 2006-2007, Ext JS, LLC.
924 * Originally Released Under LGPL - original licence link has changed is not relivant.
927 * <script type="text/javascript">
932 Roo.applyIf(Array.prototype, {
935 * Checks whether or not the specified object exists in the array.
936 * @param {Object} o The object to check for
937 * @return {Number} The index of o in the array (or -1 if it is not found)
939 indexOf : function(o){
940 for (var i = 0, len = this.length; i < len; i++){
941 if(this[i] == o) return i;
947 * Removes the specified object from the array. If the object is not found nothing happens.
948 * @param {Object} o The object to remove
950 remove : function(o){
951 var index = this.indexOf(o);
953 this.splice(index, 1);
957 * Map (JS 1.6 compatibility)
958 * @param {Function} function to call
962 var len = this.length >>> 0;
963 if (typeof fun != "function")
964 throw new TypeError();
966 var res = new Array(len);
967 var thisp = arguments[1];
968 for (var i = 0; i < len; i++)
971 res[i] = fun.call(thisp, this[i], i, this);
982 * Ext JS Library 1.1.1
983 * Copyright(c) 2006-2007, Ext JS, LLC.
985 * Originally Released Under LGPL - original licence link has changed is not relivant.
988 * <script type="text/javascript">
994 * The date parsing and format syntax is a subset of
995 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
996 * supported will provide results equivalent to their PHP versions.
998 * Following is the list of all currently supported formats:
1001 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1003 Format Output Description
1004 ------ ---------- --------------------------------------------------------------
1005 d 10 Day of the month, 2 digits with leading zeros
1006 D Wed A textual representation of a day, three letters
1007 j 10 Day of the month without leading zeros
1008 l Wednesday A full textual representation of the day of the week
1009 S th English ordinal day of month suffix, 2 chars (use with j)
1010 w 3 Numeric representation of the day of the week
1011 z 9 The julian date, or day of the year (0-365)
1012 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1013 F January A full textual representation of the month
1014 m 01 Numeric representation of a month, with leading zeros
1015 M Jan Month name abbreviation, three letters
1016 n 1 Numeric representation of a month, without leading zeros
1017 t 31 Number of days in the given month
1018 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1019 Y 2007 A full numeric representation of a year, 4 digits
1020 y 07 A two digit representation of a year
1021 a pm Lowercase Ante meridiem and Post meridiem
1022 A PM Uppercase Ante meridiem and Post meridiem
1023 g 3 12-hour format of an hour without leading zeros
1024 G 15 24-hour format of an hour without leading zeros
1025 h 03 12-hour format of an hour with leading zeros
1026 H 15 24-hour format of an hour with leading zeros
1027 i 05 Minutes with leading zeros
1028 s 01 Seconds, with leading zeros
1029 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1030 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1031 T CST Timezone setting of the machine running the code
1032 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1035 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1037 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1038 document.write(dt.format('Y-m-d')); //2007-01-10
1039 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1040 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
1043 * Here are some standard date/time patterns that you might find helpful. They
1044 * are not part of the source of Date.js, but to use them you can simply copy this
1045 * block of code into any script that is included after Date.js and they will also become
1046 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1049 ISO8601Long:"Y-m-d H:i:s",
1050 ISO8601Short:"Y-m-d",
1052 LongDate: "l, F d, Y",
1053 FullDateTime: "l, F d, Y g:i:s A",
1056 LongTime: "g:i:s A",
1057 SortableDateTime: "Y-m-d\\TH:i:s",
1058 UniversalSortableDateTime: "Y-m-d H:i:sO",
1065 var dt = new Date();
1066 document.write(dt.format(Date.patterns.ShortDate));
1071 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1072 * They generate precompiled functions from date formats instead of parsing and
1073 * processing the pattern every time you format a date. These functions are available
1074 * on every Date object (any javascript function).
1076 * The original article and download are here:
1077 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1084 Returns the number of milliseconds between this date and date
1085 @param {Date} date (optional) Defaults to now
1086 @return {Number} The diff in milliseconds
1087 @member Date getElapsed
1089 Date.prototype.getElapsed = function(date) {
1090 return Math.abs((date || new Date()).getTime()-this.getTime());
1092 // was in date file..
1096 Date.parseFunctions = {count:0};
1098 Date.parseRegexes = [];
1100 Date.formatFunctions = {count:0};
1103 Date.prototype.dateFormat = function(format) {
1104 if (Date.formatFunctions[format] == null) {
1105 Date.createNewFormat(format);
1107 var func = Date.formatFunctions[format];
1108 return this[func]();
1113 * Formats a date given the supplied format string
1114 * @param {String} format The format string
1115 * @return {String} The formatted date
1118 Date.prototype.format = Date.prototype.dateFormat;
1121 Date.createNewFormat = function(format) {
1122 var funcName = "format" + Date.formatFunctions.count++;
1123 Date.formatFunctions[format] = funcName;
1124 var code = "Date.prototype." + funcName + " = function(){return ";
1125 var special = false;
1127 for (var i = 0; i < format.length; ++i) {
1128 ch = format.charAt(i);
1129 if (!special && ch == "\\") {
1134 code += "'" + String.escape(ch) + "' + ";
1137 code += Date.getFormatCode(ch);
1140 /** eval:var:zzzzzzzzzzzzz */
1141 eval(code.substring(0, code.length - 3) + ";}");
1145 Date.getFormatCode = function(character) {
1146 switch (character) {
1148 return "String.leftPad(this.getDate(), 2, '0') + ";
1150 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1152 return "this.getDate() + ";
1154 return "Date.dayNames[this.getDay()] + ";
1156 return "this.getSuffix() + ";
1158 return "this.getDay() + ";
1160 return "this.getDayOfYear() + ";
1162 return "this.getWeekOfYear() + ";
1164 return "Date.monthNames[this.getMonth()] + ";
1166 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1168 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1170 return "(this.getMonth() + 1) + ";
1172 return "this.getDaysInMonth() + ";
1174 return "(this.isLeapYear() ? 1 : 0) + ";
1176 return "this.getFullYear() + ";
1178 return "('' + this.getFullYear()).substring(2, 4) + ";
1180 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1182 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1184 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1186 return "this.getHours() + ";
1188 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1190 return "String.leftPad(this.getHours(), 2, '0') + ";
1192 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1194 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1196 return "this.getGMTOffset() + ";
1198 return "this.getGMTColonOffset() + ";
1200 return "this.getTimezone() + ";
1202 return "(this.getTimezoneOffset() * -60) + ";
1204 return "'" + String.escape(character) + "' + ";
1209 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1210 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1211 * the date format that is not specified will default to the current date value for that part. Time parts can also
1212 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1213 * string or the parse operation will fail.
1216 //dt = Fri May 25 2007 (current date)
1217 var dt = new Date();
1219 //dt = Thu May 25 2006 (today's month/day in 2006)
1220 dt = Date.parseDate("2006", "Y");
1222 //dt = Sun Jan 15 2006 (all date parts specified)
1223 dt = Date.parseDate("2006-1-15", "Y-m-d");
1225 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1226 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1228 * @param {String} input The unparsed date as a string
1229 * @param {String} format The format the date is in
1230 * @return {Date} The parsed date
1233 Date.parseDate = function(input, format) {
1234 if (Date.parseFunctions[format] == null) {
1235 Date.createParser(format);
1237 var func = Date.parseFunctions[format];
1238 return Date[func](input);
1244 Date.createParser = function(format) {
1245 var funcName = "parse" + Date.parseFunctions.count++;
1246 var regexNum = Date.parseRegexes.length;
1247 var currentGroup = 1;
1248 Date.parseFunctions[format] = funcName;
1250 var code = "Date." + funcName + " = function(input){\n"
1251 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1252 + "var d = new Date();\n"
1253 + "y = d.getFullYear();\n"
1254 + "m = d.getMonth();\n"
1255 + "d = d.getDate();\n"
1256 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1257 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1258 + "if (results && results.length > 0) {";
1261 var special = false;
1263 for (var i = 0; i < format.length; ++i) {
1264 ch = format.charAt(i);
1265 if (!special && ch == "\\") {
1270 regex += String.escape(ch);
1273 var obj = Date.formatCodeToRegex(ch, currentGroup);
1274 currentGroup += obj.g;
1276 if (obj.g && obj.c) {
1282 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1283 + "{v = new Date(y, m, d, h, i, s);}\n"
1284 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1285 + "{v = new Date(y, m, d, h, i);}\n"
1286 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1287 + "{v = new Date(y, m, d, h);}\n"
1288 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1289 + "{v = new Date(y, m, d);}\n"
1290 + "else if (y >= 0 && m >= 0)\n"
1291 + "{v = new Date(y, m);}\n"
1292 + "else if (y >= 0)\n"
1293 + "{v = new Date(y);}\n"
1294 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1295 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1296 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1299 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1300 /** eval:var:zzzzzzzzzzzzz */
1305 Date.formatCodeToRegex = function(character, currentGroup) {
1306 switch (character) {
1310 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1313 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1314 s:"(\\d{1,2})"}; // day of month without leading zeroes
1317 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1318 s:"(\\d{2})"}; // day of month with leading zeroes
1322 s:"(?:" + Date.dayNames.join("|") + ")"};
1326 s:"(?:st|nd|rd|th)"};
1341 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1342 s:"(" + Date.monthNames.join("|") + ")"};
1345 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1346 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1349 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1350 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1353 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1354 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1365 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1369 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1370 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1374 c:"if (results[" + currentGroup + "] == 'am') {\n"
1375 + "if (h == 12) { h = 0; }\n"
1376 + "} else { if (h < 12) { h += 12; }}",
1380 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1381 + "if (h == 12) { h = 0; }\n"
1382 + "} else { if (h < 12) { h += 12; }}",
1387 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1388 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1392 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1393 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1396 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1400 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1405 "o = results[", currentGroup, "];\n",
1406 "var sn = o.substring(0,1);\n", // get + / - sign
1407 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1408 "var mn = o.substring(3,5) % 60;\n", // get minutes
1409 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1410 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1412 s:"([+\-]\\d{2,4})"};
1418 "o = results[", currentGroup, "];\n",
1419 "var sn = o.substring(0,1);\n",
1420 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1421 "var mn = o.substring(4,6) % 60;\n",
1422 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1423 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1429 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1432 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1433 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1434 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1438 s:String.escape(character)};
1443 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1444 * @return {String} The abbreviated timezone name (e.g. 'CST')
1446 Date.prototype.getTimezone = function() {
1447 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1451 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1452 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1454 Date.prototype.getGMTOffset = function() {
1455 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1456 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1457 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1461 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1462 * @return {String} 2-characters representing hours and 2-characters representing minutes
1463 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1465 Date.prototype.getGMTColonOffset = function() {
1466 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1467 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1473 * Get the numeric day number of the year, adjusted for leap year.
1474 * @return {Number} 0 through 364 (365 in leap years)
1476 Date.prototype.getDayOfYear = function() {
1478 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1479 for (var i = 0; i < this.getMonth(); ++i) {
1480 num += Date.daysInMonth[i];
1482 return num + this.getDate() - 1;
1486 * Get the string representation of the numeric week number of the year
1487 * (equivalent to the format specifier 'W').
1488 * @return {String} '00' through '52'
1490 Date.prototype.getWeekOfYear = function() {
1491 // Skip to Thursday of this week
1492 var now = this.getDayOfYear() + (4 - this.getDay());
1493 // Find the first Thursday of the year
1494 var jan1 = new Date(this.getFullYear(), 0, 1);
1495 var then = (7 - jan1.getDay() + 4);
1496 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1500 * Whether or not the current date is in a leap year.
1501 * @return {Boolean} True if the current date is in a leap year, else false
1503 Date.prototype.isLeapYear = function() {
1504 var year = this.getFullYear();
1505 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1509 * Get the first day of the current month, adjusted for leap year. The returned value
1510 * is the numeric day index within the week (0-6) which can be used in conjunction with
1511 * the {@link #monthNames} array to retrieve the textual day name.
1514 var dt = new Date('1/10/2007');
1515 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1517 * @return {Number} The day number (0-6)
1519 Date.prototype.getFirstDayOfMonth = function() {
1520 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1521 return (day < 0) ? (day + 7) : day;
1525 * Get the last day of the current month, adjusted for leap year. The returned value
1526 * is the numeric day index within the week (0-6) which can be used in conjunction with
1527 * the {@link #monthNames} array to retrieve the textual day name.
1530 var dt = new Date('1/10/2007');
1531 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1533 * @return {Number} The day number (0-6)
1535 Date.prototype.getLastDayOfMonth = function() {
1536 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1537 return (day < 0) ? (day + 7) : day;
1542 * Get the first date of this date's month
1545 Date.prototype.getFirstDateOfMonth = function() {
1546 return new Date(this.getFullYear(), this.getMonth(), 1);
1550 * Get the last date of this date's month
1553 Date.prototype.getLastDateOfMonth = function() {
1554 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1557 * Get the number of days in the current month, adjusted for leap year.
1558 * @return {Number} The number of days in the month
1560 Date.prototype.getDaysInMonth = function() {
1561 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1562 return Date.daysInMonth[this.getMonth()];
1566 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1567 * @return {String} 'st, 'nd', 'rd' or 'th'
1569 Date.prototype.getSuffix = function() {
1570 switch (this.getDate()) {
1587 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1590 * An array of textual month names.
1591 * Override these values for international dates, for example...
1592 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1611 * An array of textual day names.
1612 * Override these values for international dates, for example...
1613 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1629 Date.monthNumbers = {
1644 * Creates and returns a new Date instance with the exact same date value as the called instance.
1645 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1646 * variable will also be changed. When the intention is to create a new variable that will not
1647 * modify the original instance, you should create a clone.
1649 * Example of correctly cloning a date:
1652 var orig = new Date('10/1/2006');
1655 document.write(orig); //returns 'Thu Oct 05 2006'!
1658 var orig = new Date('10/1/2006');
1659 var copy = orig.clone();
1661 document.write(orig); //returns 'Thu Oct 01 2006'
1663 * @return {Date} The new Date instance
1665 Date.prototype.clone = function() {
1666 return new Date(this.getTime());
1670 * Clears any time information from this date
1671 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1672 @return {Date} this or the clone
1674 Date.prototype.clearTime = function(clone){
1676 return this.clone().clearTime();
1681 this.setMilliseconds(0);
1686 // safari setMonth is broken
1688 Date.brokenSetMonth = Date.prototype.setMonth;
1689 Date.prototype.setMonth = function(num){
1691 var n = Math.ceil(-num);
1692 var back_year = Math.ceil(n/12);
1693 var month = (n % 12) ? 12 - n % 12 : 0 ;
1694 this.setFullYear(this.getFullYear() - back_year);
1695 return Date.brokenSetMonth.call(this, month);
1697 return Date.brokenSetMonth.apply(this, arguments);
1702 /** Date interval constant
1706 /** Date interval constant
1710 /** Date interval constant
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1726 /** Date interval constant
1732 * Provides a convenient method of performing basic date arithmetic. This method
1733 * does not modify the Date instance being called - it creates and returns
1734 * a new Date instance containing the resulting date value.
1739 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1740 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1742 //Negative values will subtract correctly:
1743 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1744 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1746 //You can even chain several calls together in one line!
1747 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1748 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1751 * @param {String} interval A valid date interval enum value
1752 * @param {Number} value The amount to add to the current date
1753 * @return {Date} The new Date instance
1755 Date.prototype.add = function(interval, value){
1756 var d = this.clone();
1757 if (!interval || value === 0) return d;
1758 switch(interval.toLowerCase()){
1760 d.setMilliseconds(this.getMilliseconds() + value);
1763 d.setSeconds(this.getSeconds() + value);
1766 d.setMinutes(this.getMinutes() + value);
1769 d.setHours(this.getHours() + value);
1772 d.setDate(this.getDate() + value);
1775 var day = this.getDate();
1777 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1780 d.setMonth(this.getMonth() + value);
1783 d.setFullYear(this.getFullYear() + value);
1790 * Ext JS Library 1.1.1
1791 * Copyright(c) 2006-2007, Ext JS, LLC.
1793 * Originally Released Under LGPL - original licence link has changed is not relivant.
1796 * <script type="text/javascript">
1800 * @class Roo.lib.Dom
1803 * Dom utils (from YIU afaik)
1808 * Get the view width
1809 * @param {Boolean} full True will get the full document, otherwise it's the view width
1810 * @return {Number} The width
1813 getViewWidth : function(full) {
1814 return full ? this.getDocumentWidth() : this.getViewportWidth();
1817 * Get the view height
1818 * @param {Boolean} full True will get the full document, otherwise it's the view height
1819 * @return {Number} The height
1821 getViewHeight : function(full) {
1822 return full ? this.getDocumentHeight() : this.getViewportHeight();
1825 getDocumentHeight: function() {
1826 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1827 return Math.max(scrollHeight, this.getViewportHeight());
1830 getDocumentWidth: function() {
1831 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1832 return Math.max(scrollWidth, this.getViewportWidth());
1835 getViewportHeight: function() {
1836 var height = self.innerHeight;
1837 var mode = document.compatMode;
1839 if ((mode || Roo.isIE) && !Roo.isOpera) {
1840 height = (mode == "CSS1Compat") ?
1841 document.documentElement.clientHeight :
1842 document.body.clientHeight;
1848 getViewportWidth: function() {
1849 var width = self.innerWidth;
1850 var mode = document.compatMode;
1852 if (mode || Roo.isIE) {
1853 width = (mode == "CSS1Compat") ?
1854 document.documentElement.clientWidth :
1855 document.body.clientWidth;
1860 isAncestor : function(p, c) {
1867 if (p.contains && !Roo.isSafari) {
1868 return p.contains(c);
1869 } else if (p.compareDocumentPosition) {
1870 return !!(p.compareDocumentPosition(c) & 16);
1872 var parent = c.parentNode;
1877 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1880 parent = parent.parentNode;
1886 getRegion : function(el) {
1887 return Roo.lib.Region.getRegion(el);
1890 getY : function(el) {
1891 return this.getXY(el)[1];
1894 getX : function(el) {
1895 return this.getXY(el)[0];
1898 getXY : function(el) {
1899 var p, pe, b, scroll, bd = document.body;
1900 el = Roo.getDom(el);
1901 var fly = Roo.lib.AnimBase.fly;
1902 if (el.getBoundingClientRect) {
1903 b = el.getBoundingClientRect();
1904 scroll = fly(document).getScroll();
1905 return [b.left + scroll.left, b.top + scroll.top];
1911 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1918 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1925 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1926 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1933 if (p != el && pe.getStyle('overflow') != 'visible') {
1941 if (Roo.isSafari && hasAbsolute) {
1946 if (Roo.isGecko && !hasAbsolute) {
1948 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1949 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1953 while (p && p != bd) {
1954 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1966 setXY : function(el, xy) {
1967 el = Roo.fly(el, '_setXY');
1969 var pts = el.translatePoints(xy);
1970 if (xy[0] !== false) {
1971 el.dom.style.left = pts.left + "px";
1973 if (xy[1] !== false) {
1974 el.dom.style.top = pts.top + "px";
1978 setX : function(el, x) {
1979 this.setXY(el, [x, false]);
1982 setY : function(el, y) {
1983 this.setXY(el, [false, y]);
1987 * Portions of this file are based on pieces of Yahoo User Interface Library
1988 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1989 * YUI licensed under the BSD License:
1990 * http://developer.yahoo.net/yui/license.txt
1991 * <script type="text/javascript">
1995 Roo.lib.Event = function() {
1996 var loadComplete = false;
1998 var unloadListeners = [];
2000 var onAvailStack = [];
2002 var lastError = null;
2015 startInterval: function() {
2016 if (!this._interval) {
2018 var callback = function() {
2019 self._tryPreloadAttach();
2021 this._interval = setInterval(callback, this.POLL_INTERVAL);
2026 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2027 onAvailStack.push({ id: p_id,
2030 override: p_override,
2031 checkReady: false });
2033 retryCount = this.POLL_RETRYS;
2034 this.startInterval();
2038 addListener: function(el, eventName, fn) {
2039 el = Roo.getDom(el);
2044 if ("unload" == eventName) {
2045 unloadListeners[unloadListeners.length] =
2046 [el, eventName, fn];
2050 var wrappedFn = function(e) {
2051 return fn(Roo.lib.Event.getEvent(e));
2054 var li = [el, eventName, fn, wrappedFn];
2056 var index = listeners.length;
2057 listeners[index] = li;
2059 this.doAdd(el, eventName, wrappedFn, false);
2065 removeListener: function(el, eventName, fn) {
2068 el = Roo.getDom(el);
2071 return this.purgeElement(el, false, eventName);
2075 if ("unload" == eventName) {
2077 for (i = 0,len = unloadListeners.length; i < len; i++) {
2078 var li = unloadListeners[i];
2081 li[1] == eventName &&
2083 unloadListeners.splice(i, 1);
2091 var cacheItem = null;
2094 var index = arguments[3];
2096 if ("undefined" == typeof index) {
2097 index = this._getCacheIndex(el, eventName, fn);
2101 cacheItem = listeners[index];
2104 if (!el || !cacheItem) {
2108 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2110 delete listeners[index][this.WFN];
2111 delete listeners[index][this.FN];
2112 listeners.splice(index, 1);
2119 getTarget: function(ev, resolveTextNode) {
2120 ev = ev.browserEvent || ev;
2121 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2122 var t = ev.target || ev.srcElement;
2123 return this.resolveTextNode(t);
2127 resolveTextNode: function(node) {
2128 if (Roo.isSafari && node && 3 == node.nodeType) {
2129 return node.parentNode;
2136 getPageX: function(ev) {
2137 ev = ev.browserEvent || ev;
2138 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2140 if (!x && 0 !== x) {
2141 x = ev.clientX || 0;
2144 x += this.getScroll()[1];
2152 getPageY: function(ev) {
2153 ev = ev.browserEvent || ev;
2154 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2156 if (!y && 0 !== y) {
2157 y = ev.clientY || 0;
2160 y += this.getScroll()[0];
2169 getXY: function(ev) {
2170 ev = ev.browserEvent || ev;
2171 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2172 return [this.getPageX(ev), this.getPageY(ev)];
2176 getRelatedTarget: function(ev) {
2177 ev = ev.browserEvent || ev;
2178 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2179 var t = ev.relatedTarget;
2181 if (ev.type == "mouseout") {
2183 } else if (ev.type == "mouseover") {
2188 return this.resolveTextNode(t);
2192 getTime: function(ev) {
2193 ev = ev.browserEvent || ev;
2194 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2196 var t = new Date().getTime();
2200 this.lastError = ex;
2209 stopEvent: function(ev) {
2210 this.stopPropagation(ev);
2211 this.preventDefault(ev);
2215 stopPropagation: function(ev) {
2216 ev = ev.browserEvent || ev;
2217 if (ev.stopPropagation) {
2218 ev.stopPropagation();
2220 ev.cancelBubble = true;
2225 preventDefault: function(ev) {
2226 ev = ev.browserEvent || ev;
2227 if(ev.preventDefault) {
2228 ev.preventDefault();
2230 ev.returnValue = false;
2235 getEvent: function(e) {
2236 var ev = e || window.event;
2238 var c = this.getEvent.caller;
2240 ev = c.arguments[0];
2241 if (ev && Event == ev.constructor) {
2251 getCharCode: function(ev) {
2252 ev = ev.browserEvent || ev;
2253 return ev.charCode || ev.keyCode || 0;
2257 _getCacheIndex: function(el, eventName, fn) {
2258 for (var i = 0,len = listeners.length; i < len; ++i) {
2259 var li = listeners[i];
2261 li[this.FN] == fn &&
2262 li[this.EL] == el &&
2263 li[this.TYPE] == eventName) {
2275 getEl: function(id) {
2276 return document.getElementById(id);
2280 clearCache: function() {
2284 _load: function(e) {
2285 loadComplete = true;
2286 var EU = Roo.lib.Event;
2290 EU.doRemove(window, "load", EU._load);
2295 _tryPreloadAttach: function() {
2304 var tryAgain = !loadComplete;
2306 tryAgain = (retryCount > 0);
2311 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2312 var item = onAvailStack[i];
2314 var el = this.getEl(item.id);
2317 if (!item.checkReady ||
2320 (document && document.body)) {
2323 if (item.override) {
2324 if (item.override === true) {
2327 scope = item.override;
2330 item.fn.call(scope, item.obj);
2331 onAvailStack[i] = null;
2334 notAvail.push(item);
2339 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2343 this.startInterval();
2345 clearInterval(this._interval);
2346 this._interval = null;
2349 this.locked = false;
2356 purgeElement: function(el, recurse, eventName) {
2357 var elListeners = this.getListeners(el, eventName);
2359 for (var i = 0,len = elListeners.length; i < len; ++i) {
2360 var l = elListeners[i];
2361 this.removeListener(el, l.type, l.fn);
2365 if (recurse && el && el.childNodes) {
2366 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2367 this.purgeElement(el.childNodes[i], recurse, eventName);
2373 getListeners: function(el, eventName) {
2374 var results = [], searchLists;
2376 searchLists = [listeners, unloadListeners];
2377 } else if (eventName == "unload") {
2378 searchLists = [unloadListeners];
2380 searchLists = [listeners];
2383 for (var j = 0; j < searchLists.length; ++j) {
2384 var searchList = searchLists[j];
2385 if (searchList && searchList.length > 0) {
2386 for (var i = 0,len = searchList.length; i < len; ++i) {
2387 var l = searchList[i];
2388 if (l && l[this.EL] === el &&
2389 (!eventName || eventName === l[this.TYPE])) {
2394 adjust: l[this.ADJ_SCOPE],
2402 return (results.length) ? results : null;
2406 _unload: function(e) {
2408 var EU = Roo.lib.Event, i, j, l, len, index;
2410 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2411 l = unloadListeners[i];
2414 if (l[EU.ADJ_SCOPE]) {
2415 if (l[EU.ADJ_SCOPE] === true) {
2418 scope = l[EU.ADJ_SCOPE];
2421 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2422 unloadListeners[i] = null;
2428 unloadListeners = null;
2430 if (listeners && listeners.length > 0) {
2431 j = listeners.length;
2434 l = listeners[index];
2436 EU.removeListener(l[EU.EL], l[EU.TYPE],
2446 EU.doRemove(window, "unload", EU._unload);
2451 getScroll: function() {
2452 var dd = document.documentElement, db = document.body;
2453 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2454 return [dd.scrollTop, dd.scrollLeft];
2456 return [db.scrollTop, db.scrollLeft];
2463 doAdd: function () {
2464 if (window.addEventListener) {
2465 return function(el, eventName, fn, capture) {
2466 el.addEventListener(eventName, fn, (capture));
2468 } else if (window.attachEvent) {
2469 return function(el, eventName, fn, capture) {
2470 el.attachEvent("on" + eventName, fn);
2479 doRemove: function() {
2480 if (window.removeEventListener) {
2481 return function (el, eventName, fn, capture) {
2482 el.removeEventListener(eventName, fn, (capture));
2484 } else if (window.detachEvent) {
2485 return function (el, eventName, fn) {
2486 el.detachEvent("on" + eventName, fn);
2498 var E = Roo.lib.Event;
2499 E.on = E.addListener;
2500 E.un = E.removeListener;
2502 if (document && document.body) {
2505 E.doAdd(window, "load", E._load);
2507 E.doAdd(window, "unload", E._unload);
2508 E._tryPreloadAttach();
2512 * Portions of this file are based on pieces of Yahoo User Interface Library
2513 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2514 * YUI licensed under the BSD License:
2515 * http://developer.yahoo.net/yui/license.txt
2516 * <script type="text/javascript">
2522 * @class Roo.lib.Ajax
2529 request : function(method, uri, cb, data, options) {
2531 var hs = options.headers;
2534 if(hs.hasOwnProperty(h)){
2535 this.initHeader(h, hs[h], false);
2539 if(options.xmlData){
2540 this.initHeader('Content-Type', 'text/xml', false);
2542 data = options.xmlData;
2546 return this.asyncRequest(method, uri, cb, data);
2549 serializeForm : function(form) {
2550 if(typeof form == 'string') {
2551 form = (document.getElementById(form) || document.forms[form]);
2554 var el, name, val, disabled, data = '', hasSubmit = false;
2555 for (var i = 0; i < form.elements.length; i++) {
2556 el = form.elements[i];
2557 disabled = form.elements[i].disabled;
2558 name = form.elements[i].name;
2559 val = form.elements[i].value;
2561 if (!disabled && name){
2565 case 'select-multiple':
2566 for (var j = 0; j < el.options.length; j++) {
2567 if (el.options[j].selected) {
2569 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2572 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2580 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2593 if(hasSubmit == false) {
2594 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2599 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2604 data = data.substr(0, data.length - 1);
2612 useDefaultHeader:true,
2614 defaultPostHeader:'application/x-www-form-urlencoded',
2616 useDefaultXhrHeader:true,
2618 defaultXhrHeader:'XMLHttpRequest',
2620 hasDefaultHeaders:true,
2632 setProgId:function(id)
2634 this.activeX.unshift(id);
2637 setDefaultPostHeader:function(b)
2639 this.useDefaultHeader = b;
2642 setDefaultXhrHeader:function(b)
2644 this.useDefaultXhrHeader = b;
2647 setPollingInterval:function(i)
2649 if (typeof i == 'number' && isFinite(i)) {
2650 this.pollInterval = i;
2654 createXhrObject:function(transactionId)
2660 http = new XMLHttpRequest();
2662 obj = { conn:http, tId:transactionId };
2666 for (var i = 0; i < this.activeX.length; ++i) {
2670 http = new ActiveXObject(this.activeX[i]);
2672 obj = { conn:http, tId:transactionId };
2685 getConnectionObject:function()
2688 var tId = this.transactionId;
2692 o = this.createXhrObject(tId);
2694 this.transactionId++;
2705 asyncRequest:function(method, uri, callback, postData)
2707 var o = this.getConnectionObject();
2713 o.conn.open(method, uri, true);
2715 if (this.useDefaultXhrHeader) {
2716 if (!this.defaultHeaders['X-Requested-With']) {
2717 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2721 if(postData && this.useDefaultHeader){
2722 this.initHeader('Content-Type', this.defaultPostHeader);
2725 if (this.hasDefaultHeaders || this.hasHeaders) {
2729 this.handleReadyState(o, callback);
2730 o.conn.send(postData || null);
2736 handleReadyState:function(o, callback)
2740 if (callback && callback.timeout) {
2742 this.timeout[o.tId] = window.setTimeout(function() {
2743 oConn.abort(o, callback, true);
2744 }, callback.timeout);
2747 this.poll[o.tId] = window.setInterval(
2749 if (o.conn && o.conn.readyState == 4) {
2750 window.clearInterval(oConn.poll[o.tId]);
2751 delete oConn.poll[o.tId];
2753 if(callback && callback.timeout) {
2754 window.clearTimeout(oConn.timeout[o.tId]);
2755 delete oConn.timeout[o.tId];
2758 oConn.handleTransactionResponse(o, callback);
2761 , this.pollInterval);
2764 handleTransactionResponse:function(o, callback, isAbort)
2768 this.releaseObject(o);
2772 var httpStatus, responseObject;
2776 if (o.conn.status !== undefined && o.conn.status != 0) {
2777 httpStatus = o.conn.status;
2789 if (httpStatus >= 200 && httpStatus < 300) {
2790 responseObject = this.createResponseObject(o, callback.argument);
2791 if (callback.success) {
2792 if (!callback.scope) {
2793 callback.success(responseObject);
2798 callback.success.apply(callback.scope, [responseObject]);
2803 switch (httpStatus) {
2811 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2812 if (callback.failure) {
2813 if (!callback.scope) {
2814 callback.failure(responseObject);
2817 callback.failure.apply(callback.scope, [responseObject]);
2822 responseObject = this.createResponseObject(o, callback.argument);
2823 if (callback.failure) {
2824 if (!callback.scope) {
2825 callback.failure(responseObject);
2828 callback.failure.apply(callback.scope, [responseObject]);
2834 this.releaseObject(o);
2835 responseObject = null;
2838 createResponseObject:function(o, callbackArg)
2845 var headerStr = o.conn.getAllResponseHeaders();
2846 var header = headerStr.split('\n');
2847 for (var i = 0; i < header.length; i++) {
2848 var delimitPos = header[i].indexOf(':');
2849 if (delimitPos != -1) {
2850 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2858 obj.status = o.conn.status;
2859 obj.statusText = o.conn.statusText;
2860 obj.getResponseHeader = headerObj;
2861 obj.getAllResponseHeaders = headerStr;
2862 obj.responseText = o.conn.responseText;
2863 obj.responseXML = o.conn.responseXML;
2865 if (typeof callbackArg !== undefined) {
2866 obj.argument = callbackArg;
2872 createExceptionObject:function(tId, callbackArg, isAbort)
2875 var COMM_ERROR = 'communication failure';
2876 var ABORT_CODE = -1;
2877 var ABORT_ERROR = 'transaction aborted';
2883 obj.status = ABORT_CODE;
2884 obj.statusText = ABORT_ERROR;
2887 obj.status = COMM_CODE;
2888 obj.statusText = COMM_ERROR;
2892 obj.argument = callbackArg;
2898 initHeader:function(label, value, isDefault)
2900 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2902 if (headerObj[label] === undefined) {
2903 headerObj[label] = value;
2908 headerObj[label] = value + "," + headerObj[label];
2912 this.hasDefaultHeaders = true;
2915 this.hasHeaders = true;
2920 setHeader:function(o)
2922 if (this.hasDefaultHeaders) {
2923 for (var prop in this.defaultHeaders) {
2924 if (this.defaultHeaders.hasOwnProperty(prop)) {
2925 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2930 if (this.hasHeaders) {
2931 for (var prop in this.headers) {
2932 if (this.headers.hasOwnProperty(prop)) {
2933 o.conn.setRequestHeader(prop, this.headers[prop]);
2937 this.hasHeaders = false;
2941 resetDefaultHeaders:function() {
2942 delete this.defaultHeaders;
2943 this.defaultHeaders = {};
2944 this.hasDefaultHeaders = false;
2947 abort:function(o, callback, isTimeout)
2949 if(this.isCallInProgress(o)) {
2951 window.clearInterval(this.poll[o.tId]);
2952 delete this.poll[o.tId];
2954 delete this.timeout[o.tId];
2957 this.handleTransactionResponse(o, callback, true);
2967 isCallInProgress:function(o)
2970 return o.conn.readyState != 4 && o.conn.readyState != 0;
2979 releaseObject:function(o)
2988 'MSXML2.XMLHTTP.3.0',
2996 * Portions of this file are based on pieces of Yahoo User Interface Library
2997 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2998 * YUI licensed under the BSD License:
2999 * http://developer.yahoo.net/yui/license.txt
3000 * <script type="text/javascript">
3004 Roo.lib.Region = function(t, r, b, l) {
3014 Roo.lib.Region.prototype = {
3015 contains : function(region) {
3016 return ( region.left >= this.left &&
3017 region.right <= this.right &&
3018 region.top >= this.top &&
3019 region.bottom <= this.bottom );
3023 getArea : function() {
3024 return ( (this.bottom - this.top) * (this.right - this.left) );
3027 intersect : function(region) {
3028 var t = Math.max(this.top, region.top);
3029 var r = Math.min(this.right, region.right);
3030 var b = Math.min(this.bottom, region.bottom);
3031 var l = Math.max(this.left, region.left);
3033 if (b >= t && r >= l) {
3034 return new Roo.lib.Region(t, r, b, l);
3039 union : function(region) {
3040 var t = Math.min(this.top, region.top);
3041 var r = Math.max(this.right, region.right);
3042 var b = Math.max(this.bottom, region.bottom);
3043 var l = Math.min(this.left, region.left);
3045 return new Roo.lib.Region(t, r, b, l);
3048 adjust : function(t, l, b, r) {
3057 Roo.lib.Region.getRegion = function(el) {
3058 var p = Roo.lib.Dom.getXY(el);
3061 var r = p[0] + el.offsetWidth;
3062 var b = p[1] + el.offsetHeight;
3065 return new Roo.lib.Region(t, r, b, l);
3068 * Portions of this file are based on pieces of Yahoo User Interface Library
3069 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3070 * YUI licensed under the BSD License:
3071 * http://developer.yahoo.net/yui/license.txt
3072 * <script type="text/javascript">
3075 //@@dep Roo.lib.Region
3078 Roo.lib.Point = function(x, y) {
3079 if (x instanceof Array) {
3083 this.x = this.right = this.left = this[0] = x;
3084 this.y = this.top = this.bottom = this[1] = y;
3087 Roo.lib.Point.prototype = new Roo.lib.Region();
3089 * Portions of this file are based on pieces of Yahoo User Interface Library
3090 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3091 * YUI licensed under the BSD License:
3092 * http://developer.yahoo.net/yui/license.txt
3093 * <script type="text/javascript">
3100 scroll : function(el, args, duration, easing, cb, scope) {
3101 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3104 motion : function(el, args, duration, easing, cb, scope) {
3105 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3108 color : function(el, args, duration, easing, cb, scope) {
3109 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3112 run : function(el, args, duration, easing, cb, scope, type) {
3113 type = type || Roo.lib.AnimBase;
3114 if (typeof easing == "string") {
3115 easing = Roo.lib.Easing[easing];
3117 var anim = new type(el, args, duration, easing);
3118 anim.animateX(function() {
3119 Roo.callback(cb, scope);
3125 * Portions of this file are based on pieces of Yahoo User Interface Library
3126 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3127 * YUI licensed under the BSD License:
3128 * http://developer.yahoo.net/yui/license.txt
3129 * <script type="text/javascript">
3137 if (!libFlyweight) {
3138 libFlyweight = new Roo.Element.Flyweight();
3140 libFlyweight.dom = el;
3141 return libFlyweight;
3144 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3148 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3150 this.init(el, attributes, duration, method);
3154 Roo.lib.AnimBase.fly = fly;
3158 Roo.lib.AnimBase.prototype = {
3160 toString: function() {
3161 var el = this.getEl();
3162 var id = el.id || el.tagName;
3163 return ("Anim " + id);
3167 noNegatives: /width|height|opacity|padding/i,
3168 offsetAttribute: /^((width|height)|(top|left))$/,
3169 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3170 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3174 doMethod: function(attr, start, end) {
3175 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3179 setAttribute: function(attr, val, unit) {
3180 if (this.patterns.noNegatives.test(attr)) {
3181 val = (val > 0) ? val : 0;
3184 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3188 getAttribute: function(attr) {
3189 var el = this.getEl();
3190 var val = fly(el).getStyle(attr);
3192 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3193 return parseFloat(val);
3196 var a = this.patterns.offsetAttribute.exec(attr) || [];
3197 var pos = !!( a[3] );
3198 var box = !!( a[2] );
3201 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3202 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3211 getDefaultUnit: function(attr) {
3212 if (this.patterns.defaultUnit.test(attr)) {
3219 animateX : function(callback, scope) {
3220 var f = function() {
3221 this.onComplete.removeListener(f);
3222 if (typeof callback == "function") {
3223 callback.call(scope || this, this);
3226 this.onComplete.addListener(f, this);
3231 setRuntimeAttribute: function(attr) {
3234 var attributes = this.attributes;
3236 this.runtimeAttributes[attr] = {};
3238 var isset = function(prop) {
3239 return (typeof prop !== 'undefined');
3242 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3246 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3249 if (isset(attributes[attr]['to'])) {
3250 end = attributes[attr]['to'];
3251 } else if (isset(attributes[attr]['by'])) {
3252 if (start.constructor == Array) {
3254 for (var i = 0, len = start.length; i < len; ++i) {
3255 end[i] = start[i] + attributes[attr]['by'][i];
3258 end = start + attributes[attr]['by'];
3262 this.runtimeAttributes[attr].start = start;
3263 this.runtimeAttributes[attr].end = end;
3266 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3270 init: function(el, attributes, duration, method) {
3272 var isAnimated = false;
3275 var startTime = null;
3278 var actualFrames = 0;
3281 el = Roo.getDom(el);
3284 this.attributes = attributes || {};
3287 this.duration = duration || 1;
3290 this.method = method || Roo.lib.Easing.easeNone;
3293 this.useSeconds = true;
3296 this.currentFrame = 0;
3299 this.totalFrames = Roo.lib.AnimMgr.fps;
3302 this.getEl = function() {
3307 this.isAnimated = function() {
3312 this.getStartTime = function() {
3316 this.runtimeAttributes = {};
3319 this.animate = function() {
3320 if (this.isAnimated()) {
3324 this.currentFrame = 0;
3326 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3328 Roo.lib.AnimMgr.registerElement(this);
3332 this.stop = function(finish) {
3334 this.currentFrame = this.totalFrames;
3335 this._onTween.fire();
3337 Roo.lib.AnimMgr.stop(this);
3340 var onStart = function() {
3341 this.onStart.fire();
3343 this.runtimeAttributes = {};
3344 for (var attr in this.attributes) {
3345 this.setRuntimeAttribute(attr);
3350 startTime = new Date();
3354 var onTween = function() {
3356 duration: new Date() - this.getStartTime(),
3357 currentFrame: this.currentFrame
3360 data.toString = function() {
3362 'duration: ' + data.duration +
3363 ', currentFrame: ' + data.currentFrame
3367 this.onTween.fire(data);
3369 var runtimeAttributes = this.runtimeAttributes;
3371 for (var attr in runtimeAttributes) {
3372 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3378 var onComplete = function() {
3379 var actual_duration = (new Date() - startTime) / 1000 ;
3382 duration: actual_duration,
3383 frames: actualFrames,
3384 fps: actualFrames / actual_duration
3387 data.toString = function() {
3389 'duration: ' + data.duration +
3390 ', frames: ' + data.frames +
3391 ', fps: ' + data.fps
3397 this.onComplete.fire(data);
3401 this._onStart = new Roo.util.Event(this);
3402 this.onStart = new Roo.util.Event(this);
3403 this.onTween = new Roo.util.Event(this);
3404 this._onTween = new Roo.util.Event(this);
3405 this.onComplete = new Roo.util.Event(this);
3406 this._onComplete = new Roo.util.Event(this);
3407 this._onStart.addListener(onStart);
3408 this._onTween.addListener(onTween);
3409 this._onComplete.addListener(onComplete);
3414 * Portions of this file are based on pieces of Yahoo User Interface Library
3415 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3416 * YUI licensed under the BSD License:
3417 * http://developer.yahoo.net/yui/license.txt
3418 * <script type="text/javascript">
3422 Roo.lib.AnimMgr = new function() {
3439 this.registerElement = function(tween) {
3440 queue[queue.length] = tween;
3442 tween._onStart.fire();
3447 this.unRegister = function(tween, index) {
3448 tween._onComplete.fire();
3449 index = index || getIndex(tween);
3451 queue.splice(index, 1);
3455 if (tweenCount <= 0) {
3461 this.start = function() {
3462 if (thread === null) {
3463 thread = setInterval(this.run, this.delay);
3468 this.stop = function(tween) {
3470 clearInterval(thread);
3472 for (var i = 0, len = queue.length; i < len; ++i) {
3473 if (queue[0].isAnimated()) {
3474 this.unRegister(queue[0], 0);
3483 this.unRegister(tween);
3488 this.run = function() {
3489 for (var i = 0, len = queue.length; i < len; ++i) {
3490 var tween = queue[i];
3491 if (!tween || !tween.isAnimated()) {
3495 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3497 tween.currentFrame += 1;
3499 if (tween.useSeconds) {
3500 correctFrame(tween);
3502 tween._onTween.fire();
3505 Roo.lib.AnimMgr.stop(tween, i);
3510 var getIndex = function(anim) {
3511 for (var i = 0, len = queue.length; i < len; ++i) {
3512 if (queue[i] == anim) {
3520 var correctFrame = function(tween) {
3521 var frames = tween.totalFrames;
3522 var frame = tween.currentFrame;
3523 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3524 var elapsed = (new Date() - tween.getStartTime());
3527 if (elapsed < tween.duration * 1000) {
3528 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3530 tweak = frames - (frame + 1);
3532 if (tweak > 0 && isFinite(tweak)) {
3533 if (tween.currentFrame + tweak >= frames) {
3534 tweak = frames - (frame + 1);
3537 tween.currentFrame += tweak;
3543 * Portions of this file are based on pieces of Yahoo User Interface Library
3544 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545 * YUI licensed under the BSD License:
3546 * http://developer.yahoo.net/yui/license.txt
3547 * <script type="text/javascript">
3550 Roo.lib.Bezier = new function() {
3552 this.getPosition = function(points, t) {
3553 var n = points.length;
3556 for (var i = 0; i < n; ++i) {
3557 tmp[i] = [points[i][0], points[i][1]];
3560 for (var j = 1; j < n; ++j) {
3561 for (i = 0; i < n - j; ++i) {
3562 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3563 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3567 return [ tmp[0][0], tmp[0][1] ];
3571 * Portions of this file are based on pieces of Yahoo User Interface Library
3572 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3573 * YUI licensed under the BSD License:
3574 * http://developer.yahoo.net/yui/license.txt
3575 * <script type="text/javascript">
3580 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3581 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3584 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3586 var fly = Roo.lib.AnimBase.fly;
3588 var superclass = Y.ColorAnim.superclass;
3589 var proto = Y.ColorAnim.prototype;
3591 proto.toString = function() {
3592 var el = this.getEl();
3593 var id = el.id || el.tagName;
3594 return ("ColorAnim " + id);
3597 proto.patterns.color = /color$/i;
3598 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3599 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3600 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3601 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3604 proto.parseColor = function(s) {
3605 if (s.length == 3) {
3609 var c = this.patterns.hex.exec(s);
3610 if (c && c.length == 4) {
3611 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3614 c = this.patterns.rgb.exec(s);
3615 if (c && c.length == 4) {
3616 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3619 c = this.patterns.hex3.exec(s);
3620 if (c && c.length == 4) {
3621 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3626 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3627 proto.getAttribute = function(attr) {
3628 var el = this.getEl();
3629 if (this.patterns.color.test(attr)) {
3630 var val = fly(el).getStyle(attr);
3632 if (this.patterns.transparent.test(val)) {
3633 var parent = el.parentNode;
3634 val = fly(parent).getStyle(attr);
3636 while (parent && this.patterns.transparent.test(val)) {
3637 parent = parent.parentNode;
3638 val = fly(parent).getStyle(attr);
3639 if (parent.tagName.toUpperCase() == 'HTML') {
3645 val = superclass.getAttribute.call(this, attr);
3650 proto.getAttribute = function(attr) {
3651 var el = this.getEl();
3652 if (this.patterns.color.test(attr)) {
3653 var val = fly(el).getStyle(attr);
3655 if (this.patterns.transparent.test(val)) {
3656 var parent = el.parentNode;
3657 val = fly(parent).getStyle(attr);
3659 while (parent && this.patterns.transparent.test(val)) {
3660 parent = parent.parentNode;
3661 val = fly(parent).getStyle(attr);
3662 if (parent.tagName.toUpperCase() == 'HTML') {
3668 val = superclass.getAttribute.call(this, attr);
3674 proto.doMethod = function(attr, start, end) {
3677 if (this.patterns.color.test(attr)) {
3679 for (var i = 0, len = start.length; i < len; ++i) {
3680 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3683 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3686 val = superclass.doMethod.call(this, attr, start, end);
3692 proto.setRuntimeAttribute = function(attr) {
3693 superclass.setRuntimeAttribute.call(this, attr);
3695 if (this.patterns.color.test(attr)) {
3696 var attributes = this.attributes;
3697 var start = this.parseColor(this.runtimeAttributes[attr].start);
3698 var end = this.parseColor(this.runtimeAttributes[attr].end);
3700 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3701 end = this.parseColor(attributes[attr].by);
3703 for (var i = 0, len = start.length; i < len; ++i) {
3704 end[i] = start[i] + end[i];
3708 this.runtimeAttributes[attr].start = start;
3709 this.runtimeAttributes[attr].end = end;
3715 * Portions of this file are based on pieces of Yahoo User Interface Library
3716 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3717 * YUI licensed under the BSD License:
3718 * http://developer.yahoo.net/yui/license.txt
3719 * <script type="text/javascript">
3725 easeNone: function (t, b, c, d) {
3726 return c * t / d + b;
3730 easeIn: function (t, b, c, d) {
3731 return c * (t /= d) * t + b;
3735 easeOut: function (t, b, c, d) {
3736 return -c * (t /= d) * (t - 2) + b;
3740 easeBoth: function (t, b, c, d) {
3741 if ((t /= d / 2) < 1) {
3742 return c / 2 * t * t + b;
3745 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3749 easeInStrong: function (t, b, c, d) {
3750 return c * (t /= d) * t * t * t + b;
3754 easeOutStrong: function (t, b, c, d) {
3755 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3759 easeBothStrong: function (t, b, c, d) {
3760 if ((t /= d / 2) < 1) {
3761 return c / 2 * t * t * t * t + b;
3764 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3769 elasticIn: function (t, b, c, d, a, p) {
3773 if ((t /= d) == 1) {
3780 if (!a || a < Math.abs(c)) {
3785 var s = p / (2 * Math.PI) * Math.asin(c / a);
3788 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3792 elasticOut: function (t, b, c, d, a, p) {
3796 if ((t /= d) == 1) {
3803 if (!a || a < Math.abs(c)) {
3808 var s = p / (2 * Math.PI) * Math.asin(c / a);
3811 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3815 elasticBoth: function (t, b, c, d, a, p) {
3820 if ((t /= d / 2) == 2) {
3828 if (!a || a < Math.abs(c)) {
3833 var s = p / (2 * Math.PI) * Math.asin(c / a);
3837 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3838 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3840 return a * Math.pow(2, -10 * (t -= 1)) *
3841 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3846 backIn: function (t, b, c, d, s) {
3847 if (typeof s == 'undefined') {
3850 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3854 backOut: function (t, b, c, d, s) {
3855 if (typeof s == 'undefined') {
3858 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3862 backBoth: function (t, b, c, d, s) {
3863 if (typeof s == 'undefined') {
3867 if ((t /= d / 2 ) < 1) {
3868 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3870 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3874 bounceIn: function (t, b, c, d) {
3875 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3879 bounceOut: function (t, b, c, d) {
3880 if ((t /= d) < (1 / 2.75)) {
3881 return c * (7.5625 * t * t) + b;
3882 } else if (t < (2 / 2.75)) {
3883 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3884 } else if (t < (2.5 / 2.75)) {
3885 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3887 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3891 bounceBoth: function (t, b, c, d) {
3893 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3895 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
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.Motion = function(el, attributes, duration, method) {
3908 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3912 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3916 var superclass = Y.Motion.superclass;
3917 var proto = Y.Motion.prototype;
3919 proto.toString = function() {
3920 var el = this.getEl();
3921 var id = el.id || el.tagName;
3922 return ("Motion " + id);
3925 proto.patterns.points = /^points$/i;
3927 proto.setAttribute = function(attr, val, unit) {
3928 if (this.patterns.points.test(attr)) {
3929 unit = unit || 'px';
3930 superclass.setAttribute.call(this, 'left', val[0], unit);
3931 superclass.setAttribute.call(this, 'top', val[1], unit);
3933 superclass.setAttribute.call(this, attr, val, unit);
3937 proto.getAttribute = function(attr) {
3938 if (this.patterns.points.test(attr)) {
3940 superclass.getAttribute.call(this, 'left'),
3941 superclass.getAttribute.call(this, 'top')
3944 val = superclass.getAttribute.call(this, attr);
3950 proto.doMethod = function(attr, start, end) {
3953 if (this.patterns.points.test(attr)) {
3954 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3955 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3957 val = superclass.doMethod.call(this, attr, start, end);
3962 proto.setRuntimeAttribute = function(attr) {
3963 if (this.patterns.points.test(attr)) {
3964 var el = this.getEl();
3965 var attributes = this.attributes;
3967 var control = attributes['points']['control'] || [];
3971 if (control.length > 0 && !(control[0] instanceof Array)) {
3972 control = [control];
3975 for (i = 0,len = control.length; i < len; ++i) {
3976 tmp[i] = control[i];
3981 Roo.fly(el).position();
3983 if (isset(attributes['points']['from'])) {
3984 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3987 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3990 start = this.getAttribute('points');
3993 if (isset(attributes['points']['to'])) {
3994 end = translateValues.call(this, attributes['points']['to'], start);
3996 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3997 for (i = 0,len = control.length; i < len; ++i) {
3998 control[i] = translateValues.call(this, control[i], start);
4002 } else if (isset(attributes['points']['by'])) {
4003 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4005 for (i = 0,len = control.length; i < len; ++i) {
4006 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4010 this.runtimeAttributes[attr] = [start];
4012 if (control.length > 0) {
4013 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4016 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4019 superclass.setRuntimeAttribute.call(this, attr);
4023 var translateValues = function(val, start) {
4024 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4025 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4030 var isset = function(prop) {
4031 return (typeof prop !== 'undefined');
4035 * Portions of this file are based on pieces of Yahoo User Interface Library
4036 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4037 * YUI licensed under the BSD License:
4038 * http://developer.yahoo.net/yui/license.txt
4039 * <script type="text/javascript">
4043 Roo.lib.Scroll = function(el, attributes, duration, method) {
4045 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4049 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4053 var superclass = Y.Scroll.superclass;
4054 var proto = Y.Scroll.prototype;
4056 proto.toString = function() {
4057 var el = this.getEl();
4058 var id = el.id || el.tagName;
4059 return ("Scroll " + id);
4062 proto.doMethod = function(attr, start, end) {
4065 if (attr == 'scroll') {
4067 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4068 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4072 val = superclass.doMethod.call(this, attr, start, end);
4077 proto.getAttribute = function(attr) {
4079 var el = this.getEl();
4081 if (attr == 'scroll') {
4082 val = [ el.scrollLeft, el.scrollTop ];
4084 val = superclass.getAttribute.call(this, attr);
4090 proto.setAttribute = function(attr, val, unit) {
4091 var el = this.getEl();
4093 if (attr == 'scroll') {
4094 el.scrollLeft = val[0];
4095 el.scrollTop = val[1];
4097 superclass.setAttribute.call(this, attr, val, unit);
4103 * Ext JS Library 1.1.1
4104 * Copyright(c) 2006-2007, Ext JS, LLC.
4106 * Originally Released Under LGPL - original licence link has changed is not relivant.
4109 * <script type="text/javascript">
4113 // nasty IE9 hack - what a pile of crap that is..
4115 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4116 Range.prototype.createContextualFragment = function (html) {
4117 var doc = window.document;
4118 var container = doc.createElement("div");
4119 container.innerHTML = html;
4120 var frag = doc.createDocumentFragment(), n;
4121 while ((n = container.firstChild)) {
4122 frag.appendChild(n);
4129 * @class Roo.DomHelper
4130 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4131 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4134 Roo.DomHelper = function(){
4135 var tempTableEl = null;
4136 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4137 var tableRe = /^table|tbody|tr|td$/i;
4139 // build as innerHTML where available
4141 var createHtml = function(o){
4142 if(typeof o == 'string'){
4151 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4152 if(attr == "style"){
4154 if(typeof s == "function"){
4157 if(typeof s == "string"){
4158 b += ' style="' + s + '"';
4159 }else if(typeof s == "object"){
4162 if(typeof s[key] != "function"){
4163 b += key + ":" + s[key] + ";";
4170 b += ' class="' + o["cls"] + '"';
4171 }else if(attr == "htmlFor"){
4172 b += ' for="' + o["htmlFor"] + '"';
4174 b += " " + attr + '="' + o[attr] + '"';
4178 if(emptyTags.test(o.tag)){
4182 var cn = o.children || o.cn;
4184 //http://bugs.kde.org/show_bug.cgi?id=71506
4185 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4186 for(var i = 0, len = cn.length; i < len; i++) {
4187 b += createHtml(cn[i], b);
4190 b += createHtml(cn, b);
4196 b += "</" + o.tag + ">";
4203 var createDom = function(o, parentNode){
4205 // defininition craeted..
4207 if (o.ns && o.ns != 'html') {
4209 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4210 xmlns[o.ns] = o.xmlns;
4213 if (typeof(xmlns[o.ns]) == 'undefined') {
4214 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4220 if (typeof(o) == 'string') {
4221 return parentNode.appendChild(document.createTextNode(o));
4223 o.tag = o.tag || div;
4224 if (o.ns && Roo.isIE) {
4226 o.tag = o.ns + ':' + o.tag;
4229 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4230 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4233 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4234 attr == "style" || typeof o[attr] == "function") continue;
4236 if(attr=="cls" && Roo.isIE){
4237 el.className = o["cls"];
4239 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4240 else el[attr] = o[attr];
4243 Roo.DomHelper.applyStyles(el, o.style);
4244 var cn = o.children || o.cn;
4246 //http://bugs.kde.org/show_bug.cgi?id=71506
4247 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4248 for(var i = 0, len = cn.length; i < len; i++) {
4249 createDom(cn[i], el);
4256 el.innerHTML = o.html;
4259 parentNode.appendChild(el);
4264 var ieTable = function(depth, s, h, e){
4265 tempTableEl.innerHTML = [s, h, e].join('');
4266 var i = -1, el = tempTableEl;
4273 // kill repeat to save bytes
4277 tbe = '</tbody>'+te,
4283 * Nasty code for IE's broken table implementation
4285 var insertIntoTable = function(tag, where, el, html){
4287 tempTableEl = document.createElement('div');
4292 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4295 if(where == 'beforebegin'){
4299 before = el.nextSibling;
4302 node = ieTable(4, trs, html, tre);
4304 else if(tag == 'tr'){
4305 if(where == 'beforebegin'){
4308 node = ieTable(3, tbs, html, tbe);
4309 } else if(where == 'afterend'){
4310 before = el.nextSibling;
4312 node = ieTable(3, tbs, html, tbe);
4313 } else{ // INTO a TR
4314 if(where == 'afterbegin'){
4315 before = el.firstChild;
4317 node = ieTable(4, trs, html, tre);
4319 } else if(tag == 'tbody'){
4320 if(where == 'beforebegin'){
4323 node = ieTable(2, ts, html, te);
4324 } else if(where == 'afterend'){
4325 before = el.nextSibling;
4327 node = ieTable(2, ts, html, te);
4329 if(where == 'afterbegin'){
4330 before = el.firstChild;
4332 node = ieTable(3, tbs, html, tbe);
4335 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4338 if(where == 'afterbegin'){
4339 before = el.firstChild;
4341 node = ieTable(2, ts, html, te);
4343 el.insertBefore(node, before);
4348 /** True to force the use of DOM instead of html fragments @type Boolean */
4352 * Returns the markup for the passed Element(s) config
4353 * @param {Object} o The Dom object spec (and children)
4356 markup : function(o){
4357 return createHtml(o);
4361 * Applies a style specification to an element
4362 * @param {String/HTMLElement} el The element to apply styles to
4363 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4364 * a function which returns such a specification.
4366 applyStyles : function(el, styles){
4369 if(typeof styles == "string"){
4370 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4372 while ((matches = re.exec(styles)) != null){
4373 el.setStyle(matches[1], matches[2]);
4375 }else if (typeof styles == "object"){
4376 for (var style in styles){
4377 el.setStyle(style, styles[style]);
4379 }else if (typeof styles == "function"){
4380 Roo.DomHelper.applyStyles(el, styles.call());
4386 * Inserts an HTML fragment into the Dom
4387 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4388 * @param {HTMLElement} el The context element
4389 * @param {String} html The HTML fragmenet
4390 * @return {HTMLElement} The new node
4392 insertHtml : function(where, el, html){
4393 where = where.toLowerCase();
4394 if(el.insertAdjacentHTML){
4395 if(tableRe.test(el.tagName)){
4397 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4403 el.insertAdjacentHTML('BeforeBegin', html);
4404 return el.previousSibling;
4406 el.insertAdjacentHTML('AfterBegin', html);
4407 return el.firstChild;
4409 el.insertAdjacentHTML('BeforeEnd', html);
4410 return el.lastChild;
4412 el.insertAdjacentHTML('AfterEnd', html);
4413 return el.nextSibling;
4415 throw 'Illegal insertion point -> "' + where + '"';
4417 var range = el.ownerDocument.createRange();
4421 range.setStartBefore(el);
4422 frag = range.createContextualFragment(html);
4423 el.parentNode.insertBefore(frag, el);
4424 return el.previousSibling;
4427 range.setStartBefore(el.firstChild);
4428 frag = range.createContextualFragment(html);
4429 el.insertBefore(frag, el.firstChild);
4430 return el.firstChild;
4432 el.innerHTML = html;
4433 return el.firstChild;
4437 range.setStartAfter(el.lastChild);
4438 frag = range.createContextualFragment(html);
4439 el.appendChild(frag);
4440 return el.lastChild;
4442 el.innerHTML = html;
4443 return el.lastChild;
4446 range.setStartAfter(el);
4447 frag = range.createContextualFragment(html);
4448 el.parentNode.insertBefore(frag, el.nextSibling);
4449 return el.nextSibling;
4451 throw 'Illegal insertion point -> "' + where + '"';
4455 * Creates new Dom element(s) and inserts them before el
4456 * @param {String/HTMLElement/Element} el The context element
4457 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4458 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4459 * @return {HTMLElement/Roo.Element} The new node
4461 insertBefore : function(el, o, returnElement){
4462 return this.doInsert(el, o, returnElement, "beforeBegin");
4466 * Creates new Dom element(s) and inserts them after el
4467 * @param {String/HTMLElement/Element} el The context element
4468 * @param {Object} o The Dom object spec (and children)
4469 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4470 * @return {HTMLElement/Roo.Element} The new node
4472 insertAfter : function(el, o, returnElement){
4473 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4477 * Creates new Dom element(s) and inserts them as the first child of el
4478 * @param {String/HTMLElement/Element} el The context element
4479 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4480 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4481 * @return {HTMLElement/Roo.Element} The new node
4483 insertFirst : function(el, o, returnElement){
4484 return this.doInsert(el, o, returnElement, "afterBegin");
4488 doInsert : function(el, o, returnElement, pos, sibling){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml(pos, el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and appends them to el
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 append : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4511 if(this.useDom || o.ns){
4512 newNode = createDom(o, null);
4513 el.appendChild(newNode);
4515 var html = createHtml(o);
4516 newNode = this.insertHtml("beforeEnd", el, html);
4518 return returnElement ? Roo.get(newNode, true) : newNode;
4522 * Creates new Dom element(s) and overwrites the contents of el with them
4523 * @param {String/HTMLElement/Element} el The context element
4524 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4525 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4526 * @return {HTMLElement/Roo.Element} The new node
4528 overwrite : function(el, o, returnElement){
4529 el = Roo.getDom(el);
4532 while (el.childNodes.length) {
4533 el.removeChild(el.firstChild);
4537 el.innerHTML = createHtml(o);
4540 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4544 * Creates a new Roo.DomHelper.Template from the Dom object spec
4545 * @param {Object} o The Dom object spec (and children)
4546 * @return {Roo.DomHelper.Template} The new template
4548 createTemplate : function(o){
4549 var html = createHtml(o);
4550 return new Roo.Template(html);
4556 * Ext JS Library 1.1.1
4557 * Copyright(c) 2006-2007, Ext JS, LLC.
4559 * Originally Released Under LGPL - original licence link has changed is not relivant.
4562 * <script type="text/javascript">
4566 * @class Roo.Template
4567 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4568 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4571 var t = new Roo.Template({
4572 html : '<div name="{id}">' +
4573 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4575 myformat: function (value, allValues) {
4576 return 'XX' + value;
4579 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4581 * For more information see this blog post with examples:
4582 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4583 - Create Elements using DOM, HTML fragments and Templates</a>.
4585 * @param {Object} cfg - Configuration object.
4587 Roo.Template = function(cfg){
4589 if(cfg instanceof Array){
4591 }else if(arguments.length > 1){
4592 cfg = Array.prototype.join.call(arguments, "");
4596 if (typeof(cfg) == 'object') {
4607 Roo.Template.prototype = {
4610 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4611 * it should be fixed so that template is observable...
4615 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4619 * Returns an HTML fragment of this template with the specified values applied.
4620 * @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'})
4621 * @return {String} The HTML fragment
4623 applyTemplate : function(values){
4627 return this.compiled(values);
4629 var useF = this.disableFormats !== true;
4630 var fm = Roo.util.Format, tpl = this;
4631 var fn = function(m, name, format, args){
4633 if(format.substr(0, 5) == "this."){
4634 return tpl.call(format.substr(5), values[name], values);
4637 // quoted values are required for strings in compiled templates,
4638 // but for non compiled we need to strip them
4639 // quoted reversed for jsmin
4640 var re = /^\s*['"](.*)["']\s*$/;
4641 args = args.split(',');
4642 for(var i = 0, len = args.length; i < len; i++){
4643 args[i] = args[i].replace(re, "$1");
4645 args = [values[name]].concat(args);
4647 args = [values[name]];
4649 return fm[format].apply(fm, args);
4652 return values[name] !== undefined ? values[name] : "";
4655 return this.html.replace(this.re, fn);
4673 this.loading = true;
4674 this.compiled = false;
4676 var cx = new Roo.data.Connection();
4680 success : function (response) {
4682 _t.html = response.responseText;
4686 failure : function(response) {
4687 Roo.log("Template failed to load from " + _t.url);
4694 * Sets the HTML used as the template and optionally compiles it.
4695 * @param {String} html
4696 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4697 * @return {Roo.Template} this
4699 set : function(html, compile){
4701 this.compiled = null;
4709 * True to disable format functions (defaults to false)
4712 disableFormats : false,
4715 * The regular expression used to match template variables
4719 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4722 * Compiles the template into an internal function, eliminating the RegEx overhead.
4723 * @return {Roo.Template} this
4725 compile : function(){
4726 var fm = Roo.util.Format;
4727 var useF = this.disableFormats !== true;
4728 var sep = Roo.isGecko ? "+" : ",";
4729 var fn = function(m, name, format, args){
4731 args = args ? ',' + args : "";
4732 if(format.substr(0, 5) != "this."){
4733 format = "fm." + format + '(';
4735 format = 'this.call("'+ format.substr(5) + '", ';
4739 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4741 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4744 // branched to use + in gecko and [].join() in others
4746 body = "this.compiled = function(values){ return '" +
4747 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4750 body = ["this.compiled = function(values){ return ['"];
4751 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4752 body.push("'].join('');};");
4753 body = body.join('');
4763 // private function used to call members
4764 call : function(fnName, value, allValues){
4765 return this[fnName](value, allValues);
4769 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4770 * @param {String/HTMLElement/Roo.Element} el The context element
4771 * @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'})
4772 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4773 * @return {HTMLElement/Roo.Element} The new node or Element
4775 insertFirst: function(el, values, returnElement){
4776 return this.doInsert('afterBegin', el, values, returnElement);
4780 * Applies the supplied values to the template and inserts the new node(s) before el.
4781 * @param {String/HTMLElement/Roo.Element} el The context element
4782 * @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'})
4783 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4784 * @return {HTMLElement/Roo.Element} The new node or Element
4786 insertBefore: function(el, values, returnElement){
4787 return this.doInsert('beforeBegin', el, values, returnElement);
4791 * Applies the supplied values to the template and inserts the new node(s) after el.
4792 * @param {String/HTMLElement/Roo.Element} el The context element
4793 * @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'})
4794 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4795 * @return {HTMLElement/Roo.Element} The new node or Element
4797 insertAfter : function(el, values, returnElement){
4798 return this.doInsert('afterEnd', el, values, returnElement);
4802 * Applies the supplied values to the template and appends the new node(s) to el.
4803 * @param {String/HTMLElement/Roo.Element} el The context element
4804 * @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'})
4805 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4806 * @return {HTMLElement/Roo.Element} The new node or Element
4808 append : function(el, values, returnElement){
4809 return this.doInsert('beforeEnd', el, values, returnElement);
4812 doInsert : function(where, el, values, returnEl){
4813 el = Roo.getDom(el);
4814 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4815 return returnEl ? Roo.get(newNode, true) : newNode;
4819 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4820 * @param {String/HTMLElement/Roo.Element} el The context element
4821 * @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'})
4822 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823 * @return {HTMLElement/Roo.Element} The new node or Element
4825 overwrite : function(el, values, returnElement){
4826 el = Roo.getDom(el);
4827 el.innerHTML = this.applyTemplate(values);
4828 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4832 * Alias for {@link #applyTemplate}
4835 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4838 Roo.DomHelper.Template = Roo.Template;
4841 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4842 * @param {String/HTMLElement} el A DOM element or its id
4843 * @returns {Roo.Template} The created template
4846 Roo.Template.from = function(el){
4847 el = Roo.getDom(el);
4848 return new Roo.Template(el.value || el.innerHTML);
4851 * Ext JS Library 1.1.1
4852 * Copyright(c) 2006-2007, Ext JS, LLC.
4854 * Originally Released Under LGPL - original licence link has changed is not relivant.
4857 * <script type="text/javascript">
4862 * This is code is also distributed under MIT license for use
4863 * with jQuery and prototype JavaScript libraries.
4866 * @class Roo.DomQuery
4867 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).
4869 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>
4872 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.
4874 <h4>Element Selectors:</h4>
4876 <li> <b>*</b> any element</li>
4877 <li> <b>E</b> an element with the tag E</li>
4878 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4879 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4880 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4881 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4883 <h4>Attribute Selectors:</h4>
4884 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4886 <li> <b>E[foo]</b> has an attribute "foo"</li>
4887 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4888 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4889 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4890 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4891 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4892 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4894 <h4>Pseudo Classes:</h4>
4896 <li> <b>E:first-child</b> E is the first child of its parent</li>
4897 <li> <b>E:last-child</b> E is the last child of its parent</li>
4898 <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>
4899 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4900 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4901 <li> <b>E:only-child</b> E is the only child of its parent</li>
4902 <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>
4903 <li> <b>E:first</b> the first E in the resultset</li>
4904 <li> <b>E:last</b> the last E in the resultset</li>
4905 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4906 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4907 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4908 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4909 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4910 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4911 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4912 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4913 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4915 <h4>CSS Value Selectors:</h4>
4917 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4918 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4919 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4920 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4921 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4922 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4926 Roo.DomQuery = function(){
4927 var cache = {}, simpleCache = {}, valueCache = {};
4928 var nonSpace = /\S/;
4929 var trimRe = /^\s+|\s+$/g;
4930 var tplRe = /\{(\d+)\}/g;
4931 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4932 var tagTokenRe = /^(#)?([\w-\*]+)/;
4933 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4935 function child(p, index){
4937 var n = p.firstChild;
4939 if(n.nodeType == 1){
4950 while((n = n.nextSibling) && n.nodeType != 1);
4955 while((n = n.previousSibling) && n.nodeType != 1);
4959 function children(d){
4960 var n = d.firstChild, ni = -1;
4962 var nx = n.nextSibling;
4963 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4973 function byClassName(c, a, v){
4977 var r = [], ri = -1, cn;
4978 for(var i = 0, ci; ci = c[i]; i++){
4979 if((' '+ci.className+' ').indexOf(v) != -1){
4986 function attrValue(n, attr){
4987 if(!n.tagName && typeof n.length != "undefined"){
4996 if(attr == "class" || attr == "className"){
4999 return n.getAttribute(attr) || n[attr];
5003 function getNodes(ns, mode, tagName){
5004 var result = [], ri = -1, cs;
5008 tagName = tagName || "*";
5009 if(typeof ns.getElementsByTagName != "undefined"){
5013 for(var i = 0, ni; ni = ns[i]; i++){
5014 cs = ni.getElementsByTagName(tagName);
5015 for(var j = 0, ci; ci = cs[j]; j++){
5019 }else if(mode == "/" || mode == ">"){
5020 var utag = tagName.toUpperCase();
5021 for(var i = 0, ni, cn; ni = ns[i]; i++){
5022 cn = ni.children || ni.childNodes;
5023 for(var j = 0, cj; cj = cn[j]; j++){
5024 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5029 }else if(mode == "+"){
5030 var utag = tagName.toUpperCase();
5031 for(var i = 0, n; n = ns[i]; i++){
5032 while((n = n.nextSibling) && n.nodeType != 1);
5033 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5037 }else if(mode == "~"){
5038 for(var i = 0, n; n = ns[i]; i++){
5039 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5048 function concat(a, b){
5052 for(var i = 0, l = b.length; i < l; i++){
5058 function byTag(cs, tagName){
5059 if(cs.tagName || cs == document){
5065 var r = [], ri = -1;
5066 tagName = tagName.toLowerCase();
5067 for(var i = 0, ci; ci = cs[i]; i++){
5068 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5075 function byId(cs, attr, id){
5076 if(cs.tagName || cs == document){
5082 var r = [], ri = -1;
5083 for(var i = 0,ci; ci = cs[i]; i++){
5084 if(ci && ci.id == id){
5092 function byAttribute(cs, attr, value, op, custom){
5093 var r = [], ri = -1, st = custom=="{";
5094 var f = Roo.DomQuery.operators[op];
5095 for(var i = 0, ci; ci = cs[i]; i++){
5098 a = Roo.DomQuery.getStyle(ci, attr);
5100 else if(attr == "class" || attr == "className"){
5102 }else if(attr == "for"){
5104 }else if(attr == "href"){
5105 a = ci.getAttribute("href", 2);
5107 a = ci.getAttribute(attr);
5109 if((f && f(a, value)) || (!f && a)){
5116 function byPseudo(cs, name, value){
5117 return Roo.DomQuery.pseudos[name](cs, value);
5120 // This is for IE MSXML which does not support expandos.
5121 // IE runs the same speed using setAttribute, however FF slows way down
5122 // and Safari completely fails so they need to continue to use expandos.
5123 var isIE = window.ActiveXObject ? true : false;
5125 // this eval is stop the compressor from
5126 // renaming the variable to something shorter
5128 /** eval:var:batch */
5133 function nodupIEXml(cs){
5135 cs[0].setAttribute("_nodup", d);
5137 for(var i = 1, len = cs.length; i < len; i++){
5139 if(!c.getAttribute("_nodup") != d){
5140 c.setAttribute("_nodup", d);
5144 for(var i = 0, len = cs.length; i < len; i++){
5145 cs[i].removeAttribute("_nodup");
5154 var len = cs.length, c, i, r = cs, cj, ri = -1;
5155 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5158 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5159 return nodupIEXml(cs);
5163 for(i = 1; c = cs[i]; i++){
5168 for(var j = 0; j < i; j++){
5171 for(j = i+1; cj = cs[j]; j++){
5183 function quickDiffIEXml(c1, c2){
5185 for(var i = 0, len = c1.length; i < len; i++){
5186 c1[i].setAttribute("_qdiff", d);
5189 for(var i = 0, len = c2.length; i < len; i++){
5190 if(c2[i].getAttribute("_qdiff") != d){
5191 r[r.length] = c2[i];
5194 for(var i = 0, len = c1.length; i < len; i++){
5195 c1[i].removeAttribute("_qdiff");
5200 function quickDiff(c1, c2){
5201 var len1 = c1.length;
5205 if(isIE && c1[0].selectSingleNode){
5206 return quickDiffIEXml(c1, c2);
5209 for(var i = 0; i < len1; i++){
5213 for(var i = 0, len = c2.length; i < len; i++){
5214 if(c2[i]._qdiff != d){
5215 r[r.length] = c2[i];
5221 function quickId(ns, mode, root, id){
5223 var d = root.ownerDocument || root;
5224 return d.getElementById(id);
5226 ns = getNodes(ns, mode, "*");
5227 return byId(ns, null, id);
5231 getStyle : function(el, name){
5232 return Roo.fly(el).getStyle(name);
5235 * Compiles a selector/xpath query into a reusable function. The returned function
5236 * takes one parameter "root" (optional), which is the context node from where the query should start.
5237 * @param {String} selector The selector/xpath query
5238 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5239 * @return {Function}
5241 compile : function(path, type){
5242 type = type || "select";
5244 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5245 var q = path, mode, lq;
5246 var tk = Roo.DomQuery.matchers;
5247 var tklen = tk.length;
5250 // accept leading mode switch
5251 var lmode = q.match(modeRe);
5252 if(lmode && lmode[1]){
5253 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5254 q = q.replace(lmode[1], "");
5256 // strip leading slashes
5257 while(path.substr(0, 1)=="/"){
5258 path = path.substr(1);
5261 while(q && lq != q){
5263 var tm = q.match(tagTokenRe);
5264 if(type == "select"){
5267 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5269 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5271 q = q.replace(tm[0], "");
5272 }else if(q.substr(0, 1) != '@'){
5273 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5278 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5280 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5282 q = q.replace(tm[0], "");
5285 while(!(mm = q.match(modeRe))){
5286 var matched = false;
5287 for(var j = 0; j < tklen; j++){
5289 var m = q.match(t.re);
5291 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5294 q = q.replace(m[0], "");
5299 // prevent infinite loop on bad selector
5301 throw 'Error parsing selector, parsing failed at "' + q + '"';
5305 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5306 q = q.replace(mm[1], "");
5309 fn[fn.length] = "return nodup(n);\n}";
5312 * list of variables that need from compression as they are used by eval.
5322 * eval:var:byClassName
5324 * eval:var:byAttribute
5325 * eval:var:attrValue
5333 * Selects a group of elements.
5334 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5335 * @param {Node} root (optional) The start of the query (defaults to document).
5338 select : function(path, root, type){
5339 if(!root || root == document){
5342 if(typeof root == "string"){
5343 root = document.getElementById(root);
5345 var paths = path.split(",");
5347 for(var i = 0, len = paths.length; i < len; i++){
5348 var p = paths[i].replace(trimRe, "");
5350 cache[p] = Roo.DomQuery.compile(p);
5352 throw p + " is not a valid selector";
5355 var result = cache[p](root);
5356 if(result && result != document){
5357 results = results.concat(result);
5360 if(paths.length > 1){
5361 return nodup(results);
5367 * Selects a single element.
5368 * @param {String} selector The selector/xpath query
5369 * @param {Node} root (optional) The start of the query (defaults to document).
5372 selectNode : function(path, root){
5373 return Roo.DomQuery.select(path, root)[0];
5377 * Selects the value of a node, optionally replacing null with the defaultValue.
5378 * @param {String} selector The selector/xpath query
5379 * @param {Node} root (optional) The start of the query (defaults to document).
5380 * @param {String} defaultValue
5382 selectValue : function(path, root, defaultValue){
5383 path = path.replace(trimRe, "");
5384 if(!valueCache[path]){
5385 valueCache[path] = Roo.DomQuery.compile(path, "select");
5387 var n = valueCache[path](root);
5388 n = n[0] ? n[0] : n;
5389 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5390 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5394 * Selects the value of a node, parsing integers and floats.
5395 * @param {String} selector The selector/xpath query
5396 * @param {Node} root (optional) The start of the query (defaults to document).
5397 * @param {Number} defaultValue
5400 selectNumber : function(path, root, defaultValue){
5401 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5402 return parseFloat(v);
5406 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5407 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5408 * @param {String} selector The simple selector to test
5411 is : function(el, ss){
5412 if(typeof el == "string"){
5413 el = document.getElementById(el);
5415 var isArray = (el instanceof Array);
5416 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5417 return isArray ? (result.length == el.length) : (result.length > 0);
5421 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5422 * @param {Array} el An array of elements to filter
5423 * @param {String} selector The simple selector to test
5424 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5425 * the selector instead of the ones that match
5428 filter : function(els, ss, nonMatches){
5429 ss = ss.replace(trimRe, "");
5430 if(!simpleCache[ss]){
5431 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5433 var result = simpleCache[ss](els);
5434 return nonMatches ? quickDiff(result, els) : result;
5438 * Collection of matching regular expressions and code snippets.
5442 select: 'n = byClassName(n, null, " {1} ");'
5444 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5445 select: 'n = byPseudo(n, "{1}", "{2}");'
5447 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5448 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5451 select: 'n = byId(n, null, "{1}");'
5454 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5459 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5460 * 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, > <.
5463 "=" : function(a, v){
5466 "!=" : function(a, v){
5469 "^=" : function(a, v){
5470 return a && a.substr(0, v.length) == v;
5472 "$=" : function(a, v){
5473 return a && a.substr(a.length-v.length) == v;
5475 "*=" : function(a, v){
5476 return a && a.indexOf(v) !== -1;
5478 "%=" : function(a, v){
5479 return (a % v) == 0;
5481 "|=" : function(a, v){
5482 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5484 "~=" : function(a, v){
5485 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5490 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5491 * and the argument (if any) supplied in the selector.
5494 "first-child" : function(c){
5495 var r = [], ri = -1, n;
5496 for(var i = 0, ci; ci = n = c[i]; i++){
5497 while((n = n.previousSibling) && n.nodeType != 1);
5505 "last-child" : function(c){
5506 var r = [], ri = -1, n;
5507 for(var i = 0, ci; ci = n = c[i]; i++){
5508 while((n = n.nextSibling) && n.nodeType != 1);
5516 "nth-child" : function(c, a) {
5517 var r = [], ri = -1;
5518 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5519 var f = (m[1] || 1) - 0, l = m[2] - 0;
5520 for(var i = 0, n; n = c[i]; i++){
5521 var pn = n.parentNode;
5522 if (batch != pn._batch) {
5524 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5525 if(cn.nodeType == 1){
5532 if (l == 0 || n.nodeIndex == l){
5535 } else if ((n.nodeIndex + l) % f == 0){
5543 "only-child" : function(c){
5544 var r = [], ri = -1;;
5545 for(var i = 0, ci; ci = c[i]; i++){
5546 if(!prev(ci) && !next(ci)){
5553 "empty" : function(c){
5554 var r = [], ri = -1;
5555 for(var i = 0, ci; ci = c[i]; i++){
5556 var cns = ci.childNodes, j = 0, cn, empty = true;
5559 if(cn.nodeType == 1 || cn.nodeType == 3){
5571 "contains" : function(c, v){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5581 "nodeValue" : function(c, v){
5582 var r = [], ri = -1;
5583 for(var i = 0, ci; ci = c[i]; i++){
5584 if(ci.firstChild && ci.firstChild.nodeValue == v){
5591 "checked" : function(c){
5592 var r = [], ri = -1;
5593 for(var i = 0, ci; ci = c[i]; i++){
5594 if(ci.checked == true){
5601 "not" : function(c, ss){
5602 return Roo.DomQuery.filter(c, ss, true);
5605 "odd" : function(c){
5606 return this["nth-child"](c, "odd");
5609 "even" : function(c){
5610 return this["nth-child"](c, "even");
5613 "nth" : function(c, a){
5614 return c[a-1] || [];
5617 "first" : function(c){
5621 "last" : function(c){
5622 return c[c.length-1] || [];
5625 "has" : function(c, ss){
5626 var s = Roo.DomQuery.select;
5627 var r = [], ri = -1;
5628 for(var i = 0, ci; ci = c[i]; i++){
5629 if(s(ss, ci).length > 0){
5636 "next" : function(c, ss){
5637 var is = Roo.DomQuery.is;
5638 var r = [], ri = -1;
5639 for(var i = 0, ci; ci = c[i]; i++){
5648 "prev" : function(c, ss){
5649 var is = Roo.DomQuery.is;
5650 var r = [], ri = -1;
5651 for(var i = 0, ci; ci = c[i]; i++){
5664 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5665 * @param {String} path The selector/xpath query
5666 * @param {Node} root (optional) The start of the query (defaults to document).
5671 Roo.query = Roo.DomQuery.select;
5674 * Ext JS Library 1.1.1
5675 * Copyright(c) 2006-2007, Ext JS, LLC.
5677 * Originally Released Under LGPL - original licence link has changed is not relivant.
5680 * <script type="text/javascript">
5684 * @class Roo.util.Observable
5685 * Base class that provides a common interface for publishing events. Subclasses are expected to
5686 * to have a property "events" with all the events defined.<br>
5689 Employee = function(name){
5696 Roo.extend(Employee, Roo.util.Observable);
5698 * @param {Object} config properties to use (incuding events / listeners)
5701 Roo.util.Observable = function(cfg){
5704 this.addEvents(cfg.events || {});
5706 delete cfg.events; // make sure
5709 Roo.apply(this, cfg);
5712 this.on(this.listeners);
5713 delete this.listeners;
5716 Roo.util.Observable.prototype = {
5718 * @cfg {Object} listeners list of events and functions to call for this object,
5722 'click' : function(e) {
5732 * Fires the specified event with the passed parameters (minus the event name).
5733 * @param {String} eventName
5734 * @param {Object...} args Variable number of parameters are passed to handlers
5735 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5737 fireEvent : function(){
5738 var ce = this.events[arguments[0].toLowerCase()];
5739 if(typeof ce == "object"){
5740 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5747 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5750 * Appends an event handler to this component
5751 * @param {String} eventName The type of event to listen for
5752 * @param {Function} handler The method the event invokes
5753 * @param {Object} scope (optional) The scope in which to execute the handler
5754 * function. The handler function's "this" context.
5755 * @param {Object} options (optional) An object containing handler configuration
5756 * properties. This may contain any of the following properties:<ul>
5757 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5758 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5759 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5760 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5761 * by the specified number of milliseconds. If the event fires again within that time, the original
5762 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5765 * <b>Combining Options</b><br>
5766 * Using the options argument, it is possible to combine different types of listeners:<br>
5768 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5770 el.on('click', this.onClick, this, {
5777 * <b>Attaching multiple handlers in 1 call</b><br>
5778 * The method also allows for a single argument to be passed which is a config object containing properties
5779 * which specify multiple handlers.
5788 fn: this.onMouseOver,
5792 fn: this.onMouseOut,
5798 * Or a shorthand syntax which passes the same scope object to all handlers:
5801 'click': this.onClick,
5802 'mouseover': this.onMouseOver,
5803 'mouseout': this.onMouseOut,
5808 addListener : function(eventName, fn, scope, o){
5809 if(typeof eventName == "object"){
5812 if(this.filterOptRe.test(e)){
5815 if(typeof o[e] == "function"){
5817 this.addListener(e, o[e], o.scope, o);
5819 // individual options
5820 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5825 o = (!o || typeof o == "boolean") ? {} : o;
5826 eventName = eventName.toLowerCase();
5827 var ce = this.events[eventName] || true;
5828 if(typeof ce == "boolean"){
5829 ce = new Roo.util.Event(this, eventName);
5830 this.events[eventName] = ce;
5832 ce.addListener(fn, scope, o);
5836 * Removes a listener
5837 * @param {String} eventName The type of event to listen for
5838 * @param {Function} handler The handler to remove
5839 * @param {Object} scope (optional) The scope (this object) for the handler
5841 removeListener : function(eventName, fn, scope){
5842 var ce = this.events[eventName.toLowerCase()];
5843 if(typeof ce == "object"){
5844 ce.removeListener(fn, scope);
5849 * Removes all listeners for this object
5851 purgeListeners : function(){
5852 for(var evt in this.events){
5853 if(typeof this.events[evt] == "object"){
5854 this.events[evt].clearListeners();
5859 relayEvents : function(o, events){
5860 var createHandler = function(ename){
5862 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5865 for(var i = 0, len = events.length; i < len; i++){
5866 var ename = events[i];
5867 if(!this.events[ename]){ this.events[ename] = true; };
5868 o.on(ename, createHandler(ename), this);
5873 * Used to define events on this Observable
5874 * @param {Object} object The object with the events defined
5876 addEvents : function(o){
5880 Roo.applyIf(this.events, o);
5884 * Checks to see if this object has any listeners for a specified event
5885 * @param {String} eventName The name of the event to check for
5886 * @return {Boolean} True if the event is being listened for, else false
5888 hasListener : function(eventName){
5889 var e = this.events[eventName];
5890 return typeof e == "object" && e.listeners.length > 0;
5894 * Appends an event handler to this element (shorthand for addListener)
5895 * @param {String} eventName The type of event to listen for
5896 * @param {Function} handler The method the event invokes
5897 * @param {Object} scope (optional) The scope in which to execute the handler
5898 * function. The handler function's "this" context.
5899 * @param {Object} options (optional)
5902 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5904 * Removes a listener (shorthand for removeListener)
5905 * @param {String} eventName The type of event to listen for
5906 * @param {Function} handler The handler to remove
5907 * @param {Object} scope (optional) The scope (this object) for the handler
5910 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5913 * Starts capture on the specified Observable. All events will be passed
5914 * to the supplied function with the event name + standard signature of the event
5915 * <b>before</b> the event is fired. If the supplied function returns false,
5916 * the event will not fire.
5917 * @param {Observable} o The Observable to capture
5918 * @param {Function} fn The function to call
5919 * @param {Object} scope (optional) The scope (this object) for the fn
5922 Roo.util.Observable.capture = function(o, fn, scope){
5923 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5927 * Removes <b>all</b> added captures from the Observable.
5928 * @param {Observable} o The Observable to release
5931 Roo.util.Observable.releaseCapture = function(o){
5932 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5937 var createBuffered = function(h, o, scope){
5938 var task = new Roo.util.DelayedTask();
5940 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5944 var createSingle = function(h, e, fn, scope){
5946 e.removeListener(fn, scope);
5947 return h.apply(scope, arguments);
5951 var createDelayed = function(h, o, scope){
5953 var args = Array.prototype.slice.call(arguments, 0);
5954 setTimeout(function(){
5955 h.apply(scope, args);
5960 Roo.util.Event = function(obj, name){
5963 this.listeners = [];
5966 Roo.util.Event.prototype = {
5967 addListener : function(fn, scope, options){
5968 var o = options || {};
5969 scope = scope || this.obj;
5970 if(!this.isListening(fn, scope)){
5971 var l = {fn: fn, scope: scope, options: o};
5974 h = createDelayed(h, o, scope);
5977 h = createSingle(h, this, fn, scope);
5980 h = createBuffered(h, o, scope);
5983 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5984 this.listeners.push(l);
5986 this.listeners = this.listeners.slice(0);
5987 this.listeners.push(l);
5992 findListener : function(fn, scope){
5993 scope = scope || this.obj;
5994 var ls = this.listeners;
5995 for(var i = 0, len = ls.length; i < len; i++){
5997 if(l.fn == fn && l.scope == scope){
6004 isListening : function(fn, scope){
6005 return this.findListener(fn, scope) != -1;
6008 removeListener : function(fn, scope){
6010 if((index = this.findListener(fn, scope)) != -1){
6012 this.listeners.splice(index, 1);
6014 this.listeners = this.listeners.slice(0);
6015 this.listeners.splice(index, 1);
6022 clearListeners : function(){
6023 this.listeners = [];
6027 var ls = this.listeners, scope, len = ls.length;
6030 var args = Array.prototype.slice.call(arguments, 0);
6031 for(var i = 0; i < len; i++){
6033 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6034 this.firing = false;
6038 this.firing = false;
6045 * Ext JS Library 1.1.1
6046 * Copyright(c) 2006-2007, Ext JS, LLC.
6048 * Originally Released Under LGPL - original licence link has changed is not relivant.
6051 * <script type="text/javascript">
6055 * @class Roo.EventManager
6056 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6057 * several useful events directly.
6058 * See {@link Roo.EventObject} for more details on normalized event objects.
6061 Roo.EventManager = function(){
6062 var docReadyEvent, docReadyProcId, docReadyState = false;
6063 var resizeEvent, resizeTask, textEvent, textSize;
6064 var E = Roo.lib.Event;
6065 var D = Roo.lib.Dom;
6070 var fireDocReady = function(){
6072 docReadyState = true;
6075 clearInterval(docReadyProcId);
6077 if(Roo.isGecko || Roo.isOpera) {
6078 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6081 var defer = document.getElementById("ie-deferred-loader");
6083 defer.onreadystatechange = null;
6084 defer.parentNode.removeChild(defer);
6088 docReadyEvent.fire();
6089 docReadyEvent.clearListeners();
6094 var initDocReady = function(){
6095 docReadyEvent = new Roo.util.Event();
6096 if(Roo.isGecko || Roo.isOpera) {
6097 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6099 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6100 var defer = document.getElementById("ie-deferred-loader");
6101 defer.onreadystatechange = function(){
6102 if(this.readyState == "complete"){
6106 }else if(Roo.isSafari){
6107 docReadyProcId = setInterval(function(){
6108 var rs = document.readyState;
6109 if(rs == "complete") {
6114 // no matter what, make sure it fires on load
6115 E.on(window, "load", fireDocReady);
6118 var createBuffered = function(h, o){
6119 var task = new Roo.util.DelayedTask(h);
6121 // create new event object impl so new events don't wipe out properties
6122 e = new Roo.EventObjectImpl(e);
6123 task.delay(o.buffer, h, null, [e]);
6127 var createSingle = function(h, el, ename, fn){
6129 Roo.EventManager.removeListener(el, ename, fn);
6134 var createDelayed = function(h, o){
6136 // create new event object impl so new events don't wipe out properties
6137 e = new Roo.EventObjectImpl(e);
6138 setTimeout(function(){
6143 var transitionEndVal = false;
6145 var transitionEnd = function()
6147 if (transitionEndVal) {
6148 return transitionEndVal;
6150 var el = document.createElement('div');
6152 var transEndEventNames = {
6153 WebkitTransition : 'webkitTransitionEnd',
6154 MozTransition : 'transitionend',
6155 OTransition : 'oTransitionEnd otransitionend',
6156 transition : 'transitionend'
6159 for (var name in transEndEventNames) {
6160 if (el.style[name] !== undefined) {
6161 transitionEndVal = transEndEventNames[name];
6162 return transitionEndVal ;
6168 var listen = function(element, ename, opt, fn, scope){
6169 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6170 fn = fn || o.fn; scope = scope || o.scope;
6171 var el = Roo.getDom(element);
6175 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6178 if (ename == 'transitionend') {
6179 ename = transitionEnd();
6181 var h = function(e){
6182 e = Roo.EventObject.setEvent(e);
6185 t = e.getTarget(o.delegate, el);
6192 if(o.stopEvent === true){
6195 if(o.preventDefault === true){
6198 if(o.stopPropagation === true){
6199 e.stopPropagation();
6202 if(o.normalized === false){
6206 fn.call(scope || el, e, t, o);
6209 h = createDelayed(h, o);
6212 h = createSingle(h, el, ename, fn);
6215 h = createBuffered(h, o);
6217 fn._handlers = fn._handlers || [];
6220 fn._handlers.push([Roo.id(el), ename, h]);
6225 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6226 el.addEventListener("DOMMouseScroll", h, false);
6227 E.on(window, 'unload', function(){
6228 el.removeEventListener("DOMMouseScroll", h, false);
6231 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6232 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6237 var stopListening = function(el, ename, fn){
6238 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6240 for(var i = 0, len = hds.length; i < len; i++){
6242 if(h[0] == id && h[1] == ename){
6249 E.un(el, ename, hd);
6250 el = Roo.getDom(el);
6251 if(ename == "mousewheel" && el.addEventListener){
6252 el.removeEventListener("DOMMouseScroll", hd, false);
6254 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6255 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6259 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6266 * @scope Roo.EventManager
6271 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6272 * object with a Roo.EventObject
6273 * @param {Function} fn The method the event invokes
6274 * @param {Object} scope An object that becomes the scope of the handler
6275 * @param {boolean} override If true, the obj passed in becomes
6276 * the execution scope of the listener
6277 * @return {Function} The wrapped function
6280 wrap : function(fn, scope, override){
6282 Roo.EventObject.setEvent(e);
6283 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6288 * Appends an event handler to an element (shorthand for addListener)
6289 * @param {String/HTMLElement} element The html element or id to assign the
6290 * @param {String} eventName The type of event to listen for
6291 * @param {Function} handler The method the event invokes
6292 * @param {Object} scope (optional) The scope in which to execute the handler
6293 * function. The handler function's "this" context.
6294 * @param {Object} options (optional) An object containing handler configuration
6295 * properties. This may contain any of the following properties:<ul>
6296 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6297 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6298 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6299 * <li>preventDefault {Boolean} True to prevent the default action</li>
6300 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6301 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6302 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6303 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6304 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6305 * by the specified number of milliseconds. If the event fires again within that time, the original
6306 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6309 * <b>Combining Options</b><br>
6310 * Using the options argument, it is possible to combine different types of listeners:<br>
6312 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6314 el.on('click', this.onClick, this, {
6321 * <b>Attaching multiple handlers in 1 call</b><br>
6322 * The method also allows for a single argument to be passed which is a config object containing properties
6323 * which specify multiple handlers.
6333 fn: this.onMouseOver
6342 * Or a shorthand syntax:<br>
6345 'click' : this.onClick,
6346 'mouseover' : this.onMouseOver,
6347 'mouseout' : this.onMouseOut
6351 addListener : function(element, eventName, fn, scope, options){
6352 if(typeof eventName == "object"){
6358 if(typeof o[e] == "function"){
6360 listen(element, e, o, o[e], o.scope);
6362 // individual options
6363 listen(element, e, o[e]);
6368 return listen(element, eventName, options, fn, scope);
6372 * Removes an event handler
6374 * @param {String/HTMLElement} element The id or html element to remove the
6376 * @param {String} eventName The type of event
6377 * @param {Function} fn
6378 * @return {Boolean} True if a listener was actually removed
6380 removeListener : function(element, eventName, fn){
6381 return stopListening(element, eventName, fn);
6385 * Fires when the document is ready (before onload and before images are loaded). Can be
6386 * accessed shorthanded Roo.onReady().
6387 * @param {Function} fn The method the event invokes
6388 * @param {Object} scope An object that becomes the scope of the handler
6389 * @param {boolean} options
6391 onDocumentReady : function(fn, scope, options){
6392 if(docReadyState){ // if it already fired
6393 docReadyEvent.addListener(fn, scope, options);
6394 docReadyEvent.fire();
6395 docReadyEvent.clearListeners();
6401 docReadyEvent.addListener(fn, scope, options);
6405 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6406 * @param {Function} fn The method the event invokes
6407 * @param {Object} scope An object that becomes the scope of the handler
6408 * @param {boolean} options
6410 onWindowResize : function(fn, scope, options){
6412 resizeEvent = new Roo.util.Event();
6413 resizeTask = new Roo.util.DelayedTask(function(){
6414 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6416 E.on(window, "resize", function(){
6418 resizeTask.delay(50);
6420 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6424 resizeEvent.addListener(fn, scope, options);
6428 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6429 * @param {Function} fn The method the event invokes
6430 * @param {Object} scope An object that becomes the scope of the handler
6431 * @param {boolean} options
6433 onTextResize : function(fn, scope, options){
6435 textEvent = new Roo.util.Event();
6436 var textEl = new Roo.Element(document.createElement('div'));
6437 textEl.dom.className = 'x-text-resize';
6438 textEl.dom.innerHTML = 'X';
6439 textEl.appendTo(document.body);
6440 textSize = textEl.dom.offsetHeight;
6441 setInterval(function(){
6442 if(textEl.dom.offsetHeight != textSize){
6443 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6445 }, this.textResizeInterval);
6447 textEvent.addListener(fn, scope, options);
6451 * Removes the passed window resize listener.
6452 * @param {Function} fn The method the event invokes
6453 * @param {Object} scope The scope of handler
6455 removeResizeListener : function(fn, scope){
6457 resizeEvent.removeListener(fn, scope);
6462 fireResize : function(){
6464 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6468 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6472 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6474 textResizeInterval : 50
6479 * @scopeAlias pub=Roo.EventManager
6483 * Appends an event handler to an element (shorthand for addListener)
6484 * @param {String/HTMLElement} element The html element or id to assign the
6485 * @param {String} eventName The type of event to listen for
6486 * @param {Function} handler The method the event invokes
6487 * @param {Object} scope (optional) The scope in which to execute the handler
6488 * function. The handler function's "this" context.
6489 * @param {Object} options (optional) An object containing handler configuration
6490 * properties. This may contain any of the following properties:<ul>
6491 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6492 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6493 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6494 * <li>preventDefault {Boolean} True to prevent the default action</li>
6495 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6496 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6497 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6498 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6499 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6500 * by the specified number of milliseconds. If the event fires again within that time, the original
6501 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6504 * <b>Combining Options</b><br>
6505 * Using the options argument, it is possible to combine different types of listeners:<br>
6507 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6509 el.on('click', this.onClick, this, {
6516 * <b>Attaching multiple handlers in 1 call</b><br>
6517 * The method also allows for a single argument to be passed which is a config object containing properties
6518 * which specify multiple handlers.
6528 fn: this.onMouseOver
6537 * Or a shorthand syntax:<br>
6540 'click' : this.onClick,
6541 'mouseover' : this.onMouseOver,
6542 'mouseout' : this.onMouseOut
6546 pub.on = pub.addListener;
6547 pub.un = pub.removeListener;
6549 pub.stoppedMouseDownEvent = new Roo.util.Event();
6553 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6554 * @param {Function} fn The method the event invokes
6555 * @param {Object} scope An object that becomes the scope of the handler
6556 * @param {boolean} override If true, the obj passed in becomes
6557 * the execution scope of the listener
6561 Roo.onReady = Roo.EventManager.onDocumentReady;
6563 Roo.onReady(function(){
6564 var bd = Roo.get(document.body);
6569 : Roo.isGecko ? "roo-gecko"
6570 : Roo.isOpera ? "roo-opera"
6571 : Roo.isSafari ? "roo-safari" : ""];
6574 cls.push("roo-mac");
6577 cls.push("roo-linux");
6579 if(Roo.isBorderBox){
6580 cls.push('roo-border-box');
6582 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6583 var p = bd.dom.parentNode;
6585 p.className += ' roo-strict';
6588 bd.addClass(cls.join(' '));
6592 * @class Roo.EventObject
6593 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6594 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6597 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6599 var target = e.getTarget();
6602 var myDiv = Roo.get("myDiv");
6603 myDiv.on("click", handleClick);
6605 Roo.EventManager.on("myDiv", 'click', handleClick);
6606 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6610 Roo.EventObject = function(){
6612 var E = Roo.lib.Event;
6614 // safari keypress events for special keys return bad keycodes
6617 63235 : 39, // right
6620 63276 : 33, // page up
6621 63277 : 34, // page down
6622 63272 : 46, // delete
6627 // normalize button clicks
6628 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6629 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6631 Roo.EventObjectImpl = function(e){
6633 this.setEvent(e.browserEvent || e);
6636 Roo.EventObjectImpl.prototype = {
6638 * Used to fix doc tools.
6639 * @scope Roo.EventObject.prototype
6645 /** The normal browser event */
6646 browserEvent : null,
6647 /** The button pressed in a mouse event */
6649 /** True if the shift key was down during the event */
6651 /** True if the control key was down during the event */
6653 /** True if the alt key was down during the event */
6712 setEvent : function(e){
6713 if(e == this || (e && e.browserEvent)){ // already wrapped
6716 this.browserEvent = e;
6718 // normalize buttons
6719 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6720 if(e.type == 'click' && this.button == -1){
6724 this.shiftKey = e.shiftKey;
6725 // mac metaKey behaves like ctrlKey
6726 this.ctrlKey = e.ctrlKey || e.metaKey;
6727 this.altKey = e.altKey;
6728 // in getKey these will be normalized for the mac
6729 this.keyCode = e.keyCode;
6730 // keyup warnings on firefox.
6731 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6732 // cache the target for the delayed and or buffered events
6733 this.target = E.getTarget(e);
6735 this.xy = E.getXY(e);
6738 this.shiftKey = false;
6739 this.ctrlKey = false;
6740 this.altKey = false;
6750 * Stop the event (preventDefault and stopPropagation)
6752 stopEvent : function(){
6753 if(this.browserEvent){
6754 if(this.browserEvent.type == 'mousedown'){
6755 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6757 E.stopEvent(this.browserEvent);
6762 * Prevents the browsers default handling of the event.
6764 preventDefault : function(){
6765 if(this.browserEvent){
6766 E.preventDefault(this.browserEvent);
6771 isNavKeyPress : function(){
6772 var k = this.keyCode;
6773 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6774 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6777 isSpecialKey : function(){
6778 var k = this.keyCode;
6779 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6780 (k == 16) || (k == 17) ||
6781 (k >= 18 && k <= 20) ||
6782 (k >= 33 && k <= 35) ||
6783 (k >= 36 && k <= 39) ||
6784 (k >= 44 && k <= 45);
6787 * Cancels bubbling of the event.
6789 stopPropagation : function(){
6790 if(this.browserEvent){
6791 if(this.type == 'mousedown'){
6792 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6794 E.stopPropagation(this.browserEvent);
6799 * Gets the key code for the event.
6802 getCharCode : function(){
6803 return this.charCode || this.keyCode;
6807 * Returns a normalized keyCode for the event.
6808 * @return {Number} The key code
6810 getKey : function(){
6811 var k = this.keyCode || this.charCode;
6812 return Roo.isSafari ? (safariKeys[k] || k) : k;
6816 * Gets the x coordinate of the event.
6819 getPageX : function(){
6824 * Gets the y coordinate of the event.
6827 getPageY : function(){
6832 * Gets the time of the event.
6835 getTime : function(){
6836 if(this.browserEvent){
6837 return E.getTime(this.browserEvent);
6843 * Gets the page coordinates of the event.
6844 * @return {Array} The xy values like [x, y]
6851 * Gets the target for the event.
6852 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6853 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6854 search as a number or element (defaults to 10 || document.body)
6855 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6856 * @return {HTMLelement}
6858 getTarget : function(selector, maxDepth, returnEl){
6859 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6862 * Gets the related target.
6863 * @return {HTMLElement}
6865 getRelatedTarget : function(){
6866 if(this.browserEvent){
6867 return E.getRelatedTarget(this.browserEvent);
6873 * Normalizes mouse wheel delta across browsers
6874 * @return {Number} The delta
6876 getWheelDelta : function(){
6877 var e = this.browserEvent;
6879 if(e.wheelDelta){ /* IE/Opera. */
6880 delta = e.wheelDelta/120;
6881 }else if(e.detail){ /* Mozilla case. */
6882 delta = -e.detail/3;
6888 * Returns true if the control, meta, shift or alt key was pressed during this event.
6891 hasModifier : function(){
6892 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6896 * Returns true if the target of this event equals el or is a child of el
6897 * @param {String/HTMLElement/Element} el
6898 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6901 within : function(el, related){
6902 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6903 return t && Roo.fly(el).contains(t);
6906 getPoint : function(){
6907 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6911 return new Roo.EventObjectImpl();
6916 * Ext JS Library 1.1.1
6917 * Copyright(c) 2006-2007, Ext JS, LLC.
6919 * Originally Released Under LGPL - original licence link has changed is not relivant.
6922 * <script type="text/javascript">
6926 // was in Composite Element!??!?!
6929 var D = Roo.lib.Dom;
6930 var E = Roo.lib.Event;
6931 var A = Roo.lib.Anim;
6933 // local style camelizing for speed
6935 var camelRe = /(-[a-z])/gi;
6936 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6937 var view = document.defaultView;
6940 * @class Roo.Element
6941 * Represents an Element in the DOM.<br><br>
6944 var el = Roo.get("my-div");
6947 var el = getEl("my-div");
6949 // or with a DOM element
6950 var el = Roo.get(myDivElement);
6952 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6953 * each call instead of constructing a new one.<br><br>
6954 * <b>Animations</b><br />
6955 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6956 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6958 Option Default Description
6959 --------- -------- ---------------------------------------------
6960 duration .35 The duration of the animation in seconds
6961 easing easeOut The YUI easing method
6962 callback none A function to execute when the anim completes
6963 scope this The scope (this) of the callback function
6965 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6966 * manipulate the animation. Here's an example:
6968 var el = Roo.get("my-div");
6973 // default animation
6974 el.setWidth(100, true);
6976 // animation with some options set
6983 // using the "anim" property to get the Anim object
6989 el.setWidth(100, opt);
6991 if(opt.anim.isAnimated()){
6995 * <b> Composite (Collections of) Elements</b><br />
6996 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6997 * @constructor Create a new Element directly.
6998 * @param {String/HTMLElement} element
6999 * @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).
7001 Roo.Element = function(element, forceNew){
7002 var dom = typeof element == "string" ?
7003 document.getElementById(element) : element;
7004 if(!dom){ // invalid id/element
7008 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7009 return Roo.Element.cache[id];
7019 * The DOM element ID
7022 this.id = id || Roo.id(dom);
7025 var El = Roo.Element;
7029 * The element's default display mode (defaults to "")
7032 originalDisplay : "",
7036 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7041 * Sets the element's visibility mode. When setVisible() is called it
7042 * will use this to determine whether to set the visibility or the display property.
7043 * @param visMode Element.VISIBILITY or Element.DISPLAY
7044 * @return {Roo.Element} this
7046 setVisibilityMode : function(visMode){
7047 this.visibilityMode = visMode;
7051 * Convenience method for setVisibilityMode(Element.DISPLAY)
7052 * @param {String} display (optional) What to set display to when visible
7053 * @return {Roo.Element} this
7055 enableDisplayMode : function(display){
7056 this.setVisibilityMode(El.DISPLAY);
7057 if(typeof display != "undefined") this.originalDisplay = display;
7062 * 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)
7063 * @param {String} selector The simple selector to test
7064 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7065 search as a number or element (defaults to 10 || document.body)
7066 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7067 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7069 findParent : function(simpleSelector, maxDepth, returnEl){
7070 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7071 maxDepth = maxDepth || 50;
7072 if(typeof maxDepth != "number"){
7073 stopEl = Roo.getDom(maxDepth);
7076 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7077 if(dq.is(p, simpleSelector)){
7078 return returnEl ? Roo.get(p) : p;
7088 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7089 * @param {String} selector The simple selector to test
7090 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7091 search as a number or element (defaults to 10 || document.body)
7092 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7093 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7095 findParentNode : function(simpleSelector, maxDepth, returnEl){
7096 var p = Roo.fly(this.dom.parentNode, '_internal');
7097 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7101 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7102 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7103 * @param {String} selector The simple selector to test
7104 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7105 search as a number or element (defaults to 10 || document.body)
7106 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7108 up : function(simpleSelector, maxDepth){
7109 return this.findParentNode(simpleSelector, maxDepth, true);
7115 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7116 * @param {String} selector The simple selector to test
7117 * @return {Boolean} True if this element matches the selector, else false
7119 is : function(simpleSelector){
7120 return Roo.DomQuery.is(this.dom, simpleSelector);
7124 * Perform animation on this element.
7125 * @param {Object} args The YUI animation control args
7126 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7127 * @param {Function} onComplete (optional) Function to call when animation completes
7128 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7129 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7130 * @return {Roo.Element} this
7132 animate : function(args, duration, onComplete, easing, animType){
7133 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7138 * @private Internal animation call
7140 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7141 animType = animType || 'run';
7143 var anim = Roo.lib.Anim[animType](
7145 (opt.duration || defaultDur) || .35,
7146 (opt.easing || defaultEase) || 'easeOut',
7148 Roo.callback(cb, this);
7149 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7157 // private legacy anim prep
7158 preanim : function(a, i){
7159 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7163 * Removes worthless text nodes
7164 * @param {Boolean} forceReclean (optional) By default the element
7165 * keeps track if it has been cleaned already so
7166 * you can call this over and over. However, if you update the element and
7167 * need to force a reclean, you can pass true.
7169 clean : function(forceReclean){
7170 if(this.isCleaned && forceReclean !== true){
7174 var d = this.dom, n = d.firstChild, ni = -1;
7176 var nx = n.nextSibling;
7177 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7184 this.isCleaned = true;
7189 calcOffsetsTo : function(el){
7192 var restorePos = false;
7193 if(el.getStyle('position') == 'static'){
7194 el.position('relative');
7199 while(op && op != d && op.tagName != 'HTML'){
7202 op = op.offsetParent;
7205 el.position('static');
7211 * Scrolls this element into view within the passed container.
7212 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7213 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7214 * @return {Roo.Element} this
7216 scrollIntoView : function(container, hscroll){
7217 var c = Roo.getDom(container) || document.body;
7220 var o = this.calcOffsetsTo(c),
7223 b = t+el.offsetHeight,
7224 r = l+el.offsetWidth;
7226 var ch = c.clientHeight;
7227 var ct = parseInt(c.scrollTop, 10);
7228 var cl = parseInt(c.scrollLeft, 10);
7230 var cr = cl + c.clientWidth;
7238 if(hscroll !== false){
7242 c.scrollLeft = r-c.clientWidth;
7249 scrollChildIntoView : function(child, hscroll){
7250 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7254 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7255 * the new height may not be available immediately.
7256 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7257 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7258 * @param {Function} onComplete (optional) Function to call when animation completes
7259 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7260 * @return {Roo.Element} this
7262 autoHeight : function(animate, duration, onComplete, easing){
7263 var oldHeight = this.getHeight();
7265 this.setHeight(1); // force clipping
7266 setTimeout(function(){
7267 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7269 this.setHeight(height);
7271 if(typeof onComplete == "function"){
7275 this.setHeight(oldHeight); // restore original height
7276 this.setHeight(height, animate, duration, function(){
7278 if(typeof onComplete == "function") onComplete();
7279 }.createDelegate(this), easing);
7281 }.createDelegate(this), 0);
7286 * Returns true if this element is an ancestor of the passed element
7287 * @param {HTMLElement/String} el The element to check
7288 * @return {Boolean} True if this element is an ancestor of el, else false
7290 contains : function(el){
7291 if(!el){return false;}
7292 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7296 * Checks whether the element is currently visible using both visibility and display properties.
7297 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7298 * @return {Boolean} True if the element is currently visible, else false
7300 isVisible : function(deep) {
7301 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7302 if(deep !== true || !vis){
7305 var p = this.dom.parentNode;
7306 while(p && p.tagName.toLowerCase() != "body"){
7307 if(!Roo.fly(p, '_isVisible').isVisible()){
7316 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7317 * @param {String} selector The CSS selector
7318 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7319 * @return {CompositeElement/CompositeElementLite} The composite element
7321 select : function(selector, unique){
7322 return El.select(selector, unique, this.dom);
7326 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7327 * @param {String} selector The CSS selector
7328 * @return {Array} An array of the matched nodes
7330 query : function(selector, unique){
7331 return Roo.DomQuery.select(selector, this.dom);
7335 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7336 * @param {String} selector The CSS selector
7337 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7338 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7340 child : function(selector, returnDom){
7341 var n = Roo.DomQuery.selectNode(selector, this.dom);
7342 return returnDom ? n : Roo.get(n);
7346 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7347 * @param {String} selector The CSS selector
7348 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7349 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7351 down : function(selector, returnDom){
7352 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7353 return returnDom ? n : Roo.get(n);
7357 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7358 * @param {String} group The group the DD object is member of
7359 * @param {Object} config The DD config object
7360 * @param {Object} overrides An object containing methods to override/implement on the DD object
7361 * @return {Roo.dd.DD} The DD object
7363 initDD : function(group, config, overrides){
7364 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7365 return Roo.apply(dd, overrides);
7369 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7370 * @param {String} group The group the DDProxy object is member of
7371 * @param {Object} config The DDProxy config object
7372 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7373 * @return {Roo.dd.DDProxy} The DDProxy object
7375 initDDProxy : function(group, config, overrides){
7376 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7377 return Roo.apply(dd, overrides);
7381 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7382 * @param {String} group The group the DDTarget object is member of
7383 * @param {Object} config The DDTarget config object
7384 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7385 * @return {Roo.dd.DDTarget} The DDTarget object
7387 initDDTarget : function(group, config, overrides){
7388 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7389 return Roo.apply(dd, overrides);
7393 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7394 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7395 * @param {Boolean} visible Whether the element is visible
7396 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7397 * @return {Roo.Element} this
7399 setVisible : function(visible, animate){
7401 if(this.visibilityMode == El.DISPLAY){
7402 this.setDisplayed(visible);
7405 this.dom.style.visibility = visible ? "visible" : "hidden";
7408 // closure for composites
7410 var visMode = this.visibilityMode;
7412 this.setOpacity(.01);
7413 this.setVisible(true);
7415 this.anim({opacity: { to: (visible?1:0) }},
7416 this.preanim(arguments, 1),
7417 null, .35, 'easeIn', function(){
7419 if(visMode == El.DISPLAY){
7420 dom.style.display = "none";
7422 dom.style.visibility = "hidden";
7424 Roo.get(dom).setOpacity(1);
7432 * Returns true if display is not "none"
7435 isDisplayed : function() {
7436 return this.getStyle("display") != "none";
7440 * Toggles the element's visibility or display, depending on visibility mode.
7441 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7442 * @return {Roo.Element} this
7444 toggle : function(animate){
7445 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7450 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7451 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7452 * @return {Roo.Element} this
7454 setDisplayed : function(value) {
7455 if(typeof value == "boolean"){
7456 value = value ? this.originalDisplay : "none";
7458 this.setStyle("display", value);
7463 * Tries to focus the element. Any exceptions are caught and ignored.
7464 * @return {Roo.Element} this
7466 focus : function() {
7474 * Tries to blur the element. Any exceptions are caught and ignored.
7475 * @return {Roo.Element} this
7485 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7486 * @param {String/Array} className The CSS class to add, or an array of classes
7487 * @return {Roo.Element} this
7489 addClass : function(className){
7490 if(className instanceof Array){
7491 for(var i = 0, len = className.length; i < len; i++) {
7492 this.addClass(className[i]);
7495 if(className && !this.hasClass(className)){
7496 this.dom.className = this.dom.className + " " + className;
7503 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7504 * @param {String/Array} className The CSS class to add, or an array of classes
7505 * @return {Roo.Element} this
7507 radioClass : function(className){
7508 var siblings = this.dom.parentNode.childNodes;
7509 for(var i = 0; i < siblings.length; i++) {
7510 var s = siblings[i];
7511 if(s.nodeType == 1){
7512 Roo.get(s).removeClass(className);
7515 this.addClass(className);
7520 * Removes one or more CSS classes from the element.
7521 * @param {String/Array} className The CSS class to remove, or an array of classes
7522 * @return {Roo.Element} this
7524 removeClass : function(className){
7525 if(!className || !this.dom.className){
7528 if(className instanceof Array){
7529 for(var i = 0, len = className.length; i < len; i++) {
7530 this.removeClass(className[i]);
7533 if(this.hasClass(className)){
7534 var re = this.classReCache[className];
7536 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7537 this.classReCache[className] = re;
7539 this.dom.className =
7540 this.dom.className.replace(re, " ");
7550 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7551 * @param {String} className The CSS class to toggle
7552 * @return {Roo.Element} this
7554 toggleClass : function(className){
7555 if(this.hasClass(className)){
7556 this.removeClass(className);
7558 this.addClass(className);
7564 * Checks if the specified CSS class exists on this element's DOM node.
7565 * @param {String} className The CSS class to check for
7566 * @return {Boolean} True if the class exists, else false
7568 hasClass : function(className){
7569 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7573 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7574 * @param {String} oldClassName The CSS class to replace
7575 * @param {String} newClassName The replacement CSS class
7576 * @return {Roo.Element} this
7578 replaceClass : function(oldClassName, newClassName){
7579 this.removeClass(oldClassName);
7580 this.addClass(newClassName);
7585 * Returns an object with properties matching the styles requested.
7586 * For example, el.getStyles('color', 'font-size', 'width') might return
7587 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7588 * @param {String} style1 A style name
7589 * @param {String} style2 A style name
7590 * @param {String} etc.
7591 * @return {Object} The style object
7593 getStyles : function(){
7594 var a = arguments, len = a.length, r = {};
7595 for(var i = 0; i < len; i++){
7596 r[a[i]] = this.getStyle(a[i]);
7602 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7603 * @param {String} property The style property whose value is returned.
7604 * @return {String} The current value of the style property for this element.
7606 getStyle : function(){
7607 return view && view.getComputedStyle ?
7609 var el = this.dom, v, cs, camel;
7610 if(prop == 'float'){
7613 if(el.style && (v = el.style[prop])){
7616 if(cs = view.getComputedStyle(el, "")){
7617 if(!(camel = propCache[prop])){
7618 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7625 var el = this.dom, v, cs, camel;
7626 if(prop == 'opacity'){
7627 if(typeof el.style.filter == 'string'){
7628 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7630 var fv = parseFloat(m[1]);
7632 return fv ? fv / 100 : 0;
7637 }else if(prop == 'float'){
7638 prop = "styleFloat";
7640 if(!(camel = propCache[prop])){
7641 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7643 if(v = el.style[camel]){
7646 if(cs = el.currentStyle){
7654 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7655 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7656 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7657 * @return {Roo.Element} this
7659 setStyle : function(prop, value){
7660 if(typeof prop == "string"){
7662 if (prop == 'float') {
7663 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7668 if(!(camel = propCache[prop])){
7669 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7672 if(camel == 'opacity') {
7673 this.setOpacity(value);
7675 this.dom.style[camel] = value;
7678 for(var style in prop){
7679 if(typeof prop[style] != "function"){
7680 this.setStyle(style, prop[style]);
7688 * More flexible version of {@link #setStyle} for setting style properties.
7689 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7690 * a function which returns such a specification.
7691 * @return {Roo.Element} this
7693 applyStyles : function(style){
7694 Roo.DomHelper.applyStyles(this.dom, style);
7699 * 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).
7700 * @return {Number} The X position of the element
7703 return D.getX(this.dom);
7707 * 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).
7708 * @return {Number} The Y position of the element
7711 return D.getY(this.dom);
7715 * 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).
7716 * @return {Array} The XY position of the element
7719 return D.getXY(this.dom);
7723 * 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).
7724 * @param {Number} The X position of the element
7725 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7726 * @return {Roo.Element} this
7728 setX : function(x, animate){
7730 D.setX(this.dom, x);
7732 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7738 * 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).
7739 * @param {Number} The Y position of the element
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setY : function(y, animate){
7745 D.setY(this.dom, y);
7747 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7753 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7754 * @param {String} left The left CSS property value
7755 * @return {Roo.Element} this
7757 setLeft : function(left){
7758 this.setStyle("left", this.addUnits(left));
7763 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7764 * @param {String} top The top CSS property value
7765 * @return {Roo.Element} this
7767 setTop : function(top){
7768 this.setStyle("top", this.addUnits(top));
7773 * Sets the element's CSS right style.
7774 * @param {String} right The right CSS property value
7775 * @return {Roo.Element} this
7777 setRight : function(right){
7778 this.setStyle("right", this.addUnits(right));
7783 * Sets the element's CSS bottom style.
7784 * @param {String} bottom The bottom CSS property value
7785 * @return {Roo.Element} this
7787 setBottom : function(bottom){
7788 this.setStyle("bottom", this.addUnits(bottom));
7793 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7794 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7795 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7796 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7797 * @return {Roo.Element} this
7799 setXY : function(pos, animate){
7801 D.setXY(this.dom, pos);
7803 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7809 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7810 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7811 * @param {Number} x X value for new position (coordinates are page-based)
7812 * @param {Number} y Y value for new position (coordinates are page-based)
7813 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7814 * @return {Roo.Element} this
7816 setLocation : function(x, y, animate){
7817 this.setXY([x, y], this.preanim(arguments, 2));
7822 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7823 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7824 * @param {Number} x X value for new position (coordinates are page-based)
7825 * @param {Number} y Y value for new position (coordinates are page-based)
7826 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7827 * @return {Roo.Element} this
7829 moveTo : function(x, y, animate){
7830 this.setXY([x, y], this.preanim(arguments, 2));
7835 * Returns the region of the given element.
7836 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7837 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7839 getRegion : function(){
7840 return D.getRegion(this.dom);
7844 * Returns the offset height of the element
7845 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7846 * @return {Number} The element's height
7848 getHeight : function(contentHeight){
7849 var h = this.dom.offsetHeight || 0;
7850 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7854 * Returns the offset width of the element
7855 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7856 * @return {Number} The element's width
7858 getWidth : function(contentWidth){
7859 var w = this.dom.offsetWidth || 0;
7860 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7864 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7865 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7866 * if a height has not been set using CSS.
7869 getComputedHeight : function(){
7870 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7872 h = parseInt(this.getStyle('height'), 10) || 0;
7873 if(!this.isBorderBox()){
7874 h += this.getFrameWidth('tb');
7881 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7882 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7883 * if a width has not been set using CSS.
7886 getComputedWidth : function(){
7887 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7889 w = parseInt(this.getStyle('width'), 10) || 0;
7890 if(!this.isBorderBox()){
7891 w += this.getFrameWidth('lr');
7898 * Returns the size of the element.
7899 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7900 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7902 getSize : function(contentSize){
7903 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7907 * Returns the width and height of the viewport.
7908 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7910 getViewSize : function(){
7911 var d = this.dom, doc = document, aw = 0, ah = 0;
7912 if(d == doc || d == doc.body){
7913 return {width : D.getViewWidth(), height: D.getViewHeight()};
7916 width : d.clientWidth,
7917 height: d.clientHeight
7923 * Returns the value of the "value" attribute
7924 * @param {Boolean} asNumber true to parse the value as a number
7925 * @return {String/Number}
7927 getValue : function(asNumber){
7928 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7932 adjustWidth : function(width){
7933 if(typeof width == "number"){
7934 if(this.autoBoxAdjust && !this.isBorderBox()){
7935 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7945 adjustHeight : function(height){
7946 if(typeof height == "number"){
7947 if(this.autoBoxAdjust && !this.isBorderBox()){
7948 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7958 * Set the width of the element
7959 * @param {Number} width The new width
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setWidth : function(width, animate){
7964 width = this.adjustWidth(width);
7966 this.dom.style.width = this.addUnits(width);
7968 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7974 * Set the height of the element
7975 * @param {Number} height The new height
7976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977 * @return {Roo.Element} this
7979 setHeight : function(height, animate){
7980 height = this.adjustHeight(height);
7982 this.dom.style.height = this.addUnits(height);
7984 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7990 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7991 * @param {Number} width The new width
7992 * @param {Number} height The new height
7993 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7994 * @return {Roo.Element} this
7996 setSize : function(width, height, animate){
7997 if(typeof width == "object"){ // in case of object from getSize()
7998 height = width.height; width = width.width;
8000 width = this.adjustWidth(width); height = this.adjustHeight(height);
8002 this.dom.style.width = this.addUnits(width);
8003 this.dom.style.height = this.addUnits(height);
8005 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8011 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8012 * @param {Number} x X value for new position (coordinates are page-based)
8013 * @param {Number} y Y value for new position (coordinates are page-based)
8014 * @param {Number} width The new width
8015 * @param {Number} height The new height
8016 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8017 * @return {Roo.Element} this
8019 setBounds : function(x, y, width, height, animate){
8021 this.setSize(width, height);
8022 this.setLocation(x, y);
8024 width = this.adjustWidth(width); height = this.adjustHeight(height);
8025 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8026 this.preanim(arguments, 4), 'motion');
8032 * 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.
8033 * @param {Roo.lib.Region} region The region to fill
8034 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8035 * @return {Roo.Element} this
8037 setRegion : function(region, animate){
8038 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8043 * Appends an event handler
8045 * @param {String} eventName The type of event to append
8046 * @param {Function} fn The method the event invokes
8047 * @param {Object} scope (optional) The scope (this object) of the fn
8048 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8050 addListener : function(eventName, fn, scope, options){
8052 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8057 * Removes an event handler from this element
8058 * @param {String} eventName the type of event to remove
8059 * @param {Function} fn the method the event invokes
8060 * @return {Roo.Element} this
8062 removeListener : function(eventName, fn){
8063 Roo.EventManager.removeListener(this.dom, eventName, fn);
8068 * Removes all previous added listeners from this element
8069 * @return {Roo.Element} this
8071 removeAllListeners : function(){
8072 E.purgeElement(this.dom);
8076 relayEvent : function(eventName, observable){
8077 this.on(eventName, function(e){
8078 observable.fireEvent(eventName, e);
8083 * Set the opacity of the element
8084 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8085 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8086 * @return {Roo.Element} this
8088 setOpacity : function(opacity, animate){
8090 var s = this.dom.style;
8093 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8094 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8096 s.opacity = opacity;
8099 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8105 * Gets the left X coordinate
8106 * @param {Boolean} local True to get the local css position instead of page coordinate
8109 getLeft : function(local){
8113 return parseInt(this.getStyle("left"), 10) || 0;
8118 * Gets the right X coordinate of the element (element X position + element width)
8119 * @param {Boolean} local True to get the local css position instead of page coordinate
8122 getRight : function(local){
8124 return this.getX() + this.getWidth();
8126 return (this.getLeft(true) + this.getWidth()) || 0;
8131 * Gets the top Y coordinate
8132 * @param {Boolean} local True to get the local css position instead of page coordinate
8135 getTop : function(local) {
8139 return parseInt(this.getStyle("top"), 10) || 0;
8144 * Gets the bottom Y coordinate of the element (element Y position + element height)
8145 * @param {Boolean} local True to get the local css position instead of page coordinate
8148 getBottom : function(local){
8150 return this.getY() + this.getHeight();
8152 return (this.getTop(true) + this.getHeight()) || 0;
8157 * Initializes positioning on this element. If a desired position is not passed, it will make the
8158 * the element positioned relative IF it is not already positioned.
8159 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8160 * @param {Number} zIndex (optional) The zIndex to apply
8161 * @param {Number} x (optional) Set the page X position
8162 * @param {Number} y (optional) Set the page Y position
8164 position : function(pos, zIndex, x, y){
8166 if(this.getStyle('position') == 'static'){
8167 this.setStyle('position', 'relative');
8170 this.setStyle("position", pos);
8173 this.setStyle("z-index", zIndex);
8175 if(x !== undefined && y !== undefined){
8177 }else if(x !== undefined){
8179 }else if(y !== undefined){
8185 * Clear positioning back to the default when the document was loaded
8186 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8187 * @return {Roo.Element} this
8189 clearPositioning : function(value){
8197 "position" : "static"
8203 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8204 * snapshot before performing an update and then restoring the element.
8207 getPositioning : function(){
8208 var l = this.getStyle("left");
8209 var t = this.getStyle("top");
8211 "position" : this.getStyle("position"),
8213 "right" : l ? "" : this.getStyle("right"),
8215 "bottom" : t ? "" : this.getStyle("bottom"),
8216 "z-index" : this.getStyle("z-index")
8221 * Gets the width of the border(s) for the specified side(s)
8222 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8223 * passing lr would get the border (l)eft width + the border (r)ight width.
8224 * @return {Number} The width of the sides passed added together
8226 getBorderWidth : function(side){
8227 return this.addStyles(side, El.borders);
8231 * Gets the width of the padding(s) for the specified side(s)
8232 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8233 * passing lr would get the padding (l)eft + the padding (r)ight.
8234 * @return {Number} The padding of the sides passed added together
8236 getPadding : function(side){
8237 return this.addStyles(side, El.paddings);
8241 * Set positioning with an object returned by getPositioning().
8242 * @param {Object} posCfg
8243 * @return {Roo.Element} this
8245 setPositioning : function(pc){
8246 this.applyStyles(pc);
8247 if(pc.right == "auto"){
8248 this.dom.style.right = "";
8250 if(pc.bottom == "auto"){
8251 this.dom.style.bottom = "";
8257 fixDisplay : function(){
8258 if(this.getStyle("display") == "none"){
8259 this.setStyle("visibility", "hidden");
8260 this.setStyle("display", this.originalDisplay); // first try reverting to default
8261 if(this.getStyle("display") == "none"){ // if that fails, default to block
8262 this.setStyle("display", "block");
8268 * Quick set left and top adding default units
8269 * @param {String} left The left CSS property value
8270 * @param {String} top The top CSS property value
8271 * @return {Roo.Element} this
8273 setLeftTop : function(left, top){
8274 this.dom.style.left = this.addUnits(left);
8275 this.dom.style.top = this.addUnits(top);
8280 * Move this element relative to its current position.
8281 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8282 * @param {Number} distance How far to move the element in pixels
8283 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8284 * @return {Roo.Element} this
8286 move : function(direction, distance, animate){
8287 var xy = this.getXY();
8288 direction = direction.toLowerCase();
8292 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8296 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8301 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8306 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8313 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8314 * @return {Roo.Element} this
8317 if(!this.isClipped){
8318 this.isClipped = true;
8319 this.originalClip = {
8320 "o": this.getStyle("overflow"),
8321 "x": this.getStyle("overflow-x"),
8322 "y": this.getStyle("overflow-y")
8324 this.setStyle("overflow", "hidden");
8325 this.setStyle("overflow-x", "hidden");
8326 this.setStyle("overflow-y", "hidden");
8332 * Return clipping (overflow) to original clipping before clip() was called
8333 * @return {Roo.Element} this
8335 unclip : function(){
8337 this.isClipped = false;
8338 var o = this.originalClip;
8339 if(o.o){this.setStyle("overflow", o.o);}
8340 if(o.x){this.setStyle("overflow-x", o.x);}
8341 if(o.y){this.setStyle("overflow-y", o.y);}
8348 * Gets the x,y coordinates specified by the anchor position on the element.
8349 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8350 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8351 * {width: (target width), height: (target height)} (defaults to the element's current size)
8352 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8353 * @return {Array} [x, y] An array containing the element's x and y coordinates
8355 getAnchorXY : function(anchor, local, s){
8356 //Passing a different size is useful for pre-calculating anchors,
8357 //especially for anchored animations that change the el size.
8359 var w, h, vp = false;
8362 if(d == document.body || d == document){
8364 w = D.getViewWidth(); h = D.getViewHeight();
8366 w = this.getWidth(); h = this.getHeight();
8369 w = s.width; h = s.height;
8371 var x = 0, y = 0, r = Math.round;
8372 switch((anchor || "tl").toLowerCase()){
8414 var sc = this.getScroll();
8415 return [x + sc.left, y + sc.top];
8417 //Add the element's offset xy
8418 var o = this.getXY();
8419 return [x+o[0], y+o[1]];
8423 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8424 * supported position values.
8425 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8426 * @param {String} position The position to align to.
8427 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8428 * @return {Array} [x, y]
8430 getAlignToXY : function(el, p, o){
8434 throw "Element.alignTo with an element that doesn't exist";
8436 var c = false; //constrain to viewport
8437 var p1 = "", p2 = "";
8444 }else if(p.indexOf("-") == -1){
8447 p = p.toLowerCase();
8448 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8450 throw "Element.alignTo with an invalid alignment " + p;
8452 p1 = m[1]; p2 = m[2]; c = !!m[3];
8454 //Subtract the aligned el's internal xy from the target's offset xy
8455 //plus custom offset to get the aligned el's new offset xy
8456 var a1 = this.getAnchorXY(p1, true);
8457 var a2 = el.getAnchorXY(p2, false);
8458 var x = a2[0] - a1[0] + o[0];
8459 var y = a2[1] - a1[1] + o[1];
8461 //constrain the aligned el to viewport if necessary
8462 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8463 // 5px of margin for ie
8464 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8466 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8467 //perpendicular to the vp border, allow the aligned el to slide on that border,
8468 //otherwise swap the aligned el to the opposite border of the target.
8469 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8470 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8471 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8472 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8475 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8476 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8478 if((x+w) > dw + scrollX){
8479 x = swapX ? r.left-w : dw+scrollX-w;
8482 x = swapX ? r.right : scrollX;
8484 if((y+h) > dh + scrollY){
8485 y = swapY ? r.top-h : dh+scrollY-h;
8488 y = swapY ? r.bottom : scrollY;
8495 getConstrainToXY : function(){
8496 var os = {top:0, left:0, bottom:0, right: 0};
8498 return function(el, local, offsets, proposedXY){
8500 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8502 var vw, vh, vx = 0, vy = 0;
8503 if(el.dom == document.body || el.dom == document){
8504 vw = Roo.lib.Dom.getViewWidth();
8505 vh = Roo.lib.Dom.getViewHeight();
8507 vw = el.dom.clientWidth;
8508 vh = el.dom.clientHeight;
8510 var vxy = el.getXY();
8516 var s = el.getScroll();
8518 vx += offsets.left + s.left;
8519 vy += offsets.top + s.top;
8521 vw -= offsets.right;
8522 vh -= offsets.bottom;
8527 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8528 var x = xy[0], y = xy[1];
8529 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8531 // only move it if it needs it
8534 // first validate right/bottom
8543 // then make sure top/left isn't negative
8552 return moved ? [x, y] : false;
8557 adjustForConstraints : function(xy, parent, offsets){
8558 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8562 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8563 * document it aligns it to the viewport.
8564 * The position parameter is optional, and can be specified in any one of the following formats:
8566 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8567 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8568 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8569 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8570 * <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
8571 * element's anchor point, and the second value is used as the target's anchor point.</li>
8573 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8574 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8575 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8576 * that specified in order to enforce the viewport constraints.
8577 * Following are all of the supported anchor positions:
8580 ----- -----------------------------
8581 tl The top left corner (default)
8582 t The center of the top edge
8583 tr The top right corner
8584 l The center of the left edge
8585 c In the center of the element
8586 r The center of the right edge
8587 bl The bottom left corner
8588 b The center of the bottom edge
8589 br The bottom right corner
8593 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8594 el.alignTo("other-el");
8596 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8597 el.alignTo("other-el", "tr?");
8599 // align the bottom right corner of el with the center left edge of other-el
8600 el.alignTo("other-el", "br-l?");
8602 // align the center of el with the bottom left corner of other-el and
8603 // adjust the x position by -6 pixels (and the y position by 0)
8604 el.alignTo("other-el", "c-bl", [-6, 0]);
8606 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8607 * @param {String} position The position to align to.
8608 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8609 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8610 * @return {Roo.Element} this
8612 alignTo : function(element, position, offsets, animate){
8613 var xy = this.getAlignToXY(element, position, offsets);
8614 this.setXY(xy, this.preanim(arguments, 3));
8619 * Anchors an element to another element and realigns it when the window is resized.
8620 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8621 * @param {String} position The position to align to.
8622 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8623 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8624 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8625 * is a number, it is used as the buffer delay (defaults to 50ms).
8626 * @param {Function} callback The function to call after the animation finishes
8627 * @return {Roo.Element} this
8629 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8630 var action = function(){
8631 this.alignTo(el, alignment, offsets, animate);
8632 Roo.callback(callback, this);
8634 Roo.EventManager.onWindowResize(action, this);
8635 var tm = typeof monitorScroll;
8636 if(tm != 'undefined'){
8637 Roo.EventManager.on(window, 'scroll', action, this,
8638 {buffer: tm == 'number' ? monitorScroll : 50});
8640 action.call(this); // align immediately
8644 * Clears any opacity settings from this element. Required in some cases for IE.
8645 * @return {Roo.Element} this
8647 clearOpacity : function(){
8648 if (window.ActiveXObject) {
8649 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8650 this.dom.style.filter = "";
8653 this.dom.style.opacity = "";
8654 this.dom.style["-moz-opacity"] = "";
8655 this.dom.style["-khtml-opacity"] = "";
8661 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8662 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8663 * @return {Roo.Element} this
8665 hide : function(animate){
8666 this.setVisible(false, this.preanim(arguments, 0));
8671 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8672 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8673 * @return {Roo.Element} this
8675 show : function(animate){
8676 this.setVisible(true, this.preanim(arguments, 0));
8681 * @private Test if size has a unit, otherwise appends the default
8683 addUnits : function(size){
8684 return Roo.Element.addUnits(size, this.defaultUnit);
8688 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8689 * @return {Roo.Element} this
8691 beginMeasure : function(){
8693 if(el.offsetWidth || el.offsetHeight){
8694 return this; // offsets work already
8697 var p = this.dom, b = document.body; // start with this element
8698 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8699 var pe = Roo.get(p);
8700 if(pe.getStyle('display') == 'none'){
8701 changed.push({el: p, visibility: pe.getStyle("visibility")});
8702 p.style.visibility = "hidden";
8703 p.style.display = "block";
8707 this._measureChanged = changed;
8713 * Restores displays to before beginMeasure was called
8714 * @return {Roo.Element} this
8716 endMeasure : function(){
8717 var changed = this._measureChanged;
8719 for(var i = 0, len = changed.length; i < len; i++) {
8721 r.el.style.visibility = r.visibility;
8722 r.el.style.display = "none";
8724 this._measureChanged = null;
8730 * Update the innerHTML of this element, optionally searching for and processing scripts
8731 * @param {String} html The new HTML
8732 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8733 * @param {Function} callback For async script loading you can be noticed when the update completes
8734 * @return {Roo.Element} this
8736 update : function(html, loadScripts, callback){
8737 if(typeof html == "undefined"){
8740 if(loadScripts !== true){
8741 this.dom.innerHTML = html;
8742 if(typeof callback == "function"){
8750 html += '<span id="' + id + '"></span>';
8752 E.onAvailable(id, function(){
8753 var hd = document.getElementsByTagName("head")[0];
8754 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8755 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8756 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8759 while(match = re.exec(html)){
8760 var attrs = match[1];
8761 var srcMatch = attrs ? attrs.match(srcRe) : false;
8762 if(srcMatch && srcMatch[2]){
8763 var s = document.createElement("script");
8764 s.src = srcMatch[2];
8765 var typeMatch = attrs.match(typeRe);
8766 if(typeMatch && typeMatch[2]){
8767 s.type = typeMatch[2];
8770 }else if(match[2] && match[2].length > 0){
8771 if(window.execScript) {
8772 window.execScript(match[2]);
8780 window.eval(match[2]);
8784 var el = document.getElementById(id);
8785 if(el){el.parentNode.removeChild(el);}
8786 if(typeof callback == "function"){
8790 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8795 * Direct access to the UpdateManager update() method (takes the same parameters).
8796 * @param {String/Function} url The url for this request or a function to call to get the url
8797 * @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}
8798 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8799 * @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.
8800 * @return {Roo.Element} this
8803 var um = this.getUpdateManager();
8804 um.update.apply(um, arguments);
8809 * Gets this element's UpdateManager
8810 * @return {Roo.UpdateManager} The UpdateManager
8812 getUpdateManager : function(){
8813 if(!this.updateManager){
8814 this.updateManager = new Roo.UpdateManager(this);
8816 return this.updateManager;
8820 * Disables text selection for this element (normalized across browsers)
8821 * @return {Roo.Element} this
8823 unselectable : function(){
8824 this.dom.unselectable = "on";
8825 this.swallowEvent("selectstart", true);
8826 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8827 this.addClass("x-unselectable");
8832 * Calculates the x, y to center this element on the screen
8833 * @return {Array} The x, y values [x, y]
8835 getCenterXY : function(){
8836 return this.getAlignToXY(document, 'c-c');
8840 * Centers the Element in either the viewport, or another Element.
8841 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8843 center : function(centerIn){
8844 this.alignTo(centerIn || document, 'c-c');
8849 * Tests various css rules/browsers to determine if this element uses a border box
8852 isBorderBox : function(){
8853 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8857 * Return a box {x, y, width, height} that can be used to set another elements
8858 * size/location to match this element.
8859 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8860 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8861 * @return {Object} box An object in the format {x, y, width, height}
8863 getBox : function(contentBox, local){
8868 var left = parseInt(this.getStyle("left"), 10) || 0;
8869 var top = parseInt(this.getStyle("top"), 10) || 0;
8872 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8874 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8876 var l = this.getBorderWidth("l")+this.getPadding("l");
8877 var r = this.getBorderWidth("r")+this.getPadding("r");
8878 var t = this.getBorderWidth("t")+this.getPadding("t");
8879 var b = this.getBorderWidth("b")+this.getPadding("b");
8880 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)};
8882 bx.right = bx.x + bx.width;
8883 bx.bottom = bx.y + bx.height;
8888 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8889 for more information about the sides.
8890 * @param {String} sides
8893 getFrameWidth : function(sides, onlyContentBox){
8894 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8898 * 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.
8899 * @param {Object} box The box to fill {x, y, width, height}
8900 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8901 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8902 * @return {Roo.Element} this
8904 setBox : function(box, adjust, animate){
8905 var w = box.width, h = box.height;
8906 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8907 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8908 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8910 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8915 * Forces the browser to repaint this element
8916 * @return {Roo.Element} this
8918 repaint : function(){
8920 this.addClass("x-repaint");
8921 setTimeout(function(){
8922 Roo.get(dom).removeClass("x-repaint");
8928 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8929 * then it returns the calculated width of the sides (see getPadding)
8930 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8931 * @return {Object/Number}
8933 getMargins : function(side){
8936 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8937 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8938 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8939 right: parseInt(this.getStyle("margin-right"), 10) || 0
8942 return this.addStyles(side, El.margins);
8947 addStyles : function(sides, styles){
8949 for(var i = 0, len = sides.length; i < len; i++){
8950 v = this.getStyle(styles[sides.charAt(i)]);
8952 w = parseInt(v, 10);
8960 * Creates a proxy element of this element
8961 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8962 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8963 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8964 * @return {Roo.Element} The new proxy element
8966 createProxy : function(config, renderTo, matchBox){
8968 renderTo = Roo.getDom(renderTo);
8970 renderTo = document.body;
8972 config = typeof config == "object" ?
8973 config : {tag : "div", cls: config};
8974 var proxy = Roo.DomHelper.append(renderTo, config, true);
8976 proxy.setBox(this.getBox());
8982 * Puts a mask over this element to disable user interaction. Requires core.css.
8983 * This method can only be applied to elements which accept child nodes.
8984 * @param {String} msg (optional) A message to display in the mask
8985 * @param {String} msgCls (optional) A css class to apply to the msg element
8986 * @return {Element} The mask element
8988 mask : function(msg, msgCls)
8990 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8991 this.setStyle("position", "relative");
8994 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8996 this.addClass("x-masked");
8997 this._mask.setDisplayed(true);
9002 while (dom && dom.style) {
9003 if (!isNaN(parseInt(dom.style.zIndex))) {
9004 z = Math.max(z, parseInt(dom.style.zIndex));
9006 dom = dom.parentNode;
9008 // if we are masking the body - then it hides everything..
9009 if (this.dom == document.body) {
9011 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9012 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9015 if(typeof msg == 'string'){
9017 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9019 var mm = this._maskMsg;
9020 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9021 if (mm.dom.firstChild) { // weird IE issue?
9022 mm.dom.firstChild.innerHTML = msg;
9024 mm.setDisplayed(true);
9026 mm.setStyle('z-index', z + 102);
9028 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9029 this._mask.setHeight(this.getHeight());
9031 this._mask.setStyle('z-index', z + 100);
9037 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9038 * it is cached for reuse.
9040 unmask : function(removeEl){
9042 if(removeEl === true){
9043 this._mask.remove();
9046 this._maskMsg.remove();
9047 delete this._maskMsg;
9050 this._mask.setDisplayed(false);
9052 this._maskMsg.setDisplayed(false);
9056 this.removeClass("x-masked");
9060 * Returns true if this element is masked
9063 isMasked : function(){
9064 return this._mask && this._mask.isVisible();
9068 * Creates an iframe shim for this element to keep selects and other windowed objects from
9070 * @return {Roo.Element} The new shim element
9072 createShim : function(){
9073 var el = document.createElement('iframe');
9074 el.frameBorder = 'no';
9075 el.className = 'roo-shim';
9076 if(Roo.isIE && Roo.isSecure){
9077 el.src = Roo.SSL_SECURE_URL;
9079 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9080 shim.autoBoxAdjust = false;
9085 * Removes this element from the DOM and deletes it from the cache
9087 remove : function(){
9088 if(this.dom.parentNode){
9089 this.dom.parentNode.removeChild(this.dom);
9091 delete El.cache[this.dom.id];
9095 * Sets up event handlers to add and remove a css class when the mouse is over this element
9096 * @param {String} className
9097 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9098 * mouseout events for children elements
9099 * @return {Roo.Element} this
9101 addClassOnOver : function(className, preventFlicker){
9102 this.on("mouseover", function(){
9103 Roo.fly(this, '_internal').addClass(className);
9105 var removeFn = function(e){
9106 if(preventFlicker !== true || !e.within(this, true)){
9107 Roo.fly(this, '_internal').removeClass(className);
9110 this.on("mouseout", removeFn, this.dom);
9115 * Sets up event handlers to add and remove a css class when this element has the focus
9116 * @param {String} className
9117 * @return {Roo.Element} this
9119 addClassOnFocus : function(className){
9120 this.on("focus", function(){
9121 Roo.fly(this, '_internal').addClass(className);
9123 this.on("blur", function(){
9124 Roo.fly(this, '_internal').removeClass(className);
9129 * 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)
9130 * @param {String} className
9131 * @return {Roo.Element} this
9133 addClassOnClick : function(className){
9135 this.on("mousedown", function(){
9136 Roo.fly(dom, '_internal').addClass(className);
9137 var d = Roo.get(document);
9138 var fn = function(){
9139 Roo.fly(dom, '_internal').removeClass(className);
9140 d.removeListener("mouseup", fn);
9142 d.on("mouseup", fn);
9148 * Stops the specified event from bubbling and optionally prevents the default action
9149 * @param {String} eventName
9150 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9151 * @return {Roo.Element} this
9153 swallowEvent : function(eventName, preventDefault){
9154 var fn = function(e){
9155 e.stopPropagation();
9160 if(eventName instanceof Array){
9161 for(var i = 0, len = eventName.length; i < len; i++){
9162 this.on(eventName[i], fn);
9166 this.on(eventName, fn);
9173 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9176 * Sizes this element to its parent element's dimensions performing
9177 * neccessary box adjustments.
9178 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9179 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9180 * @return {Roo.Element} this
9182 fitToParent : function(monitorResize, targetParent) {
9183 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9184 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9185 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9188 var p = Roo.get(targetParent || this.dom.parentNode);
9189 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9190 if (monitorResize === true) {
9191 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9192 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9198 * Gets the next sibling, skipping text nodes
9199 * @return {HTMLElement} The next sibling or null
9201 getNextSibling : function(){
9202 var n = this.dom.nextSibling;
9203 while(n && n.nodeType != 1){
9210 * Gets the previous sibling, skipping text nodes
9211 * @return {HTMLElement} The previous sibling or null
9213 getPrevSibling : function(){
9214 var n = this.dom.previousSibling;
9215 while(n && n.nodeType != 1){
9216 n = n.previousSibling;
9223 * Appends the passed element(s) to this element
9224 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9225 * @return {Roo.Element} this
9227 appendChild: function(el){
9234 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9235 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9236 * automatically generated with the specified attributes.
9237 * @param {HTMLElement} insertBefore (optional) a child element of this element
9238 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9239 * @return {Roo.Element} The new child element
9241 createChild: function(config, insertBefore, returnDom){
9242 config = config || {tag:'div'};
9244 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9246 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9250 * Appends this element to the passed element
9251 * @param {String/HTMLElement/Element} el The new parent element
9252 * @return {Roo.Element} this
9254 appendTo: function(el){
9255 el = Roo.getDom(el);
9256 el.appendChild(this.dom);
9261 * Inserts this element before the passed element in the DOM
9262 * @param {String/HTMLElement/Element} el The element to insert before
9263 * @return {Roo.Element} this
9265 insertBefore: function(el){
9266 el = Roo.getDom(el);
9267 el.parentNode.insertBefore(this.dom, el);
9272 * Inserts this element after the passed element in the DOM
9273 * @param {String/HTMLElement/Element} el The element to insert after
9274 * @return {Roo.Element} this
9276 insertAfter: function(el){
9277 el = Roo.getDom(el);
9278 el.parentNode.insertBefore(this.dom, el.nextSibling);
9283 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9284 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9285 * @return {Roo.Element} The new child
9287 insertFirst: function(el, returnDom){
9289 if(typeof el == 'object' && !el.nodeType){ // dh config
9290 return this.createChild(el, this.dom.firstChild, returnDom);
9292 el = Roo.getDom(el);
9293 this.dom.insertBefore(el, this.dom.firstChild);
9294 return !returnDom ? Roo.get(el) : el;
9299 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9300 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9301 * @param {String} where (optional) 'before' or 'after' defaults to before
9302 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9303 * @return {Roo.Element} the inserted Element
9305 insertSibling: function(el, where, returnDom){
9306 where = where ? where.toLowerCase() : 'before';
9308 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9310 if(typeof el == 'object' && !el.nodeType){ // dh config
9311 if(where == 'after' && !this.dom.nextSibling){
9312 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9314 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9318 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9319 where == 'before' ? this.dom : this.dom.nextSibling);
9328 * Creates and wraps this element with another element
9329 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9330 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9331 * @return {HTMLElement/Element} The newly created wrapper element
9333 wrap: function(config, returnDom){
9335 config = {tag: "div"};
9337 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9338 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9343 * Replaces the passed element with this element
9344 * @param {String/HTMLElement/Element} el The element to replace
9345 * @return {Roo.Element} this
9347 replace: function(el){
9349 this.insertBefore(el);
9355 * Inserts an html fragment into this element
9356 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9357 * @param {String} html The HTML fragment
9358 * @param {Boolean} returnEl True to return an Roo.Element
9359 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9361 insertHtml : function(where, html, returnEl){
9362 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9363 return returnEl ? Roo.get(el) : el;
9367 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9368 * @param {Object} o The object with the attributes
9369 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9370 * @return {Roo.Element} this
9372 set : function(o, useSet){
9374 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9376 if(attr == "style" || typeof o[attr] == "function") continue;
9378 el.className = o["cls"];
9380 if(useSet) el.setAttribute(attr, o[attr]);
9381 else el[attr] = o[attr];
9385 Roo.DomHelper.applyStyles(el, o.style);
9391 * Convenience method for constructing a KeyMap
9392 * @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:
9393 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9394 * @param {Function} fn The function to call
9395 * @param {Object} scope (optional) The scope of the function
9396 * @return {Roo.KeyMap} The KeyMap created
9398 addKeyListener : function(key, fn, scope){
9400 if(typeof key != "object" || key instanceof Array){
9416 return new Roo.KeyMap(this, config);
9420 * Creates a KeyMap for this element
9421 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9422 * @return {Roo.KeyMap} The KeyMap created
9424 addKeyMap : function(config){
9425 return new Roo.KeyMap(this, config);
9429 * Returns true if this element is scrollable.
9432 isScrollable : function(){
9434 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9438 * 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().
9439 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9440 * @param {Number} value The new scroll value
9441 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9442 * @return {Element} this
9445 scrollTo : function(side, value, animate){
9446 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9448 this.dom[prop] = value;
9450 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9451 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9457 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9458 * within this element's scrollable range.
9459 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9460 * @param {Number} distance How far to scroll the element in pixels
9461 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9462 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9463 * was scrolled as far as it could go.
9465 scroll : function(direction, distance, animate){
9466 if(!this.isScrollable()){
9470 var l = el.scrollLeft, t = el.scrollTop;
9471 var w = el.scrollWidth, h = el.scrollHeight;
9472 var cw = el.clientWidth, ch = el.clientHeight;
9473 direction = direction.toLowerCase();
9474 var scrolled = false;
9475 var a = this.preanim(arguments, 2);
9480 var v = Math.min(l + distance, w-cw);
9481 this.scrollTo("left", v, a);
9488 var v = Math.max(l - distance, 0);
9489 this.scrollTo("left", v, a);
9497 var v = Math.max(t - distance, 0);
9498 this.scrollTo("top", v, a);
9506 var v = Math.min(t + distance, h-ch);
9507 this.scrollTo("top", v, a);
9516 * Translates the passed page coordinates into left/top css values for this element
9517 * @param {Number/Array} x The page x or an array containing [x, y]
9518 * @param {Number} y The page y
9519 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9521 translatePoints : function(x, y){
9522 if(typeof x == 'object' || x instanceof Array){
9525 var p = this.getStyle('position');
9526 var o = this.getXY();
9528 var l = parseInt(this.getStyle('left'), 10);
9529 var t = parseInt(this.getStyle('top'), 10);
9532 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9535 t = (p == "relative") ? 0 : this.dom.offsetTop;
9538 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9542 * Returns the current scroll position of the element.
9543 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9545 getScroll : function(){
9546 var d = this.dom, doc = document;
9547 if(d == doc || d == doc.body){
9548 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9549 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9550 return {left: l, top: t};
9552 return {left: d.scrollLeft, top: d.scrollTop};
9557 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9558 * are convert to standard 6 digit hex color.
9559 * @param {String} attr The css attribute
9560 * @param {String} defaultValue The default value to use when a valid color isn't found
9561 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9564 getColor : function(attr, defaultValue, prefix){
9565 var v = this.getStyle(attr);
9566 if(!v || v == "transparent" || v == "inherit") {
9567 return defaultValue;
9569 var color = typeof prefix == "undefined" ? "#" : prefix;
9570 if(v.substr(0, 4) == "rgb("){
9571 var rvs = v.slice(4, v.length -1).split(",");
9572 for(var i = 0; i < 3; i++){
9573 var h = parseInt(rvs[i]).toString(16);
9580 if(v.substr(0, 1) == "#"){
9582 for(var i = 1; i < 4; i++){
9583 var c = v.charAt(i);
9586 }else if(v.length == 7){
9587 color += v.substr(1);
9591 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9595 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9596 * gradient background, rounded corners and a 4-way shadow.
9597 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9598 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9599 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9600 * @return {Roo.Element} this
9602 boxWrap : function(cls){
9603 cls = cls || 'x-box';
9604 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9605 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9610 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9611 * @param {String} namespace The namespace in which to look for the attribute
9612 * @param {String} name The attribute name
9613 * @return {String} The attribute value
9615 getAttributeNS : Roo.isIE ? function(ns, name){
9617 var type = typeof d[ns+":"+name];
9618 if(type != 'undefined' && type != 'unknown'){
9619 return d[ns+":"+name];
9622 } : function(ns, name){
9624 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9629 * Sets or Returns the value the dom attribute value
9630 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9631 * @param {String} value (optional) The value to set the attribute to
9632 * @return {String} The attribute value
9634 attr : function(name){
9635 if (arguments.length > 1) {
9636 this.dom.setAttribute(name, arguments[1]);
9637 return arguments[1];
9639 if (typeof(name) == 'object') {
9640 for(var i in name) {
9641 this.attr(i, name[i]);
9647 if (!this.dom.hasAttribute(name)) {
9650 return this.dom.getAttribute(name);
9657 var ep = El.prototype;
9660 * Appends an event handler (Shorthand for addListener)
9661 * @param {String} eventName The type of event to append
9662 * @param {Function} fn The method the event invokes
9663 * @param {Object} scope (optional) The scope (this object) of the fn
9664 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9667 ep.on = ep.addListener;
9669 ep.mon = ep.addListener;
9672 * Removes an event handler from this element (shorthand for removeListener)
9673 * @param {String} eventName the type of event to remove
9674 * @param {Function} fn the method the event invokes
9675 * @return {Roo.Element} this
9678 ep.un = ep.removeListener;
9681 * true to automatically adjust width and height settings for box-model issues (default to true)
9683 ep.autoBoxAdjust = true;
9686 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9689 El.addUnits = function(v, defaultUnit){
9690 if(v === "" || v == "auto"){
9693 if(v === undefined){
9696 if(typeof v == "number" || !El.unitPattern.test(v)){
9697 return v + (defaultUnit || 'px');
9702 // special markup used throughout Roo when box wrapping elements
9703 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>';
9705 * Visibility mode constant - Use visibility to hide element
9711 * Visibility mode constant - Use display to hide element
9717 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9718 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9719 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9731 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9732 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9733 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9734 * @return {Element} The Element object
9737 El.get = function(el){
9739 if(!el){ return null; }
9740 if(typeof el == "string"){ // element id
9741 if(!(elm = document.getElementById(el))){
9744 if(ex = El.cache[el]){
9747 ex = El.cache[el] = new El(elm);
9750 }else if(el.tagName){ // dom element
9754 if(ex = El.cache[id]){
9757 ex = El.cache[id] = new El(el);
9760 }else if(el instanceof El){
9762 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9763 // catch case where it hasn't been appended
9764 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9767 }else if(el.isComposite){
9769 }else if(el instanceof Array){
9770 return El.select(el);
9771 }else if(el == document){
9772 // create a bogus element object representing the document object
9774 var f = function(){};
9775 f.prototype = El.prototype;
9777 docEl.dom = document;
9785 El.uncache = function(el){
9786 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9788 delete El.cache[a[i].id || a[i]];
9794 // Garbage collection - uncache elements/purge listeners on orphaned elements
9795 // so we don't hold a reference and cause the browser to retain them
9796 El.garbageCollect = function(){
9797 if(!Roo.enableGarbageCollector){
9798 clearInterval(El.collectorThread);
9801 for(var eid in El.cache){
9802 var el = El.cache[eid], d = el.dom;
9803 // -------------------------------------------------------
9804 // Determining what is garbage:
9805 // -------------------------------------------------------
9807 // dom node is null, definitely garbage
9808 // -------------------------------------------------------
9810 // no parentNode == direct orphan, definitely garbage
9811 // -------------------------------------------------------
9812 // !d.offsetParent && !document.getElementById(eid)
9813 // display none elements have no offsetParent so we will
9814 // also try to look it up by it's id. However, check
9815 // offsetParent first so we don't do unneeded lookups.
9816 // This enables collection of elements that are not orphans
9817 // directly, but somewhere up the line they have an orphan
9819 // -------------------------------------------------------
9820 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9821 delete El.cache[eid];
9822 if(d && Roo.enableListenerCollection){
9828 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9832 El.Flyweight = function(dom){
9835 El.Flyweight.prototype = El.prototype;
9837 El._flyweights = {};
9839 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9840 * the dom node can be overwritten by other code.
9841 * @param {String/HTMLElement} el The dom node or id
9842 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9843 * prevent conflicts (e.g. internally Roo uses "_internal")
9845 * @return {Element} The shared Element object
9847 El.fly = function(el, named){
9848 named = named || '_global';
9849 el = Roo.getDom(el);
9853 if(!El._flyweights[named]){
9854 El._flyweights[named] = new El.Flyweight();
9856 El._flyweights[named].dom = el;
9857 return El._flyweights[named];
9861 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9862 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9863 * Shorthand of {@link Roo.Element#get}
9864 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9865 * @return {Element} The Element object
9871 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9872 * the dom node can be overwritten by other code.
9873 * Shorthand of {@link Roo.Element#fly}
9874 * @param {String/HTMLElement} el The dom node or id
9875 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9876 * prevent conflicts (e.g. internally Roo uses "_internal")
9878 * @return {Element} The shared Element object
9884 // speedy lookup for elements never to box adjust
9885 var noBoxAdjust = Roo.isStrict ? {
9888 input:1, select:1, textarea:1
9890 if(Roo.isIE || Roo.isGecko){
9891 noBoxAdjust['button'] = 1;
9895 Roo.EventManager.on(window, 'unload', function(){
9897 delete El._flyweights;
9905 Roo.Element.selectorFunction = Roo.DomQuery.select;
9908 Roo.Element.select = function(selector, unique, root){
9910 if(typeof selector == "string"){
9911 els = Roo.Element.selectorFunction(selector, root);
9912 }else if(selector.length !== undefined){
9915 throw "Invalid selector";
9917 if(unique === true){
9918 return new Roo.CompositeElement(els);
9920 return new Roo.CompositeElementLite(els);
9924 * Selects elements based on the passed CSS selector to enable working on them as 1.
9925 * @param {String/Array} selector The CSS selector or an array of elements
9926 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9927 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9928 * @return {CompositeElementLite/CompositeElement}
9932 Roo.select = Roo.Element.select;
9949 * Ext JS Library 1.1.1
9950 * Copyright(c) 2006-2007, Ext JS, LLC.
9952 * Originally Released Under LGPL - original licence link has changed is not relivant.
9955 * <script type="text/javascript">
9960 //Notifies Element that fx methods are available
9961 Roo.enableFx = true;
9965 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9966 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9967 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9968 * Element effects to work.</p><br/>
9970 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9971 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9972 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9973 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9974 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9975 * expected results and should be done with care.</p><br/>
9977 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9978 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9981 ----- -----------------------------
9982 tl The top left corner
9983 t The center of the top edge
9984 tr The top right corner
9985 l The center of the left edge
9986 r The center of the right edge
9987 bl The bottom left corner
9988 b The center of the bottom edge
9989 br The bottom right corner
9991 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9992 * below are common options that can be passed to any Fx method.</b>
9993 * @cfg {Function} callback A function called when the effect is finished
9994 * @cfg {Object} scope The scope of the effect function
9995 * @cfg {String} easing A valid Easing value for the effect
9996 * @cfg {String} afterCls A css class to apply after the effect
9997 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9998 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9999 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10000 * effects that end with the element being visually hidden, ignored otherwise)
10001 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10002 * a function which returns such a specification that will be applied to the Element after the effect finishes
10003 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10004 * @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
10005 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10009 * Slides the element into view. An anchor point can be optionally passed to set the point of
10010 * origin for the slide effect. This function automatically handles wrapping the element with
10011 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10014 // default: slide the element in from the top
10017 // custom: slide the element in from the right with a 2-second duration
10018 el.slideIn('r', { duration: 2 });
10020 // common config options shown with default values
10026 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10027 * @param {Object} options (optional) Object literal with any of the Fx config options
10028 * @return {Roo.Element} The Element
10030 slideIn : function(anchor, o){
10031 var el = this.getFxEl();
10034 el.queueFx(o, function(){
10036 anchor = anchor || "t";
10038 // fix display to visibility
10041 // restore values after effect
10042 var r = this.getFxRestore();
10043 var b = this.getBox();
10044 // fixed size for slide
10048 var wrap = this.fxWrap(r.pos, o, "hidden");
10050 var st = this.dom.style;
10051 st.visibility = "visible";
10052 st.position = "absolute";
10054 // clear out temp styles after slide and unwrap
10055 var after = function(){
10056 el.fxUnwrap(wrap, r.pos, o);
10057 st.width = r.width;
10058 st.height = r.height;
10061 // time to calc the positions
10062 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10064 switch(anchor.toLowerCase()){
10066 wrap.setSize(b.width, 0);
10067 st.left = st.bottom = "0";
10071 wrap.setSize(0, b.height);
10072 st.right = st.top = "0";
10076 wrap.setSize(0, b.height);
10077 wrap.setX(b.right);
10078 st.left = st.top = "0";
10079 a = {width: bw, points: pt};
10082 wrap.setSize(b.width, 0);
10083 wrap.setY(b.bottom);
10084 st.left = st.top = "0";
10085 a = {height: bh, points: pt};
10088 wrap.setSize(0, 0);
10089 st.right = st.bottom = "0";
10090 a = {width: bw, height: bh};
10093 wrap.setSize(0, 0);
10094 wrap.setY(b.y+b.height);
10095 st.right = st.top = "0";
10096 a = {width: bw, height: bh, points: pt};
10099 wrap.setSize(0, 0);
10100 wrap.setXY([b.right, b.bottom]);
10101 st.left = st.top = "0";
10102 a = {width: bw, height: bh, points: pt};
10105 wrap.setSize(0, 0);
10106 wrap.setX(b.x+b.width);
10107 st.left = st.bottom = "0";
10108 a = {width: bw, height: bh, points: pt};
10111 this.dom.style.visibility = "visible";
10114 arguments.callee.anim = wrap.fxanim(a,
10124 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10125 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10126 * 'hidden') but block elements will still take up space in the document. The element must be removed
10127 * from the DOM using the 'remove' config option if desired. This function automatically handles
10128 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10131 // default: slide the element out to the top
10134 // custom: slide the element out to the right with a 2-second duration
10135 el.slideOut('r', { duration: 2 });
10137 // common config options shown with default values
10145 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10146 * @param {Object} options (optional) Object literal with any of the Fx config options
10147 * @return {Roo.Element} The Element
10149 slideOut : function(anchor, o){
10150 var el = this.getFxEl();
10153 el.queueFx(o, function(){
10155 anchor = anchor || "t";
10157 // restore values after effect
10158 var r = this.getFxRestore();
10160 var b = this.getBox();
10161 // fixed size for slide
10165 var wrap = this.fxWrap(r.pos, o, "visible");
10167 var st = this.dom.style;
10168 st.visibility = "visible";
10169 st.position = "absolute";
10173 var after = function(){
10175 el.setDisplayed(false);
10180 el.fxUnwrap(wrap, r.pos, o);
10182 st.width = r.width;
10183 st.height = r.height;
10188 var a, zero = {to: 0};
10189 switch(anchor.toLowerCase()){
10191 st.left = st.bottom = "0";
10192 a = {height: zero};
10195 st.right = st.top = "0";
10199 st.left = st.top = "0";
10200 a = {width: zero, points: {to:[b.right, b.y]}};
10203 st.left = st.top = "0";
10204 a = {height: zero, points: {to:[b.x, b.bottom]}};
10207 st.right = st.bottom = "0";
10208 a = {width: zero, height: zero};
10211 st.right = st.top = "0";
10212 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10215 st.left = st.top = "0";
10216 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10219 st.left = st.bottom = "0";
10220 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10224 arguments.callee.anim = wrap.fxanim(a,
10234 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10235 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10236 * The element must be removed from the DOM using the 'remove' config option if desired.
10242 // common config options shown with default values
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 puff : function(o){
10254 var el = this.getFxEl();
10257 el.queueFx(o, function(){
10258 this.clearOpacity();
10261 // restore values after effect
10262 var r = this.getFxRestore();
10263 var st = this.dom.style;
10265 var after = function(){
10267 el.setDisplayed(false);
10274 el.setPositioning(r.pos);
10275 st.width = r.width;
10276 st.height = r.height;
10281 var width = this.getWidth();
10282 var height = this.getHeight();
10284 arguments.callee.anim = this.fxanim({
10285 width : {to: this.adjustWidth(width * 2)},
10286 height : {to: this.adjustHeight(height * 2)},
10287 points : {by: [-(width * .5), -(height * .5)]},
10289 fontSize: {to:200, unit: "%"}
10300 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10301 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10302 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10308 // all config options shown with default values
10316 * @param {Object} options (optional) Object literal with any of the Fx config options
10317 * @return {Roo.Element} The Element
10319 switchOff : function(o){
10320 var el = this.getFxEl();
10323 el.queueFx(o, function(){
10324 this.clearOpacity();
10327 // restore values after effect
10328 var r = this.getFxRestore();
10329 var st = this.dom.style;
10331 var after = function(){
10333 el.setDisplayed(false);
10339 el.setPositioning(r.pos);
10340 st.width = r.width;
10341 st.height = r.height;
10346 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10347 this.clearOpacity();
10351 points:{by:[0, this.getHeight() * .5]}
10352 }, o, 'motion', 0.3, 'easeIn', after);
10353 }).defer(100, this);
10360 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10361 * changed using the "attr" config option) and then fading back to the original color. If no original
10362 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10365 // default: highlight background to yellow
10368 // custom: highlight foreground text to blue for 2 seconds
10369 el.highlight("0000ff", { attr: 'color', duration: 2 });
10371 // common config options shown with default values
10372 el.highlight("ffff9c", {
10373 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10374 endColor: (current color) or "ffffff",
10379 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10380 * @param {Object} options (optional) Object literal with any of the Fx config options
10381 * @return {Roo.Element} The Element
10383 highlight : function(color, o){
10384 var el = this.getFxEl();
10387 el.queueFx(o, function(){
10388 color = color || "ffff9c";
10389 attr = o.attr || "backgroundColor";
10391 this.clearOpacity();
10394 var origColor = this.getColor(attr);
10395 var restoreColor = this.dom.style[attr];
10396 endColor = (o.endColor || origColor) || "ffffff";
10398 var after = function(){
10399 el.dom.style[attr] = restoreColor;
10404 a[attr] = {from: color, to: endColor};
10405 arguments.callee.anim = this.fxanim(a,
10415 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10418 // default: a single light blue ripple
10421 // custom: 3 red ripples lasting 3 seconds total
10422 el.frame("ff0000", 3, { duration: 3 });
10424 // common config options shown with default values
10425 el.frame("C3DAF9", 1, {
10426 duration: 1 //duration of entire animation (not each individual ripple)
10427 // Note: Easing is not configurable and will be ignored if included
10430 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10431 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10432 * @param {Object} options (optional) Object literal with any of the Fx config options
10433 * @return {Roo.Element} The Element
10435 frame : function(color, count, o){
10436 var el = this.getFxEl();
10439 el.queueFx(o, function(){
10440 color = color || "#C3DAF9";
10441 if(color.length == 6){
10442 color = "#" + color;
10444 count = count || 1;
10445 duration = o.duration || 1;
10448 var b = this.getBox();
10449 var animFn = function(){
10450 var proxy = this.createProxy({
10453 visbility:"hidden",
10454 position:"absolute",
10455 "z-index":"35000", // yee haw
10456 border:"0px solid " + color
10459 var scale = Roo.isBorderBox ? 2 : 1;
10461 top:{from:b.y, to:b.y - 20},
10462 left:{from:b.x, to:b.x - 20},
10463 borderWidth:{from:0, to:10},
10464 opacity:{from:1, to:0},
10465 height:{from:b.height, to:(b.height + (20*scale))},
10466 width:{from:b.width, to:(b.width + (20*scale))}
10467 }, duration, function(){
10471 animFn.defer((duration/2)*1000, this);
10482 * Creates a pause before any subsequent queued effects begin. If there are
10483 * no effects queued after the pause it will have no effect.
10488 * @param {Number} seconds The length of time to pause (in seconds)
10489 * @return {Roo.Element} The Element
10491 pause : function(seconds){
10492 var el = this.getFxEl();
10495 el.queueFx(o, function(){
10496 setTimeout(function(){
10498 }, seconds * 1000);
10504 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10505 * using the "endOpacity" config option.
10508 // default: fade in from opacity 0 to 100%
10511 // custom: fade in from opacity 0 to 75% over 2 seconds
10512 el.fadeIn({ endOpacity: .75, duration: 2});
10514 // common config options shown with default values
10516 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10521 * @param {Object} options (optional) Object literal with any of the Fx config options
10522 * @return {Roo.Element} The Element
10524 fadeIn : function(o){
10525 var el = this.getFxEl();
10527 el.queueFx(o, function(){
10528 this.setOpacity(0);
10530 this.dom.style.visibility = 'visible';
10531 var to = o.endOpacity || 1;
10532 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10533 o, null, .5, "easeOut", function(){
10535 this.clearOpacity();
10544 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10545 * using the "endOpacity" config option.
10548 // default: fade out from the element's current opacity to 0
10551 // custom: fade out from the element's current opacity to 25% over 2 seconds
10552 el.fadeOut({ endOpacity: .25, duration: 2});
10554 // common config options shown with default values
10556 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10563 * @param {Object} options (optional) Object literal with any of the Fx config options
10564 * @return {Roo.Element} The Element
10566 fadeOut : function(o){
10567 var el = this.getFxEl();
10569 el.queueFx(o, function(){
10570 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10571 o, null, .5, "easeOut", function(){
10572 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10573 this.dom.style.display = "none";
10575 this.dom.style.visibility = "hidden";
10577 this.clearOpacity();
10585 * Animates the transition of an element's dimensions from a starting height/width
10586 * to an ending height/width.
10589 // change height and width to 100x100 pixels
10590 el.scale(100, 100);
10592 // common config options shown with default values. The height and width will default to
10593 // the element's existing values if passed as null.
10596 [element's height], {
10601 * @param {Number} width The new width (pass undefined to keep the original width)
10602 * @param {Number} height The new height (pass undefined to keep the original height)
10603 * @param {Object} options (optional) Object literal with any of the Fx config options
10604 * @return {Roo.Element} The Element
10606 scale : function(w, h, o){
10607 this.shift(Roo.apply({}, o, {
10615 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10616 * Any of these properties not specified in the config object will not be changed. This effect
10617 * requires that at least one new dimension, position or opacity setting must be passed in on
10618 * the config object in order for the function to have any effect.
10621 // slide the element horizontally to x position 200 while changing the height and opacity
10622 el.shift({ x: 200, height: 50, opacity: .8 });
10624 // common config options shown with default values.
10626 width: [element's width],
10627 height: [element's height],
10628 x: [element's x position],
10629 y: [element's y position],
10630 opacity: [element's opacity],
10635 * @param {Object} options Object literal with any of the Fx config options
10636 * @return {Roo.Element} The Element
10638 shift : function(o){
10639 var el = this.getFxEl();
10641 el.queueFx(o, function(){
10642 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10643 if(w !== undefined){
10644 a.width = {to: this.adjustWidth(w)};
10646 if(h !== undefined){
10647 a.height = {to: this.adjustHeight(h)};
10649 if(x !== undefined || y !== undefined){
10651 x !== undefined ? x : this.getX(),
10652 y !== undefined ? y : this.getY()
10655 if(op !== undefined){
10656 a.opacity = {to: op};
10658 if(o.xy !== undefined){
10659 a.points = {to: o.xy};
10661 arguments.callee.anim = this.fxanim(a,
10662 o, 'motion', .35, "easeOut", function(){
10670 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10671 * ending point of the effect.
10674 // default: slide the element downward while fading out
10677 // custom: slide the element out to the right with a 2-second duration
10678 el.ghost('r', { duration: 2 });
10680 // common config options shown with default values
10688 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10689 * @param {Object} options (optional) Object literal with any of the Fx config options
10690 * @return {Roo.Element} The Element
10692 ghost : function(anchor, o){
10693 var el = this.getFxEl();
10696 el.queueFx(o, function(){
10697 anchor = anchor || "b";
10699 // restore values after effect
10700 var r = this.getFxRestore();
10701 var w = this.getWidth(),
10702 h = this.getHeight();
10704 var st = this.dom.style;
10706 var after = function(){
10708 el.setDisplayed(false);
10714 el.setPositioning(r.pos);
10715 st.width = r.width;
10716 st.height = r.height;
10721 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10722 switch(anchor.toLowerCase()){
10749 arguments.callee.anim = this.fxanim(a,
10759 * Ensures that all effects queued after syncFx is called on the element are
10760 * run concurrently. This is the opposite of {@link #sequenceFx}.
10761 * @return {Roo.Element} The Element
10763 syncFx : function(){
10764 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10773 * Ensures that all effects queued after sequenceFx is called on the element are
10774 * run in sequence. This is the opposite of {@link #syncFx}.
10775 * @return {Roo.Element} The Element
10777 sequenceFx : function(){
10778 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10780 concurrent : false,
10787 nextFx : function(){
10788 var ef = this.fxQueue[0];
10795 * Returns true if the element has any effects actively running or queued, else returns false.
10796 * @return {Boolean} True if element has active effects, else false
10798 hasActiveFx : function(){
10799 return this.fxQueue && this.fxQueue[0];
10803 * Stops any running effects and clears the element's internal effects queue if it contains
10804 * any additional effects that haven't started yet.
10805 * @return {Roo.Element} The Element
10807 stopFx : function(){
10808 if(this.hasActiveFx()){
10809 var cur = this.fxQueue[0];
10810 if(cur && cur.anim && cur.anim.isAnimated()){
10811 this.fxQueue = [cur]; // clear out others
10812 cur.anim.stop(true);
10819 beforeFx : function(o){
10820 if(this.hasActiveFx() && !o.concurrent){
10831 * Returns true if the element is currently blocking so that no other effect can be queued
10832 * until this effect is finished, else returns false if blocking is not set. This is commonly
10833 * used to ensure that an effect initiated by a user action runs to completion prior to the
10834 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10835 * @return {Boolean} True if blocking, else false
10837 hasFxBlock : function(){
10838 var q = this.fxQueue;
10839 return q && q[0] && q[0].block;
10843 queueFx : function(o, fn){
10847 if(!this.hasFxBlock()){
10848 Roo.applyIf(o, this.fxDefaults);
10850 var run = this.beforeFx(o);
10851 fn.block = o.block;
10852 this.fxQueue.push(fn);
10864 fxWrap : function(pos, o, vis){
10866 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10869 wrapXY = this.getXY();
10871 var div = document.createElement("div");
10872 div.style.visibility = vis;
10873 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10874 wrap.setPositioning(pos);
10875 if(wrap.getStyle("position") == "static"){
10876 wrap.position("relative");
10878 this.clearPositioning('auto');
10880 wrap.dom.appendChild(this.dom);
10882 wrap.setXY(wrapXY);
10889 fxUnwrap : function(wrap, pos, o){
10890 this.clearPositioning();
10891 this.setPositioning(pos);
10893 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10899 getFxRestore : function(){
10900 var st = this.dom.style;
10901 return {pos: this.getPositioning(), width: st.width, height : st.height};
10905 afterFx : function(o){
10907 this.applyStyles(o.afterStyle);
10910 this.addClass(o.afterCls);
10912 if(o.remove === true){
10915 Roo.callback(o.callback, o.scope, [this]);
10917 this.fxQueue.shift();
10923 getFxEl : function(){ // support for composite element fx
10924 return Roo.get(this.dom);
10928 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10929 animType = animType || 'run';
10931 var anim = Roo.lib.Anim[animType](
10933 (opt.duration || defaultDur) || .35,
10934 (opt.easing || defaultEase) || 'easeOut',
10936 Roo.callback(cb, this);
10945 // backwords compat
10946 Roo.Fx.resize = Roo.Fx.scale;
10948 //When included, Roo.Fx is automatically applied to Element so that all basic
10949 //effects are available directly via the Element API
10950 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10952 * Ext JS Library 1.1.1
10953 * Copyright(c) 2006-2007, Ext JS, LLC.
10955 * Originally Released Under LGPL - original licence link has changed is not relivant.
10958 * <script type="text/javascript">
10963 * @class Roo.CompositeElement
10964 * Standard composite class. Creates a Roo.Element for every element in the collection.
10966 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10967 * actions will be performed on all the elements in this collection.</b>
10969 * All methods return <i>this</i> and can be chained.
10971 var els = Roo.select("#some-el div.some-class", true);
10972 // or select directly from an existing element
10973 var el = Roo.get('some-el');
10974 el.select('div.some-class', true);
10976 els.setWidth(100); // all elements become 100 width
10977 els.hide(true); // all elements fade out and hide
10979 els.setWidth(100).hide(true);
10982 Roo.CompositeElement = function(els){
10983 this.elements = [];
10984 this.addElements(els);
10986 Roo.CompositeElement.prototype = {
10988 addElements : function(els){
10989 if(!els) return this;
10990 if(typeof els == "string"){
10991 els = Roo.Element.selectorFunction(els);
10993 var yels = this.elements;
10994 var index = yels.length-1;
10995 for(var i = 0, len = els.length; i < len; i++) {
10996 yels[++index] = Roo.get(els[i]);
11002 * Clears this composite and adds the elements returned by the passed selector.
11003 * @param {String/Array} els A string CSS selector, an array of elements or an element
11004 * @return {CompositeElement} this
11006 fill : function(els){
11007 this.elements = [];
11013 * Filters this composite to only elements that match the passed selector.
11014 * @param {String} selector A string CSS selector
11015 * @param {Boolean} inverse return inverse filter (not matches)
11016 * @return {CompositeElement} this
11018 filter : function(selector, inverse){
11020 inverse = inverse || false;
11021 this.each(function(el){
11022 var match = inverse ? !el.is(selector) : el.is(selector);
11024 els[els.length] = el.dom;
11031 invoke : function(fn, args){
11032 var els = this.elements;
11033 for(var i = 0, len = els.length; i < len; i++) {
11034 Roo.Element.prototype[fn].apply(els[i], args);
11039 * Adds elements to this composite.
11040 * @param {String/Array} els A string CSS selector, an array of elements or an element
11041 * @return {CompositeElement} this
11043 add : function(els){
11044 if(typeof els == "string"){
11045 this.addElements(Roo.Element.selectorFunction(els));
11046 }else if(els.length !== undefined){
11047 this.addElements(els);
11049 this.addElements([els]);
11054 * Calls the passed function passing (el, this, index) for each element in this composite.
11055 * @param {Function} fn The function to call
11056 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11057 * @return {CompositeElement} this
11059 each : function(fn, scope){
11060 var els = this.elements;
11061 for(var i = 0, len = els.length; i < len; i++){
11062 if(fn.call(scope || els[i], els[i], this, i) === false) {
11070 * Returns the Element object at the specified index
11071 * @param {Number} index
11072 * @return {Roo.Element}
11074 item : function(index){
11075 return this.elements[index] || null;
11079 * Returns the first Element
11080 * @return {Roo.Element}
11082 first : function(){
11083 return this.item(0);
11087 * Returns the last Element
11088 * @return {Roo.Element}
11091 return this.item(this.elements.length-1);
11095 * Returns the number of elements in this composite
11098 getCount : function(){
11099 return this.elements.length;
11103 * Returns true if this composite contains the passed element
11106 contains : function(el){
11107 return this.indexOf(el) !== -1;
11111 * Returns true if this composite contains the passed element
11114 indexOf : function(el){
11115 return this.elements.indexOf(Roo.get(el));
11120 * Removes the specified element(s).
11121 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11122 * or an array of any of those.
11123 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11124 * @return {CompositeElement} this
11126 removeElement : function(el, removeDom){
11127 if(el instanceof Array){
11128 for(var i = 0, len = el.length; i < len; i++){
11129 this.removeElement(el[i]);
11133 var index = typeof el == 'number' ? el : this.indexOf(el);
11136 var d = this.elements[index];
11140 d.parentNode.removeChild(d);
11143 this.elements.splice(index, 1);
11149 * Replaces the specified element with the passed element.
11150 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11152 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11153 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11154 * @return {CompositeElement} this
11156 replaceElement : function(el, replacement, domReplace){
11157 var index = typeof el == 'number' ? el : this.indexOf(el);
11160 this.elements[index].replaceWith(replacement);
11162 this.elements.splice(index, 1, Roo.get(replacement))
11169 * Removes all elements.
11171 clear : function(){
11172 this.elements = [];
11176 Roo.CompositeElement.createCall = function(proto, fnName){
11177 if(!proto[fnName]){
11178 proto[fnName] = function(){
11179 return this.invoke(fnName, arguments);
11183 for(var fnName in Roo.Element.prototype){
11184 if(typeof Roo.Element.prototype[fnName] == "function"){
11185 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11191 * Ext JS Library 1.1.1
11192 * Copyright(c) 2006-2007, Ext JS, LLC.
11194 * Originally Released Under LGPL - original licence link has changed is not relivant.
11197 * <script type="text/javascript">
11201 * @class Roo.CompositeElementLite
11202 * @extends Roo.CompositeElement
11203 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11205 var els = Roo.select("#some-el div.some-class");
11206 // or select directly from an existing element
11207 var el = Roo.get('some-el');
11208 el.select('div.some-class');
11210 els.setWidth(100); // all elements become 100 width
11211 els.hide(true); // all elements fade out and hide
11213 els.setWidth(100).hide(true);
11214 </code></pre><br><br>
11215 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11216 * actions will be performed on all the elements in this collection.</b>
11218 Roo.CompositeElementLite = function(els){
11219 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11220 this.el = new Roo.Element.Flyweight();
11222 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11223 addElements : function(els){
11225 if(els instanceof Array){
11226 this.elements = this.elements.concat(els);
11228 var yels = this.elements;
11229 var index = yels.length-1;
11230 for(var i = 0, len = els.length; i < len; i++) {
11231 yels[++index] = els[i];
11237 invoke : function(fn, args){
11238 var els = this.elements;
11240 for(var i = 0, len = els.length; i < len; i++) {
11242 Roo.Element.prototype[fn].apply(el, args);
11247 * Returns a flyweight Element of the dom element object at the specified index
11248 * @param {Number} index
11249 * @return {Roo.Element}
11251 item : function(index){
11252 if(!this.elements[index]){
11255 this.el.dom = this.elements[index];
11259 // fixes scope with flyweight
11260 addListener : function(eventName, handler, scope, opt){
11261 var els = this.elements;
11262 for(var i = 0, len = els.length; i < len; i++) {
11263 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11269 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11270 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11271 * a reference to the dom node, use el.dom.</b>
11272 * @param {Function} fn The function to call
11273 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11274 * @return {CompositeElement} this
11276 each : function(fn, scope){
11277 var els = this.elements;
11279 for(var i = 0, len = els.length; i < len; i++){
11281 if(fn.call(scope || el, el, this, i) === false){
11288 indexOf : function(el){
11289 return this.elements.indexOf(Roo.getDom(el));
11292 replaceElement : function(el, replacement, domReplace){
11293 var index = typeof el == 'number' ? el : this.indexOf(el);
11295 replacement = Roo.getDom(replacement);
11297 var d = this.elements[index];
11298 d.parentNode.insertBefore(replacement, d);
11299 d.parentNode.removeChild(d);
11301 this.elements.splice(index, 1, replacement);
11306 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11310 * Ext JS Library 1.1.1
11311 * Copyright(c) 2006-2007, Ext JS, LLC.
11313 * Originally Released Under LGPL - original licence link has changed is not relivant.
11316 * <script type="text/javascript">
11322 * @class Roo.data.Connection
11323 * @extends Roo.util.Observable
11324 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11325 * either to a configured URL, or to a URL specified at request time.<br><br>
11327 * Requests made by this class are asynchronous, and will return immediately. No data from
11328 * the server will be available to the statement immediately following the {@link #request} call.
11329 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11331 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11332 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11333 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11334 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11335 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11336 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11337 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11338 * standard DOM methods.
11340 * @param {Object} config a configuration object.
11342 Roo.data.Connection = function(config){
11343 Roo.apply(this, config);
11346 * @event beforerequest
11347 * Fires before a network request is made to retrieve a data object.
11348 * @param {Connection} conn This Connection object.
11349 * @param {Object} options The options config object passed to the {@link #request} method.
11351 "beforerequest" : true,
11353 * @event requestcomplete
11354 * Fires if the request was successfully completed.
11355 * @param {Connection} conn This Connection object.
11356 * @param {Object} response The XHR object containing the response data.
11357 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11358 * @param {Object} options The options config object passed to the {@link #request} method.
11360 "requestcomplete" : true,
11362 * @event requestexception
11363 * Fires if an error HTTP status was returned from the server.
11364 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11365 * @param {Connection} conn This Connection object.
11366 * @param {Object} response The XHR object containing the response data.
11367 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11368 * @param {Object} options The options config object passed to the {@link #request} method.
11370 "requestexception" : true
11372 Roo.data.Connection.superclass.constructor.call(this);
11375 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11377 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11380 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11381 * extra parameters to each request made by this object. (defaults to undefined)
11384 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11385 * to each request made by this object. (defaults to undefined)
11388 * @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)
11391 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11395 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11401 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11404 disableCaching: true,
11407 * Sends an HTTP request to a remote server.
11408 * @param {Object} options An object which may contain the following properties:<ul>
11409 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11410 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11411 * request, a url encoded string or a function to call to get either.</li>
11412 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11413 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11414 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11415 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11416 * <li>options {Object} The parameter to the request call.</li>
11417 * <li>success {Boolean} True if the request succeeded.</li>
11418 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11420 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11421 * The callback is passed the following parameters:<ul>
11422 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11423 * <li>options {Object} The parameter to the request call.</li>
11425 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11426 * The callback is passed the following parameters:<ul>
11427 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11428 * <li>options {Object} The parameter to the request call.</li>
11430 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11431 * for the callback function. Defaults to the browser window.</li>
11432 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11433 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11434 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11435 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11436 * params for the post data. Any params will be appended to the URL.</li>
11437 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11439 * @return {Number} transactionId
11441 request : function(o){
11442 if(this.fireEvent("beforerequest", this, o) !== false){
11445 if(typeof p == "function"){
11446 p = p.call(o.scope||window, o);
11448 if(typeof p == "object"){
11449 p = Roo.urlEncode(o.params);
11451 if(this.extraParams){
11452 var extras = Roo.urlEncode(this.extraParams);
11453 p = p ? (p + '&' + extras) : extras;
11456 var url = o.url || this.url;
11457 if(typeof url == 'function'){
11458 url = url.call(o.scope||window, o);
11462 var form = Roo.getDom(o.form);
11463 url = url || form.action;
11465 var enctype = form.getAttribute("enctype");
11466 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11467 return this.doFormUpload(o, p, url);
11469 var f = Roo.lib.Ajax.serializeForm(form);
11470 p = p ? (p + '&' + f) : f;
11473 var hs = o.headers;
11474 if(this.defaultHeaders){
11475 hs = Roo.apply(hs || {}, this.defaultHeaders);
11482 success: this.handleResponse,
11483 failure: this.handleFailure,
11485 argument: {options: o},
11486 timeout : o.timeout || this.timeout
11489 var method = o.method||this.method||(p ? "POST" : "GET");
11491 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11492 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11495 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11499 }else if(this.autoAbort !== false){
11503 if((method == 'GET' && p) || o.xmlData){
11504 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11507 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11508 return this.transId;
11510 Roo.callback(o.callback, o.scope, [o, null, null]);
11516 * Determine whether this object has a request outstanding.
11517 * @param {Number} transactionId (Optional) defaults to the last transaction
11518 * @return {Boolean} True if there is an outstanding request.
11520 isLoading : function(transId){
11522 return Roo.lib.Ajax.isCallInProgress(transId);
11524 return this.transId ? true : false;
11529 * Aborts any outstanding request.
11530 * @param {Number} transactionId (Optional) defaults to the last transaction
11532 abort : function(transId){
11533 if(transId || this.isLoading()){
11534 Roo.lib.Ajax.abort(transId || this.transId);
11539 handleResponse : function(response){
11540 this.transId = false;
11541 var options = response.argument.options;
11542 response.argument = options ? options.argument : null;
11543 this.fireEvent("requestcomplete", this, response, options);
11544 Roo.callback(options.success, options.scope, [response, options]);
11545 Roo.callback(options.callback, options.scope, [options, true, response]);
11549 handleFailure : function(response, e){
11550 this.transId = false;
11551 var options = response.argument.options;
11552 response.argument = options ? options.argument : null;
11553 this.fireEvent("requestexception", this, response, options, e);
11554 Roo.callback(options.failure, options.scope, [response, options]);
11555 Roo.callback(options.callback, options.scope, [options, false, response]);
11559 doFormUpload : function(o, ps, url){
11561 var frame = document.createElement('iframe');
11564 frame.className = 'x-hidden';
11566 frame.src = Roo.SSL_SECURE_URL;
11568 document.body.appendChild(frame);
11571 document.frames[id].name = id;
11574 var form = Roo.getDom(o.form);
11576 form.method = 'POST';
11577 form.enctype = form.encoding = 'multipart/form-data';
11583 if(ps){ // add dynamic params
11585 ps = Roo.urlDecode(ps, false);
11587 if(ps.hasOwnProperty(k)){
11588 hd = document.createElement('input');
11589 hd.type = 'hidden';
11592 form.appendChild(hd);
11599 var r = { // bogus response object
11604 r.argument = o ? o.argument : null;
11609 doc = frame.contentWindow.document;
11611 doc = (frame.contentDocument || window.frames[id].document);
11613 if(doc && doc.body){
11614 r.responseText = doc.body.innerHTML;
11616 if(doc && doc.XMLDocument){
11617 r.responseXML = doc.XMLDocument;
11619 r.responseXML = doc;
11626 Roo.EventManager.removeListener(frame, 'load', cb, this);
11628 this.fireEvent("requestcomplete", this, r, o);
11629 Roo.callback(o.success, o.scope, [r, o]);
11630 Roo.callback(o.callback, o.scope, [o, true, r]);
11632 setTimeout(function(){document.body.removeChild(frame);}, 100);
11635 Roo.EventManager.on(frame, 'load', cb, this);
11638 if(hiddens){ // remove dynamic params
11639 for(var i = 0, len = hiddens.length; i < len; i++){
11640 form.removeChild(hiddens[i]);
11647 * Ext JS Library 1.1.1
11648 * Copyright(c) 2006-2007, Ext JS, LLC.
11650 * Originally Released Under LGPL - original licence link has changed is not relivant.
11653 * <script type="text/javascript">
11657 * Global Ajax request class.
11660 * @extends Roo.data.Connection
11663 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11664 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11665 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11666 * @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)
11667 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11668 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11669 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11671 Roo.Ajax = new Roo.data.Connection({
11680 * Serialize the passed form into a url encoded string
11682 * @param {String/HTMLElement} form
11685 serializeForm : function(form){
11686 return Roo.lib.Ajax.serializeForm(form);
11690 * Ext JS Library 1.1.1
11691 * Copyright(c) 2006-2007, Ext JS, LLC.
11693 * Originally Released Under LGPL - original licence link has changed is not relivant.
11696 * <script type="text/javascript">
11701 * @class Roo.UpdateManager
11702 * @extends Roo.util.Observable
11703 * Provides AJAX-style update for Element object.<br><br>
11706 * // Get it from a Roo.Element object
11707 * var el = Roo.get("foo");
11708 * var mgr = el.getUpdateManager();
11709 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11711 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11713 * // or directly (returns the same UpdateManager instance)
11714 * var mgr = new Roo.UpdateManager("myElementId");
11715 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11716 * mgr.on("update", myFcnNeedsToKnow);
11718 // short handed call directly from the element object
11719 Roo.get("foo").load({
11723 text: "Loading Foo..."
11727 * Create new UpdateManager directly.
11728 * @param {String/HTMLElement/Roo.Element} el The element to update
11729 * @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).
11731 Roo.UpdateManager = function(el, forceNew){
11733 if(!forceNew && el.updateManager){
11734 return el.updateManager;
11737 * The Element object
11738 * @type Roo.Element
11742 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11745 this.defaultUrl = null;
11749 * @event beforeupdate
11750 * Fired before an update is made, return false from your handler and the update is cancelled.
11751 * @param {Roo.Element} el
11752 * @param {String/Object/Function} url
11753 * @param {String/Object} params
11755 "beforeupdate": true,
11758 * Fired after successful update is made.
11759 * @param {Roo.Element} el
11760 * @param {Object} oResponseObject The response Object
11765 * Fired on update failure.
11766 * @param {Roo.Element} el
11767 * @param {Object} oResponseObject The response Object
11771 var d = Roo.UpdateManager.defaults;
11773 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11776 this.sslBlankUrl = d.sslBlankUrl;
11778 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11781 this.disableCaching = d.disableCaching;
11783 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11786 this.indicatorText = d.indicatorText;
11788 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11791 this.showLoadIndicator = d.showLoadIndicator;
11793 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11796 this.timeout = d.timeout;
11799 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11802 this.loadScripts = d.loadScripts;
11805 * Transaction object of current executing transaction
11807 this.transaction = null;
11812 this.autoRefreshProcId = null;
11814 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11817 this.refreshDelegate = this.refresh.createDelegate(this);
11819 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11822 this.updateDelegate = this.update.createDelegate(this);
11824 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11827 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11831 this.successDelegate = this.processSuccess.createDelegate(this);
11835 this.failureDelegate = this.processFailure.createDelegate(this);
11837 if(!this.renderer){
11839 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11841 this.renderer = new Roo.UpdateManager.BasicRenderer();
11844 Roo.UpdateManager.superclass.constructor.call(this);
11847 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11849 * Get the Element this UpdateManager is bound to
11850 * @return {Roo.Element} The element
11852 getEl : function(){
11856 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11857 * @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:
11860 url: "your-url.php",<br/>
11861 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11862 callback: yourFunction,<br/>
11863 scope: yourObject, //(optional scope) <br/>
11864 discardUrl: false, <br/>
11865 nocache: false,<br/>
11866 text: "Loading...",<br/>
11868 scripts: false<br/>
11871 * The only required property is url. The optional properties nocache, text and scripts
11872 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11873 * @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}
11874 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11875 * @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.
11877 update : function(url, params, callback, discardUrl){
11878 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11879 var method = this.method,
11881 if(typeof url == "object"){ // must be config object
11884 params = params || cfg.params;
11885 callback = callback || cfg.callback;
11886 discardUrl = discardUrl || cfg.discardUrl;
11887 if(callback && cfg.scope){
11888 callback = callback.createDelegate(cfg.scope);
11890 if(typeof cfg.method != "undefined"){method = cfg.method;};
11891 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11892 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11893 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11894 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11896 this.showLoading();
11898 this.defaultUrl = url;
11900 if(typeof url == "function"){
11901 url = url.call(this);
11904 method = method || (params ? "POST" : "GET");
11905 if(method == "GET"){
11906 url = this.prepareUrl(url);
11909 var o = Roo.apply(cfg ||{}, {
11912 success: this.successDelegate,
11913 failure: this.failureDelegate,
11914 callback: undefined,
11915 timeout: (this.timeout*1000),
11916 argument: {"url": url, "form": null, "callback": callback, "params": params}
11918 Roo.log("updated manager called with timeout of " + o.timeout);
11919 this.transaction = Roo.Ajax.request(o);
11924 * 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.
11925 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11926 * @param {String/HTMLElement} form The form Id or form element
11927 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11928 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11929 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11931 formUpdate : function(form, url, reset, callback){
11932 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11933 if(typeof url == "function"){
11934 url = url.call(this);
11936 form = Roo.getDom(form);
11937 this.transaction = Roo.Ajax.request({
11940 success: this.successDelegate,
11941 failure: this.failureDelegate,
11942 timeout: (this.timeout*1000),
11943 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11945 this.showLoading.defer(1, this);
11950 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11951 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11953 refresh : function(callback){
11954 if(this.defaultUrl == null){
11957 this.update(this.defaultUrl, null, callback, true);
11961 * Set this element to auto refresh.
11962 * @param {Number} interval How often to update (in seconds).
11963 * @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)
11964 * @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}
11965 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11966 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11968 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11970 this.update(url || this.defaultUrl, params, callback, true);
11972 if(this.autoRefreshProcId){
11973 clearInterval(this.autoRefreshProcId);
11975 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11979 * Stop auto refresh on this element.
11981 stopAutoRefresh : function(){
11982 if(this.autoRefreshProcId){
11983 clearInterval(this.autoRefreshProcId);
11984 delete this.autoRefreshProcId;
11988 isAutoRefreshing : function(){
11989 return this.autoRefreshProcId ? true : false;
11992 * Called to update the element to "Loading" state. Override to perform custom action.
11994 showLoading : function(){
11995 if(this.showLoadIndicator){
11996 this.el.update(this.indicatorText);
12001 * Adds unique parameter to query string if disableCaching = true
12004 prepareUrl : function(url){
12005 if(this.disableCaching){
12006 var append = "_dc=" + (new Date().getTime());
12007 if(url.indexOf("?") !== -1){
12008 url += "&" + append;
12010 url += "?" + append;
12019 processSuccess : function(response){
12020 this.transaction = null;
12021 if(response.argument.form && response.argument.reset){
12022 try{ // put in try/catch since some older FF releases had problems with this
12023 response.argument.form.reset();
12026 if(this.loadScripts){
12027 this.renderer.render(this.el, response, this,
12028 this.updateComplete.createDelegate(this, [response]));
12030 this.renderer.render(this.el, response, this);
12031 this.updateComplete(response);
12035 updateComplete : function(response){
12036 this.fireEvent("update", this.el, response);
12037 if(typeof response.argument.callback == "function"){
12038 response.argument.callback(this.el, true, response);
12045 processFailure : function(response){
12046 this.transaction = null;
12047 this.fireEvent("failure", this.el, response);
12048 if(typeof response.argument.callback == "function"){
12049 response.argument.callback(this.el, false, response);
12054 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12055 * @param {Object} renderer The object implementing the render() method
12057 setRenderer : function(renderer){
12058 this.renderer = renderer;
12061 getRenderer : function(){
12062 return this.renderer;
12066 * Set the defaultUrl used for updates
12067 * @param {String/Function} defaultUrl The url or a function to call to get the url
12069 setDefaultUrl : function(defaultUrl){
12070 this.defaultUrl = defaultUrl;
12074 * Aborts the executing transaction
12076 abort : function(){
12077 if(this.transaction){
12078 Roo.Ajax.abort(this.transaction);
12083 * Returns true if an update is in progress
12084 * @return {Boolean}
12086 isUpdating : function(){
12087 if(this.transaction){
12088 return Roo.Ajax.isLoading(this.transaction);
12095 * @class Roo.UpdateManager.defaults
12096 * @static (not really - but it helps the doc tool)
12097 * The defaults collection enables customizing the default properties of UpdateManager
12099 Roo.UpdateManager.defaults = {
12101 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12107 * True to process scripts by default (Defaults to false).
12110 loadScripts : false,
12113 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12116 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12118 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12121 disableCaching : false,
12123 * Whether to show indicatorText when loading (Defaults to true).
12126 showLoadIndicator : true,
12128 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12131 indicatorText : '<div class="loading-indicator">Loading...</div>'
12135 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12137 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12138 * @param {String/HTMLElement/Roo.Element} el The element to update
12139 * @param {String} url The url
12140 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12141 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12144 * @member Roo.UpdateManager
12146 Roo.UpdateManager.updateElement = function(el, url, params, options){
12147 var um = Roo.get(el, true).getUpdateManager();
12148 Roo.apply(um, options);
12149 um.update(url, params, options ? options.callback : null);
12151 // alias for backwards compat
12152 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12154 * @class Roo.UpdateManager.BasicRenderer
12155 * Default Content renderer. Updates the elements innerHTML with the responseText.
12157 Roo.UpdateManager.BasicRenderer = function(){};
12159 Roo.UpdateManager.BasicRenderer.prototype = {
12161 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12162 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12163 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12164 * @param {Roo.Element} el The element being rendered
12165 * @param {Object} response The YUI Connect response object
12166 * @param {UpdateManager} updateManager The calling update manager
12167 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12169 render : function(el, response, updateManager, callback){
12170 el.update(response.responseText, updateManager.loadScripts, callback);
12176 * (c)) Alan Knowles
12182 * @class Roo.DomTemplate
12183 * @extends Roo.Template
12184 * An effort at a dom based template engine..
12186 * Similar to XTemplate, except it uses dom parsing to create the template..
12188 * Supported features:
12193 {a_variable} - output encoded.
12194 {a_variable.format:("Y-m-d")} - call a method on the variable
12195 {a_variable:raw} - unencoded output
12196 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12197 {a_variable:this.method_on_template(...)} - call a method on the template object.
12202 <div roo-for="a_variable or condition.."></div>
12203 <div roo-if="a_variable or condition"></div>
12204 <div roo-exec="some javascript"></div>
12205 <div roo-name="named_template"></div>
12210 Roo.DomTemplate = function()
12212 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12219 Roo.extend(Roo.DomTemplate, Roo.Template, {
12221 * id counter for sub templates.
12225 * flag to indicate if dom parser is inside a pre,
12226 * it will strip whitespace if not.
12231 * The various sub templates
12239 * basic tag replacing syntax
12242 * // you can fake an object call by doing this
12246 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12247 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12249 iterChild : function (node, method) {
12251 var oldPre = this.inPre;
12252 if (node.tagName == 'PRE') {
12255 for( var i = 0; i < node.childNodes.length; i++) {
12256 method.call(this, node.childNodes[i]);
12258 this.inPre = oldPre;
12264 * compile the template
12266 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12269 compile: function()
12273 // covert the html into DOM...
12277 doc = document.implementation.createHTMLDocument("");
12278 doc.documentElement.innerHTML = this.html ;
12279 div = doc.documentElement;
12281 // old IE... - nasty -- it causes all sorts of issues.. with
12282 // images getting pulled from server..
12283 div = document.createElement('div');
12284 div.innerHTML = this.html;
12286 //doc.documentElement.innerHTML = htmlBody
12292 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12294 var tpls = this.tpls;
12296 // create a top level template from the snippet..
12298 //Roo.log(div.innerHTML);
12305 body : div.innerHTML,
12318 Roo.each(tpls, function(tp){
12319 this.compileTpl(tp);
12320 this.tpls[tp.id] = tp;
12323 this.master = tpls[0];
12329 compileNode : function(node, istop) {
12334 // skip anything not a tag..
12335 if (node.nodeType != 1) {
12336 if (node.nodeType == 3 && !this.inPre) {
12337 // reduce white space..
12338 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12361 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12362 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12363 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12364 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12370 // just itterate children..
12371 this.iterChild(node,this.compileNode);
12374 tpl.uid = this.id++;
12375 tpl.value = node.getAttribute('roo-' + tpl.attr);
12376 node.removeAttribute('roo-'+ tpl.attr);
12377 if (tpl.attr != 'name') {
12378 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12379 node.parentNode.replaceChild(placeholder, node);
12382 var placeholder = document.createElement('span');
12383 placeholder.className = 'roo-tpl-' + tpl.value;
12384 node.parentNode.replaceChild(placeholder, node);
12387 // parent now sees '{domtplXXXX}
12388 this.iterChild(node,this.compileNode);
12390 // we should now have node body...
12391 var div = document.createElement('div');
12392 div.appendChild(node);
12394 // this has the unfortunate side effect of converting tagged attributes
12395 // eg. href="{...}" into %7C...%7D
12396 // this has been fixed by searching for those combo's although it's a bit hacky..
12399 tpl.body = div.innerHTML;
12406 switch (tpl.value) {
12407 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12408 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12409 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12414 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12418 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12422 tpl.id = tpl.value; // replace non characters???
12428 this.tpls.push(tpl);
12438 * Compile a segment of the template into a 'sub-template'
12444 compileTpl : function(tpl)
12446 var fm = Roo.util.Format;
12447 var useF = this.disableFormats !== true;
12449 var sep = Roo.isGecko ? "+\n" : ",\n";
12451 var undef = function(str) {
12452 Roo.debug && Roo.log("Property not found :" + str);
12456 //Roo.log(tpl.body);
12460 var fn = function(m, lbrace, name, format, args)
12463 //Roo.log(arguments);
12464 args = args ? args.replace(/\\'/g,"'") : args;
12465 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12466 if (typeof(format) == 'undefined') {
12467 format = 'htmlEncode';
12469 if (format == 'raw' ) {
12473 if(name.substr(0, 6) == 'domtpl'){
12474 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12477 // build an array of options to determine if value is undefined..
12479 // basically get 'xxxx.yyyy' then do
12480 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12481 // (function () { Roo.log("Property not found"); return ''; })() :
12486 Roo.each(name.split('.'), function(st) {
12487 lookfor += (lookfor.length ? '.': '') + st;
12488 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12491 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12494 if(format && useF){
12496 args = args ? ',' + args : "";
12498 if(format.substr(0, 5) != "this."){
12499 format = "fm." + format + '(';
12501 format = 'this.call("'+ format.substr(5) + '", ';
12505 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12508 if (args && args.length) {
12509 // called with xxyx.yuu:(test,test)
12511 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12513 // raw.. - :raw modifier..
12514 return "'"+ sep + udef_st + name + ")"+sep+"'";
12518 // branched to use + in gecko and [].join() in others
12520 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12521 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12524 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12525 body.push(tpl.body.replace(/(\r\n|\n)/g,
12526 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12527 body.push("'].join('');};};");
12528 body = body.join('');
12531 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12533 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12540 * same as applyTemplate, except it's done to one of the subTemplates
12541 * when using named templates, you can do:
12543 * var str = pl.applySubTemplate('your-name', values);
12546 * @param {Number} id of the template
12547 * @param {Object} values to apply to template
12548 * @param {Object} parent (normaly the instance of this object)
12550 applySubTemplate : function(id, values, parent)
12554 var t = this.tpls[id];
12558 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12559 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12563 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12570 if(t.execCall && t.execCall.call(this, values, parent)){
12574 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12580 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12581 parent = t.target ? values : parent;
12582 if(t.forCall && vs instanceof Array){
12584 for(var i = 0, len = vs.length; i < len; i++){
12586 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12588 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12590 //Roo.log(t.compiled);
12594 return buf.join('');
12597 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12602 return t.compiled.call(this, vs, parent);
12604 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12606 //Roo.log(t.compiled);
12614 applyTemplate : function(values){
12615 return this.master.compiled.call(this, values, {});
12616 //var s = this.subs;
12619 apply : function(){
12620 return this.applyTemplate.apply(this, arguments);
12625 Roo.DomTemplate.from = function(el){
12626 el = Roo.getDom(el);
12627 return new Roo.Domtemplate(el.value || el.innerHTML);
12630 * Ext JS Library 1.1.1
12631 * Copyright(c) 2006-2007, Ext JS, LLC.
12633 * Originally Released Under LGPL - original licence link has changed is not relivant.
12636 * <script type="text/javascript">
12640 * @class Roo.util.DelayedTask
12641 * Provides a convenient method of performing setTimeout where a new
12642 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12643 * You can use this class to buffer
12644 * the keypress events for a certain number of milliseconds, and perform only if they stop
12645 * for that amount of time.
12646 * @constructor The parameters to this constructor serve as defaults and are not required.
12647 * @param {Function} fn (optional) The default function to timeout
12648 * @param {Object} scope (optional) The default scope of that timeout
12649 * @param {Array} args (optional) The default Array of arguments
12651 Roo.util.DelayedTask = function(fn, scope, args){
12652 var id = null, d, t;
12654 var call = function(){
12655 var now = new Date().getTime();
12659 fn.apply(scope, args || []);
12663 * Cancels any pending timeout and queues a new one
12664 * @param {Number} delay The milliseconds to delay
12665 * @param {Function} newFn (optional) Overrides function passed to constructor
12666 * @param {Object} newScope (optional) Overrides scope passed to constructor
12667 * @param {Array} newArgs (optional) Overrides args passed to constructor
12669 this.delay = function(delay, newFn, newScope, newArgs){
12670 if(id && delay != d){
12674 t = new Date().getTime();
12676 scope = newScope || scope;
12677 args = newArgs || args;
12679 id = setInterval(call, d);
12684 * Cancel the last queued timeout
12686 this.cancel = function(){
12694 * Ext JS Library 1.1.1
12695 * Copyright(c) 2006-2007, Ext JS, LLC.
12697 * Originally Released Under LGPL - original licence link has changed is not relivant.
12700 * <script type="text/javascript">
12704 Roo.util.TaskRunner = function(interval){
12705 interval = interval || 10;
12706 var tasks = [], removeQueue = [];
12708 var running = false;
12710 var stopThread = function(){
12716 var startThread = function(){
12719 id = setInterval(runTasks, interval);
12723 var removeTask = function(task){
12724 removeQueue.push(task);
12730 var runTasks = function(){
12731 if(removeQueue.length > 0){
12732 for(var i = 0, len = removeQueue.length; i < len; i++){
12733 tasks.remove(removeQueue[i]);
12736 if(tasks.length < 1){
12741 var now = new Date().getTime();
12742 for(var i = 0, len = tasks.length; i < len; ++i){
12744 var itime = now - t.taskRunTime;
12745 if(t.interval <= itime){
12746 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12747 t.taskRunTime = now;
12748 if(rt === false || t.taskRunCount === t.repeat){
12753 if(t.duration && t.duration <= (now - t.taskStartTime)){
12760 * Queues a new task.
12761 * @param {Object} task
12763 this.start = function(task){
12765 task.taskStartTime = new Date().getTime();
12766 task.taskRunTime = 0;
12767 task.taskRunCount = 0;
12772 this.stop = function(task){
12777 this.stopAll = function(){
12779 for(var i = 0, len = tasks.length; i < len; i++){
12780 if(tasks[i].onStop){
12789 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12791 * Ext JS Library 1.1.1
12792 * Copyright(c) 2006-2007, Ext JS, LLC.
12794 * Originally Released Under LGPL - original licence link has changed is not relivant.
12797 * <script type="text/javascript">
12802 * @class Roo.util.MixedCollection
12803 * @extends Roo.util.Observable
12804 * A Collection class that maintains both numeric indexes and keys and exposes events.
12806 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12807 * collection (defaults to false)
12808 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12809 * and return the key value for that item. This is used when available to look up the key on items that
12810 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12811 * equivalent to providing an implementation for the {@link #getKey} method.
12813 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12821 * Fires when the collection is cleared.
12826 * Fires when an item is added to the collection.
12827 * @param {Number} index The index at which the item was added.
12828 * @param {Object} o The item added.
12829 * @param {String} key The key associated with the added item.
12834 * Fires when an item is replaced in the collection.
12835 * @param {String} key he key associated with the new added.
12836 * @param {Object} old The item being replaced.
12837 * @param {Object} new The new item.
12842 * Fires when an item is removed from the collection.
12843 * @param {Object} o The item being removed.
12844 * @param {String} key (optional) The key associated with the removed item.
12849 this.allowFunctions = allowFunctions === true;
12851 this.getKey = keyFn;
12853 Roo.util.MixedCollection.superclass.constructor.call(this);
12856 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12857 allowFunctions : false,
12860 * Adds an item to the collection.
12861 * @param {String} key The key to associate with the item
12862 * @param {Object} o The item to add.
12863 * @return {Object} The item added.
12865 add : function(key, o){
12866 if(arguments.length == 1){
12868 key = this.getKey(o);
12873 if(typeof key == "undefined" || key === null){
12875 this.items.push(o);
12876 this.keys.push(null);
12878 var old = this.map[key];
12880 return this.replace(key, o);
12883 this.items.push(o);
12885 this.keys.push(key);
12887 this.fireEvent("add", this.length-1, o, key);
12892 * MixedCollection has a generic way to fetch keys if you implement getKey.
12895 var mc = new Roo.util.MixedCollection();
12896 mc.add(someEl.dom.id, someEl);
12897 mc.add(otherEl.dom.id, otherEl);
12901 var mc = new Roo.util.MixedCollection();
12902 mc.getKey = function(el){
12908 // or via the constructor
12909 var mc = new Roo.util.MixedCollection(false, function(el){
12915 * @param o {Object} The item for which to find the key.
12916 * @return {Object} The key for the passed item.
12918 getKey : function(o){
12923 * Replaces an item in the collection.
12924 * @param {String} key The key associated with the item to replace, or the item to replace.
12925 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12926 * @return {Object} The new item.
12928 replace : function(key, o){
12929 if(arguments.length == 1){
12931 key = this.getKey(o);
12933 var old = this.item(key);
12934 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12935 return this.add(key, o);
12937 var index = this.indexOfKey(key);
12938 this.items[index] = o;
12940 this.fireEvent("replace", key, old, o);
12945 * Adds all elements of an Array or an Object to the collection.
12946 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12947 * an Array of values, each of which are added to the collection.
12949 addAll : function(objs){
12950 if(arguments.length > 1 || objs instanceof Array){
12951 var args = arguments.length > 1 ? arguments : objs;
12952 for(var i = 0, len = args.length; i < len; i++){
12956 for(var key in objs){
12957 if(this.allowFunctions || typeof objs[key] != "function"){
12958 this.add(key, objs[key]);
12965 * Executes the specified function once for every item in the collection, passing each
12966 * item as the first and only parameter. returning false from the function will stop the iteration.
12967 * @param {Function} fn The function to execute for each item.
12968 * @param {Object} scope (optional) The scope in which to execute the function.
12970 each : function(fn, scope){
12971 var items = [].concat(this.items); // each safe for removal
12972 for(var i = 0, len = items.length; i < len; i++){
12973 if(fn.call(scope || items[i], items[i], i, len) === false){
12980 * Executes the specified function once for every key in the collection, passing each
12981 * key, and its associated item as the first two parameters.
12982 * @param {Function} fn The function to execute for each item.
12983 * @param {Object} scope (optional) The scope in which to execute the function.
12985 eachKey : function(fn, scope){
12986 for(var i = 0, len = this.keys.length; i < len; i++){
12987 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12992 * Returns the first item in the collection which elicits a true return value from the
12993 * passed selection function.
12994 * @param {Function} fn The selection function to execute for each item.
12995 * @param {Object} scope (optional) The scope in which to execute the function.
12996 * @return {Object} The first item in the collection which returned true from the selection function.
12998 find : function(fn, scope){
12999 for(var i = 0, len = this.items.length; i < len; i++){
13000 if(fn.call(scope || window, this.items[i], this.keys[i])){
13001 return this.items[i];
13008 * Inserts an item at the specified index in the collection.
13009 * @param {Number} index The index to insert the item at.
13010 * @param {String} key The key to associate with the new item, or the item itself.
13011 * @param {Object} o (optional) If the second parameter was a key, the new item.
13012 * @return {Object} The item inserted.
13014 insert : function(index, key, o){
13015 if(arguments.length == 2){
13017 key = this.getKey(o);
13019 if(index >= this.length){
13020 return this.add(key, o);
13023 this.items.splice(index, 0, o);
13024 if(typeof key != "undefined" && key != null){
13027 this.keys.splice(index, 0, key);
13028 this.fireEvent("add", index, o, key);
13033 * Removed an item from the collection.
13034 * @param {Object} o The item to remove.
13035 * @return {Object} The item removed.
13037 remove : function(o){
13038 return this.removeAt(this.indexOf(o));
13042 * Remove an item from a specified index in the collection.
13043 * @param {Number} index The index within the collection of the item to remove.
13045 removeAt : function(index){
13046 if(index < this.length && index >= 0){
13048 var o = this.items[index];
13049 this.items.splice(index, 1);
13050 var key = this.keys[index];
13051 if(typeof key != "undefined"){
13052 delete this.map[key];
13054 this.keys.splice(index, 1);
13055 this.fireEvent("remove", o, key);
13060 * Removed an item associated with the passed key fom the collection.
13061 * @param {String} key The key of the item to remove.
13063 removeKey : function(key){
13064 return this.removeAt(this.indexOfKey(key));
13068 * Returns the number of items in the collection.
13069 * @return {Number} the number of items in the collection.
13071 getCount : function(){
13072 return this.length;
13076 * Returns index within the collection of the passed Object.
13077 * @param {Object} o The item to find the index of.
13078 * @return {Number} index of the item.
13080 indexOf : function(o){
13081 if(!this.items.indexOf){
13082 for(var i = 0, len = this.items.length; i < len; i++){
13083 if(this.items[i] == o) return i;
13087 return this.items.indexOf(o);
13092 * Returns index within the collection of the passed key.
13093 * @param {String} key The key to find the index of.
13094 * @return {Number} index of the key.
13096 indexOfKey : function(key){
13097 if(!this.keys.indexOf){
13098 for(var i = 0, len = this.keys.length; i < len; i++){
13099 if(this.keys[i] == key) return i;
13103 return this.keys.indexOf(key);
13108 * Returns the item associated with the passed key OR index. Key has priority over index.
13109 * @param {String/Number} key The key or index of the item.
13110 * @return {Object} The item associated with the passed key.
13112 item : function(key){
13113 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13114 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13118 * Returns the item at the specified index.
13119 * @param {Number} index The index of the item.
13122 itemAt : function(index){
13123 return this.items[index];
13127 * Returns the item associated with the passed key.
13128 * @param {String/Number} key The key of the item.
13129 * @return {Object} The item associated with the passed key.
13131 key : function(key){
13132 return this.map[key];
13136 * Returns true if the collection contains the passed Object as an item.
13137 * @param {Object} o The Object to look for in the collection.
13138 * @return {Boolean} True if the collection contains the Object as an item.
13140 contains : function(o){
13141 return this.indexOf(o) != -1;
13145 * Returns true if the collection contains the passed Object as a key.
13146 * @param {String} key The key to look for in the collection.
13147 * @return {Boolean} True if the collection contains the Object as a key.
13149 containsKey : function(key){
13150 return typeof this.map[key] != "undefined";
13154 * Removes all items from the collection.
13156 clear : function(){
13161 this.fireEvent("clear");
13165 * Returns the first item in the collection.
13166 * @return {Object} the first item in the collection..
13168 first : function(){
13169 return this.items[0];
13173 * Returns the last item in the collection.
13174 * @return {Object} the last item in the collection..
13177 return this.items[this.length-1];
13180 _sort : function(property, dir, fn){
13181 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13182 fn = fn || function(a, b){
13185 var c = [], k = this.keys, items = this.items;
13186 for(var i = 0, len = items.length; i < len; i++){
13187 c[c.length] = {key: k[i], value: items[i], index: i};
13189 c.sort(function(a, b){
13190 var v = fn(a[property], b[property]) * dsc;
13192 v = (a.index < b.index ? -1 : 1);
13196 for(var i = 0, len = c.length; i < len; i++){
13197 items[i] = c[i].value;
13200 this.fireEvent("sort", this);
13204 * Sorts this collection with the passed comparison function
13205 * @param {String} direction (optional) "ASC" or "DESC"
13206 * @param {Function} fn (optional) comparison function
13208 sort : function(dir, fn){
13209 this._sort("value", dir, fn);
13213 * Sorts this collection by keys
13214 * @param {String} direction (optional) "ASC" or "DESC"
13215 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13217 keySort : function(dir, fn){
13218 this._sort("key", dir, fn || function(a, b){
13219 return String(a).toUpperCase()-String(b).toUpperCase();
13224 * Returns a range of items in this collection
13225 * @param {Number} startIndex (optional) defaults to 0
13226 * @param {Number} endIndex (optional) default to the last item
13227 * @return {Array} An array of items
13229 getRange : function(start, end){
13230 var items = this.items;
13231 if(items.length < 1){
13234 start = start || 0;
13235 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13238 for(var i = start; i <= end; i++) {
13239 r[r.length] = items[i];
13242 for(var i = start; i >= end; i--) {
13243 r[r.length] = items[i];
13250 * Filter the <i>objects</i> in this collection by a specific property.
13251 * Returns a new collection that has been filtered.
13252 * @param {String} property A property on your objects
13253 * @param {String/RegExp} value Either string that the property values
13254 * should start with or a RegExp to test against the property
13255 * @return {MixedCollection} The new filtered collection
13257 filter : function(property, value){
13258 if(!value.exec){ // not a regex
13259 value = String(value);
13260 if(value.length == 0){
13261 return this.clone();
13263 value = new RegExp("^" + Roo.escapeRe(value), "i");
13265 return this.filterBy(function(o){
13266 return o && value.test(o[property]);
13271 * Filter by a function. * Returns a new collection that has been filtered.
13272 * The passed function will be called with each
13273 * object in the collection. If the function returns true, the value is included
13274 * otherwise it is filtered.
13275 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13276 * @param {Object} scope (optional) The scope of the function (defaults to this)
13277 * @return {MixedCollection} The new filtered collection
13279 filterBy : function(fn, scope){
13280 var r = new Roo.util.MixedCollection();
13281 r.getKey = this.getKey;
13282 var k = this.keys, it = this.items;
13283 for(var i = 0, len = it.length; i < len; i++){
13284 if(fn.call(scope||this, it[i], k[i])){
13285 r.add(k[i], it[i]);
13292 * Creates a duplicate of this collection
13293 * @return {MixedCollection}
13295 clone : function(){
13296 var r = new Roo.util.MixedCollection();
13297 var k = this.keys, it = this.items;
13298 for(var i = 0, len = it.length; i < len; i++){
13299 r.add(k[i], it[i]);
13301 r.getKey = this.getKey;
13306 * Returns the item associated with the passed key or index.
13308 * @param {String/Number} key The key or index of the item.
13309 * @return {Object} The item associated with the passed key.
13311 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13313 * Ext JS Library 1.1.1
13314 * Copyright(c) 2006-2007, Ext JS, LLC.
13316 * Originally Released Under LGPL - original licence link has changed is not relivant.
13319 * <script type="text/javascript">
13322 * @class Roo.util.JSON
13323 * Modified version of Douglas Crockford"s json.js that doesn"t
13324 * mess with the Object prototype
13325 * http://www.json.org/js.html
13328 Roo.util.JSON = new (function(){
13329 var useHasOwn = {}.hasOwnProperty ? true : false;
13331 // crashes Safari in some instances
13332 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13334 var pad = function(n) {
13335 return n < 10 ? "0" + n : n;
13348 var encodeString = function(s){
13349 if (/["\\\x00-\x1f]/.test(s)) {
13350 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13355 c = b.charCodeAt();
13357 Math.floor(c / 16).toString(16) +
13358 (c % 16).toString(16);
13361 return '"' + s + '"';
13364 var encodeArray = function(o){
13365 var a = ["["], b, i, l = o.length, v;
13366 for (i = 0; i < l; i += 1) {
13368 switch (typeof v) {
13377 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13385 var encodeDate = function(o){
13386 return '"' + o.getFullYear() + "-" +
13387 pad(o.getMonth() + 1) + "-" +
13388 pad(o.getDate()) + "T" +
13389 pad(o.getHours()) + ":" +
13390 pad(o.getMinutes()) + ":" +
13391 pad(o.getSeconds()) + '"';
13395 * Encodes an Object, Array or other value
13396 * @param {Mixed} o The variable to encode
13397 * @return {String} The JSON string
13399 this.encode = function(o)
13401 // should this be extended to fully wrap stringify..
13403 if(typeof o == "undefined" || o === null){
13405 }else if(o instanceof Array){
13406 return encodeArray(o);
13407 }else if(o instanceof Date){
13408 return encodeDate(o);
13409 }else if(typeof o == "string"){
13410 return encodeString(o);
13411 }else if(typeof o == "number"){
13412 return isFinite(o) ? String(o) : "null";
13413 }else if(typeof o == "boolean"){
13416 var a = ["{"], b, i, v;
13418 if(!useHasOwn || o.hasOwnProperty(i)) {
13420 switch (typeof v) {
13429 a.push(this.encode(i), ":",
13430 v === null ? "null" : this.encode(v));
13441 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13442 * @param {String} json The JSON string
13443 * @return {Object} The resulting object
13445 this.decode = function(json){
13447 return /** eval:var:json */ eval("(" + json + ')');
13451 * Shorthand for {@link Roo.util.JSON#encode}
13452 * @member Roo encode
13454 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13456 * Shorthand for {@link Roo.util.JSON#decode}
13457 * @member Roo decode
13459 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13462 * Ext JS Library 1.1.1
13463 * Copyright(c) 2006-2007, Ext JS, LLC.
13465 * Originally Released Under LGPL - original licence link has changed is not relivant.
13468 * <script type="text/javascript">
13472 * @class Roo.util.Format
13473 * Reusable data formatting functions
13476 Roo.util.Format = function(){
13477 var trimRe = /^\s+|\s+$/g;
13480 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13481 * @param {String} value The string to truncate
13482 * @param {Number} length The maximum length to allow before truncating
13483 * @return {String} The converted text
13485 ellipsis : function(value, len){
13486 if(value && value.length > len){
13487 return value.substr(0, len-3)+"...";
13493 * Checks a reference and converts it to empty string if it is undefined
13494 * @param {Mixed} value Reference to check
13495 * @return {Mixed} Empty string if converted, otherwise the original value
13497 undef : function(value){
13498 return typeof value != "undefined" ? value : "";
13502 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13503 * @param {String} value The string to encode
13504 * @return {String} The encoded text
13506 htmlEncode : function(value){
13507 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13511 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13512 * @param {String} value The string to decode
13513 * @return {String} The decoded text
13515 htmlDecode : function(value){
13516 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13520 * Trims any whitespace from either side of a string
13521 * @param {String} value The text to trim
13522 * @return {String} The trimmed text
13524 trim : function(value){
13525 return String(value).replace(trimRe, "");
13529 * Returns a substring from within an original string
13530 * @param {String} value The original text
13531 * @param {Number} start The start index of the substring
13532 * @param {Number} length The length of the substring
13533 * @return {String} The substring
13535 substr : function(value, start, length){
13536 return String(value).substr(start, length);
13540 * Converts a string to all lower case letters
13541 * @param {String} value The text to convert
13542 * @return {String} The converted text
13544 lowercase : function(value){
13545 return String(value).toLowerCase();
13549 * Converts a string to all upper case letters
13550 * @param {String} value The text to convert
13551 * @return {String} The converted text
13553 uppercase : function(value){
13554 return String(value).toUpperCase();
13558 * Converts the first character only of a string to upper case
13559 * @param {String} value The text to convert
13560 * @return {String} The converted text
13562 capitalize : function(value){
13563 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13567 call : function(value, fn){
13568 if(arguments.length > 2){
13569 var args = Array.prototype.slice.call(arguments, 2);
13570 args.unshift(value);
13572 return /** eval:var:value */ eval(fn).apply(window, args);
13574 /** eval:var:value */
13575 return /** eval:var:value */ eval(fn).call(window, value);
13581 * safer version of Math.toFixed..??/
13582 * @param {Number/String} value The numeric value to format
13583 * @param {Number/String} value Decimal places
13584 * @return {String} The formatted currency string
13586 toFixed : function(v, n)
13588 // why not use to fixed - precision is buggered???
13590 return Math.round(v-0);
13592 var fact = Math.pow(10,n+1);
13593 v = (Math.round((v-0)*fact))/fact;
13594 var z = (''+fact).substring(2);
13595 if (v == Math.floor(v)) {
13596 return Math.floor(v) + '.' + z;
13599 // now just padd decimals..
13600 var ps = String(v).split('.');
13601 var fd = (ps[1] + z);
13602 var r = fd.substring(0,n);
13603 var rm = fd.substring(n);
13605 return ps[0] + '.' + r;
13607 r*=1; // turn it into a number;
13609 if (String(r).length != n) {
13612 r = String(r).substring(1); // chop the end off.
13615 return ps[0] + '.' + r;
13620 * Format a number as US currency
13621 * @param {Number/String} value The numeric value to format
13622 * @return {String} The formatted currency string
13624 usMoney : function(v){
13625 return '$' + Roo.util.Format.number(v);
13630 * eventually this should probably emulate php's number_format
13631 * @param {Number/String} value The numeric value to format
13632 * @param {Number} decimals number of decimal places
13633 * @return {String} The formatted currency string
13635 number : function(v,decimals)
13637 // multiply and round.
13638 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13639 var mul = Math.pow(10, decimals);
13640 var zero = String(mul).substring(1);
13641 v = (Math.round((v-0)*mul))/mul;
13643 // if it's '0' number.. then
13645 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13647 var ps = v.split('.');
13651 var r = /(\d+)(\d{3})/;
13653 while (r.test(whole)) {
13654 whole = whole.replace(r, '$1' + ',' + '$2');
13660 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13661 // does not have decimals
13662 (decimals ? ('.' + zero) : '');
13665 return whole + sub ;
13669 * Parse a value into a formatted date using the specified format pattern.
13670 * @param {Mixed} value The value to format
13671 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13672 * @return {String} The formatted date string
13674 date : function(v, format){
13678 if(!(v instanceof Date)){
13679 v = new Date(Date.parse(v));
13681 return v.dateFormat(format || Roo.util.Format.defaults.date);
13685 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13686 * @param {String} format Any valid date format string
13687 * @return {Function} The date formatting function
13689 dateRenderer : function(format){
13690 return function(v){
13691 return Roo.util.Format.date(v, format);
13696 stripTagsRE : /<\/?[^>]+>/gi,
13699 * Strips all HTML tags
13700 * @param {Mixed} value The text from which to strip tags
13701 * @return {String} The stripped text
13703 stripTags : function(v){
13704 return !v ? v : String(v).replace(this.stripTagsRE, "");
13708 Roo.util.Format.defaults = {
13712 * Ext JS Library 1.1.1
13713 * Copyright(c) 2006-2007, Ext JS, LLC.
13715 * Originally Released Under LGPL - original licence link has changed is not relivant.
13718 * <script type="text/javascript">
13725 * @class Roo.MasterTemplate
13726 * @extends Roo.Template
13727 * Provides a template that can have child templates. The syntax is:
13729 var t = new Roo.MasterTemplate(
13730 '<select name="{name}">',
13731 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13734 t.add('options', {value: 'foo', text: 'bar'});
13735 // or you can add multiple child elements in one shot
13736 t.addAll('options', [
13737 {value: 'foo', text: 'bar'},
13738 {value: 'foo2', text: 'bar2'},
13739 {value: 'foo3', text: 'bar3'}
13741 // then append, applying the master template values
13742 t.append('my-form', {name: 'my-select'});
13744 * A name attribute for the child template is not required if you have only one child
13745 * template or you want to refer to them by index.
13747 Roo.MasterTemplate = function(){
13748 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13749 this.originalHtml = this.html;
13751 var m, re = this.subTemplateRe;
13754 while(m = re.exec(this.html)){
13755 var name = m[1], content = m[2];
13760 tpl : new Roo.Template(content)
13763 st[name] = st[subIndex];
13765 st[subIndex].tpl.compile();
13766 st[subIndex].tpl.call = this.call.createDelegate(this);
13769 this.subCount = subIndex;
13772 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13774 * The regular expression used to match sub templates
13778 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13781 * Applies the passed values to a child template.
13782 * @param {String/Number} name (optional) The name or index of the child template
13783 * @param {Array/Object} values The values to be applied to the template
13784 * @return {MasterTemplate} this
13786 add : function(name, values){
13787 if(arguments.length == 1){
13788 values = arguments[0];
13791 var s = this.subs[name];
13792 s.buffer[s.buffer.length] = s.tpl.apply(values);
13797 * Applies all the passed values to a child template.
13798 * @param {String/Number} name (optional) The name or index of the child template
13799 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13800 * @param {Boolean} reset (optional) True to reset the template first
13801 * @return {MasterTemplate} this
13803 fill : function(name, values, reset){
13805 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13813 for(var i = 0, len = values.length; i < len; i++){
13814 this.add(name, values[i]);
13820 * Resets the template for reuse
13821 * @return {MasterTemplate} this
13823 reset : function(){
13825 for(var i = 0; i < this.subCount; i++){
13831 applyTemplate : function(values){
13833 var replaceIndex = -1;
13834 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13835 return s[++replaceIndex].buffer.join("");
13837 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13840 apply : function(){
13841 return this.applyTemplate.apply(this, arguments);
13844 compile : function(){return this;}
13848 * Alias for fill().
13851 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13853 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13854 * var tpl = Roo.MasterTemplate.from('element-id');
13855 * @param {String/HTMLElement} el
13856 * @param {Object} config
13859 Roo.MasterTemplate.from = function(el, config){
13860 el = Roo.getDom(el);
13861 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13864 * Ext JS Library 1.1.1
13865 * Copyright(c) 2006-2007, Ext JS, LLC.
13867 * Originally Released Under LGPL - original licence link has changed is not relivant.
13870 * <script type="text/javascript">
13875 * @class Roo.util.CSS
13876 * Utility class for manipulating CSS rules
13879 Roo.util.CSS = function(){
13881 var doc = document;
13883 var camelRe = /(-[a-z])/gi;
13884 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13888 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13889 * tag and appended to the HEAD of the document.
13890 * @param {String|Object} cssText The text containing the css rules
13891 * @param {String} id An id to add to the stylesheet for later removal
13892 * @return {StyleSheet}
13894 createStyleSheet : function(cssText, id){
13896 var head = doc.getElementsByTagName("head")[0];
13897 var nrules = doc.createElement("style");
13898 nrules.setAttribute("type", "text/css");
13900 nrules.setAttribute("id", id);
13902 if (typeof(cssText) != 'string') {
13903 // support object maps..
13904 // not sure if this a good idea..
13905 // perhaps it should be merged with the general css handling
13906 // and handle js style props.
13907 var cssTextNew = [];
13908 for(var n in cssText) {
13910 for(var k in cssText[n]) {
13911 citems.push( k + ' : ' +cssText[n][k] + ';' );
13913 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13916 cssText = cssTextNew.join("\n");
13922 head.appendChild(nrules);
13923 ss = nrules.styleSheet;
13924 ss.cssText = cssText;
13927 nrules.appendChild(doc.createTextNode(cssText));
13929 nrules.cssText = cssText;
13931 head.appendChild(nrules);
13932 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13934 this.cacheStyleSheet(ss);
13939 * Removes a style or link tag by id
13940 * @param {String} id The id of the tag
13942 removeStyleSheet : function(id){
13943 var existing = doc.getElementById(id);
13945 existing.parentNode.removeChild(existing);
13950 * Dynamically swaps an existing stylesheet reference for a new one
13951 * @param {String} id The id of an existing link tag to remove
13952 * @param {String} url The href of the new stylesheet to include
13954 swapStyleSheet : function(id, url){
13955 this.removeStyleSheet(id);
13956 var ss = doc.createElement("link");
13957 ss.setAttribute("rel", "stylesheet");
13958 ss.setAttribute("type", "text/css");
13959 ss.setAttribute("id", id);
13960 ss.setAttribute("href", url);
13961 doc.getElementsByTagName("head")[0].appendChild(ss);
13965 * Refresh the rule cache if you have dynamically added stylesheets
13966 * @return {Object} An object (hash) of rules indexed by selector
13968 refreshCache : function(){
13969 return this.getRules(true);
13973 cacheStyleSheet : function(stylesheet){
13977 try{// try catch for cross domain access issue
13978 var ssRules = stylesheet.cssRules || stylesheet.rules;
13979 for(var j = ssRules.length-1; j >= 0; --j){
13980 rules[ssRules[j].selectorText] = ssRules[j];
13986 * Gets all css rules for the document
13987 * @param {Boolean} refreshCache true to refresh the internal cache
13988 * @return {Object} An object (hash) of rules indexed by selector
13990 getRules : function(refreshCache){
13991 if(rules == null || refreshCache){
13993 var ds = doc.styleSheets;
13994 for(var i =0, len = ds.length; i < len; i++){
13996 this.cacheStyleSheet(ds[i]);
14004 * Gets an an individual CSS rule by selector(s)
14005 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14006 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14007 * @return {CSSRule} The CSS rule or null if one is not found
14009 getRule : function(selector, refreshCache){
14010 var rs = this.getRules(refreshCache);
14011 if(!(selector instanceof Array)){
14012 return rs[selector];
14014 for(var i = 0; i < selector.length; i++){
14015 if(rs[selector[i]]){
14016 return rs[selector[i]];
14024 * Updates a rule property
14025 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14026 * @param {String} property The css property
14027 * @param {String} value The new value for the property
14028 * @return {Boolean} true If a rule was found and updated
14030 updateRule : function(selector, property, value){
14031 if(!(selector instanceof Array)){
14032 var rule = this.getRule(selector);
14034 rule.style[property.replace(camelRe, camelFn)] = value;
14038 for(var i = 0; i < selector.length; i++){
14039 if(this.updateRule(selector[i], property, value)){
14049 * Ext JS Library 1.1.1
14050 * Copyright(c) 2006-2007, Ext JS, LLC.
14052 * Originally Released Under LGPL - original licence link has changed is not relivant.
14055 * <script type="text/javascript">
14061 * @class Roo.util.ClickRepeater
14062 * @extends Roo.util.Observable
14064 * A wrapper class which can be applied to any element. Fires a "click" event while the
14065 * mouse is pressed. The interval between firings may be specified in the config but
14066 * defaults to 10 milliseconds.
14068 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14070 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14071 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14072 * Similar to an autorepeat key delay.
14073 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14074 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14075 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14076 * "interval" and "delay" are ignored. "immediate" is honored.
14077 * @cfg {Boolean} preventDefault True to prevent the default click event
14078 * @cfg {Boolean} stopDefault True to stop the default click event
14081 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14082 * 2007-02-02 jvs Renamed to ClickRepeater
14083 * 2007-02-03 jvs Modifications for FF Mac and Safari
14086 * @param {String/HTMLElement/Element} el The element to listen on
14087 * @param {Object} config
14089 Roo.util.ClickRepeater = function(el, config)
14091 this.el = Roo.get(el);
14092 this.el.unselectable();
14094 Roo.apply(this, config);
14099 * Fires when the mouse button is depressed.
14100 * @param {Roo.util.ClickRepeater} this
14102 "mousedown" : true,
14105 * Fires on a specified interval during the time the element is pressed.
14106 * @param {Roo.util.ClickRepeater} this
14111 * Fires when the mouse key is released.
14112 * @param {Roo.util.ClickRepeater} this
14117 this.el.on("mousedown", this.handleMouseDown, this);
14118 if(this.preventDefault || this.stopDefault){
14119 this.el.on("click", function(e){
14120 if(this.preventDefault){
14121 e.preventDefault();
14123 if(this.stopDefault){
14129 // allow inline handler
14131 this.on("click", this.handler, this.scope || this);
14134 Roo.util.ClickRepeater.superclass.constructor.call(this);
14137 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14140 preventDefault : true,
14141 stopDefault : false,
14145 handleMouseDown : function(){
14146 clearTimeout(this.timer);
14148 if(this.pressClass){
14149 this.el.addClass(this.pressClass);
14151 this.mousedownTime = new Date();
14153 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14154 this.el.on("mouseout", this.handleMouseOut, this);
14156 this.fireEvent("mousedown", this);
14157 this.fireEvent("click", this);
14159 this.timer = this.click.defer(this.delay || this.interval, this);
14163 click : function(){
14164 this.fireEvent("click", this);
14165 this.timer = this.click.defer(this.getInterval(), this);
14169 getInterval: function(){
14170 if(!this.accelerate){
14171 return this.interval;
14173 var pressTime = this.mousedownTime.getElapsed();
14174 if(pressTime < 500){
14176 }else if(pressTime < 1700){
14178 }else if(pressTime < 2600){
14180 }else if(pressTime < 3500){
14182 }else if(pressTime < 4400){
14184 }else if(pressTime < 5300){
14186 }else if(pressTime < 6200){
14194 handleMouseOut : function(){
14195 clearTimeout(this.timer);
14196 if(this.pressClass){
14197 this.el.removeClass(this.pressClass);
14199 this.el.on("mouseover", this.handleMouseReturn, this);
14203 handleMouseReturn : function(){
14204 this.el.un("mouseover", this.handleMouseReturn);
14205 if(this.pressClass){
14206 this.el.addClass(this.pressClass);
14212 handleMouseUp : function(){
14213 clearTimeout(this.timer);
14214 this.el.un("mouseover", this.handleMouseReturn);
14215 this.el.un("mouseout", this.handleMouseOut);
14216 Roo.get(document).un("mouseup", this.handleMouseUp);
14217 this.el.removeClass(this.pressClass);
14218 this.fireEvent("mouseup", this);
14222 * Ext JS Library 1.1.1
14223 * Copyright(c) 2006-2007, Ext JS, LLC.
14225 * Originally Released Under LGPL - original licence link has changed is not relivant.
14228 * <script type="text/javascript">
14233 * @class Roo.KeyNav
14234 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14235 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14236 * way to implement custom navigation schemes for any UI component.</p>
14237 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14238 * pageUp, pageDown, del, home, end. Usage:</p>
14240 var nav = new Roo.KeyNav("my-element", {
14241 "left" : function(e){
14242 this.moveLeft(e.ctrlKey);
14244 "right" : function(e){
14245 this.moveRight(e.ctrlKey);
14247 "enter" : function(e){
14254 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14255 * @param {Object} config The config
14257 Roo.KeyNav = function(el, config){
14258 this.el = Roo.get(el);
14259 Roo.apply(this, config);
14260 if(!this.disabled){
14261 this.disabled = true;
14266 Roo.KeyNav.prototype = {
14268 * @cfg {Boolean} disabled
14269 * True to disable this KeyNav instance (defaults to false)
14273 * @cfg {String} defaultEventAction
14274 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14275 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14276 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14278 defaultEventAction: "stopEvent",
14280 * @cfg {Boolean} forceKeyDown
14281 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14282 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14283 * handle keydown instead of keypress.
14285 forceKeyDown : false,
14288 prepareEvent : function(e){
14289 var k = e.getKey();
14290 var h = this.keyToHandler[k];
14291 //if(h && this[h]){
14292 // e.stopPropagation();
14294 if(Roo.isSafari && h && k >= 37 && k <= 40){
14300 relay : function(e){
14301 var k = e.getKey();
14302 var h = this.keyToHandler[k];
14304 if(this.doRelay(e, this[h], h) !== true){
14305 e[this.defaultEventAction]();
14311 doRelay : function(e, h, hname){
14312 return h.call(this.scope || this, e);
14315 // possible handlers
14329 // quick lookup hash
14346 * Enable this KeyNav
14348 enable: function(){
14350 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14351 // the EventObject will normalize Safari automatically
14352 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14353 this.el.on("keydown", this.relay, this);
14355 this.el.on("keydown", this.prepareEvent, this);
14356 this.el.on("keypress", this.relay, this);
14358 this.disabled = false;
14363 * Disable this KeyNav
14365 disable: function(){
14366 if(!this.disabled){
14367 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14368 this.el.un("keydown", this.relay);
14370 this.el.un("keydown", this.prepareEvent);
14371 this.el.un("keypress", this.relay);
14373 this.disabled = true;
14378 * Ext JS Library 1.1.1
14379 * Copyright(c) 2006-2007, Ext JS, LLC.
14381 * Originally Released Under LGPL - original licence link has changed is not relivant.
14384 * <script type="text/javascript">
14389 * @class Roo.KeyMap
14390 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14391 * The constructor accepts the same config object as defined by {@link #addBinding}.
14392 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14393 * combination it will call the function with this signature (if the match is a multi-key
14394 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14395 * A KeyMap can also handle a string representation of keys.<br />
14398 // map one key by key code
14399 var map = new Roo.KeyMap("my-element", {
14400 key: 13, // or Roo.EventObject.ENTER
14405 // map multiple keys to one action by string
14406 var map = new Roo.KeyMap("my-element", {
14412 // map multiple keys to multiple actions by strings and array of codes
14413 var map = new Roo.KeyMap("my-element", [
14416 fn: function(){ alert("Return was pressed"); }
14419 fn: function(){ alert('a, b or c was pressed'); }
14424 fn: function(){ alert('Control + shift + tab was pressed.'); }
14428 * <b>Note: A KeyMap starts enabled</b>
14430 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14431 * @param {Object} config The config (see {@link #addBinding})
14432 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14434 Roo.KeyMap = function(el, config, eventName){
14435 this.el = Roo.get(el);
14436 this.eventName = eventName || "keydown";
14437 this.bindings = [];
14439 this.addBinding(config);
14444 Roo.KeyMap.prototype = {
14446 * True to stop the event from bubbling and prevent the default browser action if the
14447 * key was handled by the KeyMap (defaults to false)
14453 * Add a new binding to this KeyMap. The following config object properties are supported:
14455 Property Type Description
14456 ---------- --------------- ----------------------------------------------------------------------
14457 key String/Array A single keycode or an array of keycodes to handle
14458 shift Boolean True to handle key only when shift is pressed (defaults to false)
14459 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14460 alt Boolean True to handle key only when alt is pressed (defaults to false)
14461 fn Function The function to call when KeyMap finds the expected key combination
14462 scope Object The scope of the callback function
14468 var map = new Roo.KeyMap(document, {
14469 key: Roo.EventObject.ENTER,
14474 //Add a new binding to the existing KeyMap later
14482 * @param {Object/Array} config A single KeyMap config or an array of configs
14484 addBinding : function(config){
14485 if(config instanceof Array){
14486 for(var i = 0, len = config.length; i < len; i++){
14487 this.addBinding(config[i]);
14491 var keyCode = config.key,
14492 shift = config.shift,
14493 ctrl = config.ctrl,
14496 scope = config.scope;
14497 if(typeof keyCode == "string"){
14499 var keyString = keyCode.toUpperCase();
14500 for(var j = 0, len = keyString.length; j < len; j++){
14501 ks.push(keyString.charCodeAt(j));
14505 var keyArray = keyCode instanceof Array;
14506 var handler = function(e){
14507 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14508 var k = e.getKey();
14510 for(var i = 0, len = keyCode.length; i < len; i++){
14511 if(keyCode[i] == k){
14512 if(this.stopEvent){
14515 fn.call(scope || window, k, e);
14521 if(this.stopEvent){
14524 fn.call(scope || window, k, e);
14529 this.bindings.push(handler);
14533 * Shorthand for adding a single key listener
14534 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14535 * following options:
14536 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14537 * @param {Function} fn The function to call
14538 * @param {Object} scope (optional) The scope of the function
14540 on : function(key, fn, scope){
14541 var keyCode, shift, ctrl, alt;
14542 if(typeof key == "object" && !(key instanceof Array)){
14561 handleKeyDown : function(e){
14562 if(this.enabled){ //just in case
14563 var b = this.bindings;
14564 for(var i = 0, len = b.length; i < len; i++){
14565 b[i].call(this, e);
14571 * Returns true if this KeyMap is enabled
14572 * @return {Boolean}
14574 isEnabled : function(){
14575 return this.enabled;
14579 * Enables this KeyMap
14581 enable: function(){
14583 this.el.on(this.eventName, this.handleKeyDown, this);
14584 this.enabled = true;
14589 * Disable this KeyMap
14591 disable: function(){
14593 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14594 this.enabled = false;
14599 * Ext JS Library 1.1.1
14600 * Copyright(c) 2006-2007, Ext JS, LLC.
14602 * Originally Released Under LGPL - original licence link has changed is not relivant.
14605 * <script type="text/javascript">
14610 * @class Roo.util.TextMetrics
14611 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14612 * wide, in pixels, a given block of text will be.
14615 Roo.util.TextMetrics = function(){
14619 * Measures the size of the specified text
14620 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14621 * that can affect the size of the rendered text
14622 * @param {String} text The text to measure
14623 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14624 * in order to accurately measure the text height
14625 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14627 measure : function(el, text, fixedWidth){
14629 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14632 shared.setFixedWidth(fixedWidth || 'auto');
14633 return shared.getSize(text);
14637 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14638 * the overhead of multiple calls to initialize the style properties on each measurement.
14639 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14640 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14641 * in order to accurately measure the text height
14642 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14644 createInstance : function(el, fixedWidth){
14645 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14652 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14653 var ml = new Roo.Element(document.createElement('div'));
14654 document.body.appendChild(ml.dom);
14655 ml.position('absolute');
14656 ml.setLeftTop(-1000, -1000);
14660 ml.setWidth(fixedWidth);
14665 * Returns the size of the specified text based on the internal element's style and width properties
14666 * @memberOf Roo.util.TextMetrics.Instance#
14667 * @param {String} text The text to measure
14668 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14670 getSize : function(text){
14672 var s = ml.getSize();
14678 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14679 * that can affect the size of the rendered text
14680 * @memberOf Roo.util.TextMetrics.Instance#
14681 * @param {String/HTMLElement} el The element, dom node or id
14683 bind : function(el){
14685 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14690 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14691 * to set a fixed width in order to accurately measure the text height.
14692 * @memberOf Roo.util.TextMetrics.Instance#
14693 * @param {Number} width The width to set on the element
14695 setFixedWidth : function(width){
14696 ml.setWidth(width);
14700 * Returns the measured width of the specified text
14701 * @memberOf Roo.util.TextMetrics.Instance#
14702 * @param {String} text The text to measure
14703 * @return {Number} width The width in pixels
14705 getWidth : function(text){
14706 ml.dom.style.width = 'auto';
14707 return this.getSize(text).width;
14711 * Returns the measured height of the specified text. For multiline text, be sure to call
14712 * {@link #setFixedWidth} if necessary.
14713 * @memberOf Roo.util.TextMetrics.Instance#
14714 * @param {String} text The text to measure
14715 * @return {Number} height The height in pixels
14717 getHeight : function(text){
14718 return this.getSize(text).height;
14722 instance.bind(bindTo);
14727 // backwards compat
14728 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14730 * Ext JS Library 1.1.1
14731 * Copyright(c) 2006-2007, Ext JS, LLC.
14733 * Originally Released Under LGPL - original licence link has changed is not relivant.
14736 * <script type="text/javascript">
14740 * @class Roo.state.Provider
14741 * Abstract base class for state provider implementations. This class provides methods
14742 * for encoding and decoding <b>typed</b> variables including dates and defines the
14743 * Provider interface.
14745 Roo.state.Provider = function(){
14747 * @event statechange
14748 * Fires when a state change occurs.
14749 * @param {Provider} this This state provider
14750 * @param {String} key The state key which was changed
14751 * @param {String} value The encoded value for the state
14754 "statechange": true
14757 Roo.state.Provider.superclass.constructor.call(this);
14759 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14761 * Returns the current value for a key
14762 * @param {String} name The key name
14763 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14764 * @return {Mixed} The state data
14766 get : function(name, defaultValue){
14767 return typeof this.state[name] == "undefined" ?
14768 defaultValue : this.state[name];
14772 * Clears a value from the state
14773 * @param {String} name The key name
14775 clear : function(name){
14776 delete this.state[name];
14777 this.fireEvent("statechange", this, name, null);
14781 * Sets the value for a key
14782 * @param {String} name The key name
14783 * @param {Mixed} value The value to set
14785 set : function(name, value){
14786 this.state[name] = value;
14787 this.fireEvent("statechange", this, name, value);
14791 * Decodes a string previously encoded with {@link #encodeValue}.
14792 * @param {String} value The value to decode
14793 * @return {Mixed} The decoded value
14795 decodeValue : function(cookie){
14796 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14797 var matches = re.exec(unescape(cookie));
14798 if(!matches || !matches[1]) return; // non state cookie
14799 var type = matches[1];
14800 var v = matches[2];
14803 return parseFloat(v);
14805 return new Date(Date.parse(v));
14810 var values = v.split("^");
14811 for(var i = 0, len = values.length; i < len; i++){
14812 all.push(this.decodeValue(values[i]));
14817 var values = v.split("^");
14818 for(var i = 0, len = values.length; i < len; i++){
14819 var kv = values[i].split("=");
14820 all[kv[0]] = this.decodeValue(kv[1]);
14829 * Encodes a value including type information. Decode with {@link #decodeValue}.
14830 * @param {Mixed} value The value to encode
14831 * @return {String} The encoded value
14833 encodeValue : function(v){
14835 if(typeof v == "number"){
14837 }else if(typeof v == "boolean"){
14838 enc = "b:" + (v ? "1" : "0");
14839 }else if(v instanceof Date){
14840 enc = "d:" + v.toGMTString();
14841 }else if(v instanceof Array){
14843 for(var i = 0, len = v.length; i < len; i++){
14844 flat += this.encodeValue(v[i]);
14845 if(i != len-1) flat += "^";
14848 }else if(typeof v == "object"){
14851 if(typeof v[key] != "function"){
14852 flat += key + "=" + this.encodeValue(v[key]) + "^";
14855 enc = "o:" + flat.substring(0, flat.length-1);
14859 return escape(enc);
14865 * Ext JS Library 1.1.1
14866 * Copyright(c) 2006-2007, Ext JS, LLC.
14868 * Originally Released Under LGPL - original licence link has changed is not relivant.
14871 * <script type="text/javascript">
14874 * @class Roo.state.Manager
14875 * This is the global state manager. By default all components that are "state aware" check this class
14876 * for state information if you don't pass them a custom state provider. In order for this class
14877 * to be useful, it must be initialized with a provider when your application initializes.
14879 // in your initialization function
14881 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14883 // supposed you have a {@link Roo.BorderLayout}
14884 var layout = new Roo.BorderLayout(...);
14885 layout.restoreState();
14886 // or a {Roo.BasicDialog}
14887 var dialog = new Roo.BasicDialog(...);
14888 dialog.restoreState();
14892 Roo.state.Manager = function(){
14893 var provider = new Roo.state.Provider();
14897 * Configures the default state provider for your application
14898 * @param {Provider} stateProvider The state provider to set
14900 setProvider : function(stateProvider){
14901 provider = stateProvider;
14905 * Returns the current value for a key
14906 * @param {String} name The key name
14907 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14908 * @return {Mixed} The state data
14910 get : function(key, defaultValue){
14911 return provider.get(key, defaultValue);
14915 * Sets the value for a key
14916 * @param {String} name The key name
14917 * @param {Mixed} value The state data
14919 set : function(key, value){
14920 provider.set(key, value);
14924 * Clears a value from the state
14925 * @param {String} name The key name
14927 clear : function(key){
14928 provider.clear(key);
14932 * Gets the currently configured state provider
14933 * @return {Provider} The state provider
14935 getProvider : function(){
14942 * Ext JS Library 1.1.1
14943 * Copyright(c) 2006-2007, Ext JS, LLC.
14945 * Originally Released Under LGPL - original licence link has changed is not relivant.
14948 * <script type="text/javascript">
14951 * @class Roo.state.CookieProvider
14952 * @extends Roo.state.Provider
14953 * The default Provider implementation which saves state via cookies.
14956 var cp = new Roo.state.CookieProvider({
14958 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14959 domain: "roojs.com"
14961 Roo.state.Manager.setProvider(cp);
14963 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14964 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14965 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14966 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14967 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14968 * domain the page is running on including the 'www' like 'www.roojs.com')
14969 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14971 * Create a new CookieProvider
14972 * @param {Object} config The configuration object
14974 Roo.state.CookieProvider = function(config){
14975 Roo.state.CookieProvider.superclass.constructor.call(this);
14977 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14978 this.domain = null;
14979 this.secure = false;
14980 Roo.apply(this, config);
14981 this.state = this.readCookies();
14984 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14986 set : function(name, value){
14987 if(typeof value == "undefined" || value === null){
14991 this.setCookie(name, value);
14992 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14996 clear : function(name){
14997 this.clearCookie(name);
14998 Roo.state.CookieProvider.superclass.clear.call(this, name);
15002 readCookies : function(){
15004 var c = document.cookie + ";";
15005 var re = /\s?(.*?)=(.*?);/g;
15007 while((matches = re.exec(c)) != null){
15008 var name = matches[1];
15009 var value = matches[2];
15010 if(name && name.substring(0,3) == "ys-"){
15011 cookies[name.substr(3)] = this.decodeValue(value);
15018 setCookie : function(name, value){
15019 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15020 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15021 ((this.path == null) ? "" : ("; path=" + this.path)) +
15022 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15023 ((this.secure == true) ? "; secure" : "");
15027 clearCookie : function(name){
15028 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15029 ((this.path == null) ? "" : ("; path=" + this.path)) +
15030 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15031 ((this.secure == true) ? "; secure" : "");
15035 * Ext JS Library 1.1.1
15036 * Copyright(c) 2006-2007, Ext JS, LLC.
15038 * Originally Released Under LGPL - original licence link has changed is not relivant.
15041 * <script type="text/javascript">
15046 * @class Roo.ComponentMgr
15047 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15050 Roo.ComponentMgr = function(){
15051 var all = new Roo.util.MixedCollection();
15055 * Registers a component.
15056 * @param {Roo.Component} c The component
15058 register : function(c){
15063 * Unregisters a component.
15064 * @param {Roo.Component} c The component
15066 unregister : function(c){
15071 * Returns a component by id
15072 * @param {String} id The component id
15074 get : function(id){
15075 return all.get(id);
15079 * Registers a function that will be called when a specified component is added to ComponentMgr
15080 * @param {String} id The component id
15081 * @param {Funtction} fn The callback function
15082 * @param {Object} scope The scope of the callback
15084 onAvailable : function(id, fn, scope){
15085 all.on("add", function(index, o){
15087 fn.call(scope || o, o);
15088 all.un("add", fn, scope);
15095 * Ext JS Library 1.1.1
15096 * Copyright(c) 2006-2007, Ext JS, LLC.
15098 * Originally Released Under LGPL - original licence link has changed is not relivant.
15101 * <script type="text/javascript">
15105 * @class Roo.Component
15106 * @extends Roo.util.Observable
15107 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15108 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15109 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15110 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15111 * All visual components (widgets) that require rendering into a layout should subclass Component.
15113 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15114 * 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
15115 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15117 Roo.Component = function(config){
15118 config = config || {};
15119 if(config.tagName || config.dom || typeof config == "string"){ // element object
15120 config = {el: config, id: config.id || config};
15122 this.initialConfig = config;
15124 Roo.apply(this, config);
15128 * Fires after the component is disabled.
15129 * @param {Roo.Component} this
15134 * Fires after the component is enabled.
15135 * @param {Roo.Component} this
15139 * @event beforeshow
15140 * Fires before the component is shown. Return false to stop the show.
15141 * @param {Roo.Component} this
15146 * Fires after the component is shown.
15147 * @param {Roo.Component} this
15151 * @event beforehide
15152 * Fires before the component is hidden. Return false to stop the hide.
15153 * @param {Roo.Component} this
15158 * Fires after the component is hidden.
15159 * @param {Roo.Component} this
15163 * @event beforerender
15164 * Fires before the component is rendered. Return false to stop the render.
15165 * @param {Roo.Component} this
15167 beforerender : true,
15170 * Fires after the component is rendered.
15171 * @param {Roo.Component} this
15175 * @event beforedestroy
15176 * Fires before the component is destroyed. Return false to stop the destroy.
15177 * @param {Roo.Component} this
15179 beforedestroy : true,
15182 * Fires after the component is destroyed.
15183 * @param {Roo.Component} this
15188 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15190 Roo.ComponentMgr.register(this);
15191 Roo.Component.superclass.constructor.call(this);
15192 this.initComponent();
15193 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15194 this.render(this.renderTo);
15195 delete this.renderTo;
15200 Roo.Component.AUTO_ID = 1000;
15202 Roo.extend(Roo.Component, Roo.util.Observable, {
15204 * @scope Roo.Component.prototype
15206 * true if this component is hidden. Read-only.
15211 * true if this component is disabled. Read-only.
15216 * true if this component has been rendered. Read-only.
15220 /** @cfg {String} disableClass
15221 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15223 disabledClass : "x-item-disabled",
15224 /** @cfg {Boolean} allowDomMove
15225 * Whether the component can move the Dom node when rendering (defaults to true).
15227 allowDomMove : true,
15228 /** @cfg {String} hideMode (display|visibility)
15229 * How this component should hidden. Supported values are
15230 * "visibility" (css visibility), "offsets" (negative offset position) and
15231 * "display" (css display) - defaults to "display".
15233 hideMode: 'display',
15236 ctype : "Roo.Component",
15239 * @cfg {String} actionMode
15240 * which property holds the element that used for hide() / show() / disable() / enable()
15246 getActionEl : function(){
15247 return this[this.actionMode];
15250 initComponent : Roo.emptyFn,
15252 * If this is a lazy rendering component, render it to its container element.
15253 * @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.
15255 render : function(container, position){
15256 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15257 if(!container && this.el){
15258 this.el = Roo.get(this.el);
15259 container = this.el.dom.parentNode;
15260 this.allowDomMove = false;
15262 this.container = Roo.get(container);
15263 this.rendered = true;
15264 if(position !== undefined){
15265 if(typeof position == 'number'){
15266 position = this.container.dom.childNodes[position];
15268 position = Roo.getDom(position);
15271 this.onRender(this.container, position || null);
15273 this.el.addClass(this.cls);
15277 this.el.applyStyles(this.style);
15280 this.fireEvent("render", this);
15281 this.afterRender(this.container);
15293 // default function is not really useful
15294 onRender : function(ct, position){
15296 this.el = Roo.get(this.el);
15297 if(this.allowDomMove !== false){
15298 ct.dom.insertBefore(this.el.dom, position);
15304 getAutoCreate : function(){
15305 var cfg = typeof this.autoCreate == "object" ?
15306 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15307 if(this.id && !cfg.id){
15314 afterRender : Roo.emptyFn,
15317 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15318 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15320 destroy : function(){
15321 if(this.fireEvent("beforedestroy", this) !== false){
15322 this.purgeListeners();
15323 this.beforeDestroy();
15325 this.el.removeAllListeners();
15327 if(this.actionMode == "container"){
15328 this.container.remove();
15332 Roo.ComponentMgr.unregister(this);
15333 this.fireEvent("destroy", this);
15338 beforeDestroy : function(){
15343 onDestroy : function(){
15348 * Returns the underlying {@link Roo.Element}.
15349 * @return {Roo.Element} The element
15351 getEl : function(){
15356 * Returns the id of this component.
15359 getId : function(){
15364 * Try to focus this component.
15365 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15366 * @return {Roo.Component} this
15368 focus : function(selectText){
15371 if(selectText === true){
15372 this.el.dom.select();
15387 * Disable this component.
15388 * @return {Roo.Component} this
15390 disable : function(){
15394 this.disabled = true;
15395 this.fireEvent("disable", this);
15400 onDisable : function(){
15401 this.getActionEl().addClass(this.disabledClass);
15402 this.el.dom.disabled = true;
15406 * Enable this component.
15407 * @return {Roo.Component} this
15409 enable : function(){
15413 this.disabled = false;
15414 this.fireEvent("enable", this);
15419 onEnable : function(){
15420 this.getActionEl().removeClass(this.disabledClass);
15421 this.el.dom.disabled = false;
15425 * Convenience function for setting disabled/enabled by boolean.
15426 * @param {Boolean} disabled
15428 setDisabled : function(disabled){
15429 this[disabled ? "disable" : "enable"]();
15433 * Show this component.
15434 * @return {Roo.Component} this
15437 if(this.fireEvent("beforeshow", this) !== false){
15438 this.hidden = false;
15442 this.fireEvent("show", this);
15448 onShow : function(){
15449 var ae = this.getActionEl();
15450 if(this.hideMode == 'visibility'){
15451 ae.dom.style.visibility = "visible";
15452 }else if(this.hideMode == 'offsets'){
15453 ae.removeClass('x-hidden');
15455 ae.dom.style.display = "";
15460 * Hide this component.
15461 * @return {Roo.Component} this
15464 if(this.fireEvent("beforehide", this) !== false){
15465 this.hidden = true;
15469 this.fireEvent("hide", this);
15475 onHide : function(){
15476 var ae = this.getActionEl();
15477 if(this.hideMode == 'visibility'){
15478 ae.dom.style.visibility = "hidden";
15479 }else if(this.hideMode == 'offsets'){
15480 ae.addClass('x-hidden');
15482 ae.dom.style.display = "none";
15487 * Convenience function to hide or show this component by boolean.
15488 * @param {Boolean} visible True to show, false to hide
15489 * @return {Roo.Component} this
15491 setVisible: function(visible){
15501 * Returns true if this component is visible.
15503 isVisible : function(){
15504 return this.getActionEl().isVisible();
15507 cloneConfig : function(overrides){
15508 overrides = overrides || {};
15509 var id = overrides.id || Roo.id();
15510 var cfg = Roo.applyIf(overrides, this.initialConfig);
15511 cfg.id = id; // prevent dup id
15512 return new this.constructor(cfg);
15516 * Ext JS Library 1.1.1
15517 * Copyright(c) 2006-2007, Ext JS, LLC.
15519 * Originally Released Under LGPL - original licence link has changed is not relivant.
15522 * <script type="text/javascript">
15526 * @class Roo.BoxComponent
15527 * @extends Roo.Component
15528 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15529 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15530 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15531 * layout containers.
15533 * @param {Roo.Element/String/Object} config The configuration options.
15535 Roo.BoxComponent = function(config){
15536 Roo.Component.call(this, config);
15540 * Fires after the component is resized.
15541 * @param {Roo.Component} this
15542 * @param {Number} adjWidth The box-adjusted width that was set
15543 * @param {Number} adjHeight The box-adjusted height that was set
15544 * @param {Number} rawWidth The width that was originally specified
15545 * @param {Number} rawHeight The height that was originally specified
15550 * Fires after the component is moved.
15551 * @param {Roo.Component} this
15552 * @param {Number} x The new x position
15553 * @param {Number} y The new y position
15559 Roo.extend(Roo.BoxComponent, Roo.Component, {
15560 // private, set in afterRender to signify that the component has been rendered
15562 // private, used to defer height settings to subclasses
15563 deferHeight: false,
15564 /** @cfg {Number} width
15565 * width (optional) size of component
15567 /** @cfg {Number} height
15568 * height (optional) size of component
15572 * Sets the width and height of the component. This method fires the resize event. This method can accept
15573 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15574 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15575 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15576 * @return {Roo.BoxComponent} this
15578 setSize : function(w, h){
15579 // support for standard size objects
15580 if(typeof w == 'object'){
15585 if(!this.boxReady){
15591 // prevent recalcs when not needed
15592 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15595 this.lastSize = {width: w, height: h};
15597 var adj = this.adjustSize(w, h);
15598 var aw = adj.width, ah = adj.height;
15599 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15600 var rz = this.getResizeEl();
15601 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15602 rz.setSize(aw, ah);
15603 }else if(!this.deferHeight && ah !== undefined){
15605 }else if(aw !== undefined){
15608 this.onResize(aw, ah, w, h);
15609 this.fireEvent('resize', this, aw, ah, w, h);
15615 * Gets the current size of the component's underlying element.
15616 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15618 getSize : function(){
15619 return this.el.getSize();
15623 * Gets the current XY position of the component's underlying element.
15624 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15625 * @return {Array} The XY position of the element (e.g., [100, 200])
15627 getPosition : function(local){
15628 if(local === true){
15629 return [this.el.getLeft(true), this.el.getTop(true)];
15631 return this.xy || this.el.getXY();
15635 * Gets the current box measurements of the component's underlying element.
15636 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15637 * @returns {Object} box An object in the format {x, y, width, height}
15639 getBox : function(local){
15640 var s = this.el.getSize();
15642 s.x = this.el.getLeft(true);
15643 s.y = this.el.getTop(true);
15645 var xy = this.xy || this.el.getXY();
15653 * Sets the current box measurements of the component's underlying element.
15654 * @param {Object} box An object in the format {x, y, width, height}
15655 * @returns {Roo.BoxComponent} this
15657 updateBox : function(box){
15658 this.setSize(box.width, box.height);
15659 this.setPagePosition(box.x, box.y);
15664 getResizeEl : function(){
15665 return this.resizeEl || this.el;
15669 getPositionEl : function(){
15670 return this.positionEl || this.el;
15674 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15675 * This method fires the move event.
15676 * @param {Number} left The new left
15677 * @param {Number} top The new top
15678 * @returns {Roo.BoxComponent} this
15680 setPosition : function(x, y){
15683 if(!this.boxReady){
15686 var adj = this.adjustPosition(x, y);
15687 var ax = adj.x, ay = adj.y;
15689 var el = this.getPositionEl();
15690 if(ax !== undefined || ay !== undefined){
15691 if(ax !== undefined && ay !== undefined){
15692 el.setLeftTop(ax, ay);
15693 }else if(ax !== undefined){
15695 }else if(ay !== undefined){
15698 this.onPosition(ax, ay);
15699 this.fireEvent('move', this, ax, ay);
15705 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15706 * This method fires the move event.
15707 * @param {Number} x The new x position
15708 * @param {Number} y The new y position
15709 * @returns {Roo.BoxComponent} this
15711 setPagePosition : function(x, y){
15714 if(!this.boxReady){
15717 if(x === undefined || y === undefined){ // cannot translate undefined points
15720 var p = this.el.translatePoints(x, y);
15721 this.setPosition(p.left, p.top);
15726 onRender : function(ct, position){
15727 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15729 this.resizeEl = Roo.get(this.resizeEl);
15731 if(this.positionEl){
15732 this.positionEl = Roo.get(this.positionEl);
15737 afterRender : function(){
15738 Roo.BoxComponent.superclass.afterRender.call(this);
15739 this.boxReady = true;
15740 this.setSize(this.width, this.height);
15741 if(this.x || this.y){
15742 this.setPosition(this.x, this.y);
15744 if(this.pageX || this.pageY){
15745 this.setPagePosition(this.pageX, this.pageY);
15750 * Force the component's size to recalculate based on the underlying element's current height and width.
15751 * @returns {Roo.BoxComponent} this
15753 syncSize : function(){
15754 delete this.lastSize;
15755 this.setSize(this.el.getWidth(), this.el.getHeight());
15760 * Called after the component is resized, this method is empty by default but can be implemented by any
15761 * subclass that needs to perform custom logic after a resize occurs.
15762 * @param {Number} adjWidth The box-adjusted width that was set
15763 * @param {Number} adjHeight The box-adjusted height that was set
15764 * @param {Number} rawWidth The width that was originally specified
15765 * @param {Number} rawHeight The height that was originally specified
15767 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15772 * Called after the component is moved, this method is empty by default but can be implemented by any
15773 * subclass that needs to perform custom logic after a move occurs.
15774 * @param {Number} x The new x position
15775 * @param {Number} y The new y position
15777 onPosition : function(x, y){
15782 adjustSize : function(w, h){
15783 if(this.autoWidth){
15786 if(this.autoHeight){
15789 return {width : w, height: h};
15793 adjustPosition : function(x, y){
15794 return {x : x, y: y};
15797 * Original code for Roojs - LGPL
15798 * <script type="text/javascript">
15802 * @class Roo.XComponent
15803 * A delayed Element creator...
15804 * Or a way to group chunks of interface together.
15805 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15806 * used in conjunction with XComponent.build() it will create an instance of each element,
15807 * then call addxtype() to build the User interface.
15809 * Mypart.xyx = new Roo.XComponent({
15811 parent : 'Mypart.xyz', // empty == document.element.!!
15815 disabled : function() {}
15817 tree : function() { // return an tree of xtype declared components
15821 xtype : 'NestedLayoutPanel',
15828 * It can be used to build a big heiracy, with parent etc.
15829 * or you can just use this to render a single compoent to a dom element
15830 * MYPART.render(Roo.Element | String(id) | dom_element )
15837 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15838 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15840 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15842 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15843 * - if mulitple topModules exist, the last one is defined as the top module.
15847 * When the top level or multiple modules are to embedded into a existing HTML page,
15848 * the parent element can container '#id' of the element where the module will be drawn.
15852 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15853 * it relies more on a include mechanism, where sub modules are included into an outer page.
15854 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15856 * Bootstrap Roo Included elements
15858 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15859 * hence confusing the component builder as it thinks there are multiple top level elements.
15863 * @extends Roo.util.Observable
15865 * @param cfg {Object} configuration of component
15868 Roo.XComponent = function(cfg) {
15869 Roo.apply(this, cfg);
15873 * Fires when this the componnt is built
15874 * @param {Roo.XComponent} c the component
15879 this.region = this.region || 'center'; // default..
15880 Roo.XComponent.register(this);
15881 this.modules = false;
15882 this.el = false; // where the layout goes..
15886 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15889 * The created element (with Roo.factory())
15890 * @type {Roo.Layout}
15896 * for BC - use el in new code
15897 * @type {Roo.Layout}
15903 * for BC - use el in new code
15904 * @type {Roo.Layout}
15909 * @cfg {Function|boolean} disabled
15910 * If this module is disabled by some rule, return true from the funtion
15915 * @cfg {String} parent
15916 * Name of parent element which it get xtype added to..
15921 * @cfg {String} order
15922 * Used to set the order in which elements are created (usefull for multiple tabs)
15927 * @cfg {String} name
15928 * String to display while loading.
15932 * @cfg {String} region
15933 * Region to render component to (defaults to center)
15938 * @cfg {Array} items
15939 * A single item array - the first element is the root of the tree..
15940 * It's done this way to stay compatible with the Xtype system...
15946 * The method that retuns the tree of parts that make up this compoennt
15953 * render element to dom or tree
15954 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15957 render : function(el)
15961 var hp = this.parent ? 1 : 0;
15962 Roo.debug && Roo.log(this);
15964 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15965 // if parent is a '#.....' string, then let's use that..
15966 var ename = this.parent.substr(1);
15967 this.parent = false;
15968 Roo.debug && Roo.log(ename);
15970 case 'bootstrap-body' :
15971 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15972 this.parent = { el : new Roo.bootstrap.Body() };
15973 Roo.debug && Roo.log("setting el to doc body");
15976 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15980 this.parent = { el : true};
15983 el = Roo.get(ename);
15988 if (!el && !this.parent) {
15989 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15993 Roo.debug && Roo.log("EL:");
15994 Roo.debug && Roo.log(el);
15995 Roo.debug && Roo.log("this.parent.el:");
15996 Roo.debug && Roo.log(this.parent.el);
15998 var tree = this._tree ? this._tree() : this.tree();
16000 // altertive root elements ??? - we need a better way to indicate these.
16001 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16002 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16004 if (!this.parent && is_alt) {
16005 //el = Roo.get(document.body);
16006 this.parent = { el : true };
16011 if (!this.parent) {
16013 Roo.debug && Roo.log("no parent - creating one");
16015 el = el ? Roo.get(el) : false;
16017 // it's a top level one..
16019 el : new Roo.BorderLayout(el || document.body, {
16025 tabPosition: 'top',
16026 //resizeTabs: true,
16027 alwaysShowTabs: el && hp? false : true,
16028 hideTabs: el || !hp ? true : false,
16035 if (!this.parent.el) {
16036 // probably an old style ctor, which has been disabled.
16040 // The 'tree' method is '_tree now'
16042 tree.region = tree.region || this.region;
16044 if (this.parent.el === true) {
16045 // bootstrap... - body..
16046 this.parent.el = Roo.factory(tree);
16049 this.el = this.parent.el.addxtype(tree);
16050 this.fireEvent('built', this);
16052 this.panel = this.el;
16053 this.layout = this.panel.layout;
16054 this.parentLayout = this.parent.layout || false;
16060 Roo.apply(Roo.XComponent, {
16062 * @property hideProgress
16063 * true to disable the building progress bar.. usefull on single page renders.
16066 hideProgress : false,
16068 * @property buildCompleted
16069 * True when the builder has completed building the interface.
16072 buildCompleted : false,
16075 * @property topModule
16076 * the upper most module - uses document.element as it's constructor.
16083 * @property modules
16084 * array of modules to be created by registration system.
16085 * @type {Array} of Roo.XComponent
16090 * @property elmodules
16091 * array of modules to be created by which use #ID
16092 * @type {Array} of Roo.XComponent
16098 * @property build_from_html
16099 * Build elements from html - used by bootstrap HTML stuff
16100 * - this is cleared after build is completed
16101 * @type {boolean} true (default false)
16104 build_from_html : false,
16107 * Register components to be built later.
16109 * This solves the following issues
16110 * - Building is not done on page load, but after an authentication process has occured.
16111 * - Interface elements are registered on page load
16112 * - Parent Interface elements may not be loaded before child, so this handles that..
16119 module : 'Pman.Tab.projectMgr',
16121 parent : 'Pman.layout',
16122 disabled : false, // or use a function..
16125 * * @param {Object} details about module
16127 register : function(obj) {
16129 Roo.XComponent.event.fireEvent('register', obj);
16130 switch(typeof(obj.disabled) ) {
16136 if ( obj.disabled() ) {
16142 if (obj.disabled) {
16148 this.modules.push(obj);
16152 * convert a string to an object..
16153 * eg. 'AAA.BBB' -> finds AAA.BBB
16157 toObject : function(str)
16159 if (!str || typeof(str) == 'object') {
16162 if (str.substring(0,1) == '#') {
16166 var ar = str.split('.');
16171 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16173 throw "Module not found : " + str;
16177 throw "Module not found : " + str;
16179 Roo.each(ar, function(e) {
16180 if (typeof(o[e]) == 'undefined') {
16181 throw "Module not found : " + str;
16192 * move modules into their correct place in the tree..
16195 preBuild : function ()
16198 Roo.each(this.modules , function (obj)
16200 Roo.XComponent.event.fireEvent('beforebuild', obj);
16202 var opar = obj.parent;
16204 obj.parent = this.toObject(opar);
16206 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16211 Roo.debug && Roo.log("GOT top level module");
16212 Roo.debug && Roo.log(obj);
16213 obj.modules = new Roo.util.MixedCollection(false,
16214 function(o) { return o.order + '' }
16216 this.topModule = obj;
16219 // parent is a string (usually a dom element name..)
16220 if (typeof(obj.parent) == 'string') {
16221 this.elmodules.push(obj);
16224 if (obj.parent.constructor != Roo.XComponent) {
16225 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16227 if (!obj.parent.modules) {
16228 obj.parent.modules = new Roo.util.MixedCollection(false,
16229 function(o) { return o.order + '' }
16232 if (obj.parent.disabled) {
16233 obj.disabled = true;
16235 obj.parent.modules.add(obj);
16240 * make a list of modules to build.
16241 * @return {Array} list of modules.
16244 buildOrder : function()
16247 var cmp = function(a,b) {
16248 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16250 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16251 throw "No top level modules to build";
16254 // make a flat list in order of modules to build.
16255 var mods = this.topModule ? [ this.topModule ] : [];
16258 // elmodules (is a list of DOM based modules )
16259 Roo.each(this.elmodules, function(e) {
16261 if (!this.topModule &&
16262 typeof(e.parent) == 'string' &&
16263 e.parent.substring(0,1) == '#' &&
16264 Roo.get(e.parent.substr(1))
16267 _this.topModule = e;
16273 // add modules to their parents..
16274 var addMod = function(m) {
16275 Roo.debug && Roo.log("build Order: add: " + m.name);
16278 if (m.modules && !m.disabled) {
16279 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16280 m.modules.keySort('ASC', cmp );
16281 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16283 m.modules.each(addMod);
16285 Roo.debug && Roo.log("build Order: no child modules");
16287 // not sure if this is used any more..
16289 m.finalize.name = m.name + " (clean up) ";
16290 mods.push(m.finalize);
16294 if (this.topModule && this.topModule.modules) {
16295 this.topModule.modules.keySort('ASC', cmp );
16296 this.topModule.modules.each(addMod);
16302 * Build the registered modules.
16303 * @param {Object} parent element.
16304 * @param {Function} optional method to call after module has been added.
16308 build : function(opts)
16311 if (typeof(opts) != 'undefined') {
16312 Roo.apply(this,opts);
16316 var mods = this.buildOrder();
16318 //this.allmods = mods;
16319 //Roo.debug && Roo.log(mods);
16321 if (!mods.length) { // should not happen
16322 throw "NO modules!!!";
16326 var msg = "Building Interface...";
16327 // flash it up as modal - so we store the mask!?
16328 if (!this.hideProgress && Roo.MessageBox) {
16329 Roo.MessageBox.show({ title: 'loading' });
16330 Roo.MessageBox.show({
16331 title: "Please wait...",
16340 var total = mods.length;
16343 var progressRun = function() {
16344 if (!mods.length) {
16345 Roo.debug && Roo.log('hide?');
16346 if (!this.hideProgress && Roo.MessageBox) {
16347 Roo.MessageBox.hide();
16349 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16351 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16357 var m = mods.shift();
16360 Roo.debug && Roo.log(m);
16361 // not sure if this is supported any more.. - modules that are are just function
16362 if (typeof(m) == 'function') {
16364 return progressRun.defer(10, _this);
16368 msg = "Building Interface " + (total - mods.length) +
16370 (m.name ? (' - ' + m.name) : '');
16371 Roo.debug && Roo.log(msg);
16372 if (!this.hideProgress && Roo.MessageBox) {
16373 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16377 // is the module disabled?
16378 var disabled = (typeof(m.disabled) == 'function') ?
16379 m.disabled.call(m.module.disabled) : m.disabled;
16383 return progressRun(); // we do not update the display!
16391 // it's 10 on top level, and 1 on others??? why...
16392 return progressRun.defer(10, _this);
16395 progressRun.defer(1, _this);
16409 * wrapper for event.on - aliased later..
16410 * Typically use to register a event handler for register:
16412 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16421 Roo.XComponent.event = new Roo.util.Observable({
16425 * Fires when an Component is registered,
16426 * set the disable property on the Component to stop registration.
16427 * @param {Roo.XComponent} c the component being registerd.
16432 * @event beforebuild
16433 * Fires before each Component is built
16434 * can be used to apply permissions.
16435 * @param {Roo.XComponent} c the component being registerd.
16438 'beforebuild' : true,
16440 * @event buildcomplete
16441 * Fires on the top level element when all elements have been built
16442 * @param {Roo.XComponent} the top level component.
16444 'buildcomplete' : true
16449 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16452 * Ext JS Library 1.1.1
16453 * Copyright(c) 2006-2007, Ext JS, LLC.
16455 * Originally Released Under LGPL - original licence link has changed is not relivant.
16458 * <script type="text/javascript">
16464 * These classes are derivatives of the similarly named classes in the YUI Library.
16465 * The original license:
16466 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16467 * Code licensed under the BSD License:
16468 * http://developer.yahoo.net/yui/license.txt
16473 var Event=Roo.EventManager;
16474 var Dom=Roo.lib.Dom;
16477 * @class Roo.dd.DragDrop
16478 * @extends Roo.util.Observable
16479 * Defines the interface and base operation of items that that can be
16480 * dragged or can be drop targets. It was designed to be extended, overriding
16481 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16482 * Up to three html elements can be associated with a DragDrop instance:
16484 * <li>linked element: the element that is passed into the constructor.
16485 * This is the element which defines the boundaries for interaction with
16486 * other DragDrop objects.</li>
16487 * <li>handle element(s): The drag operation only occurs if the element that
16488 * was clicked matches a handle element. By default this is the linked
16489 * element, but there are times that you will want only a portion of the
16490 * linked element to initiate the drag operation, and the setHandleElId()
16491 * method provides a way to define this.</li>
16492 * <li>drag element: this represents the element that would be moved along
16493 * with the cursor during a drag operation. By default, this is the linked
16494 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16495 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16498 * This class should not be instantiated until the onload event to ensure that
16499 * the associated elements are available.
16500 * The following would define a DragDrop obj that would interact with any
16501 * other DragDrop obj in the "group1" group:
16503 * dd = new Roo.dd.DragDrop("div1", "group1");
16505 * Since none of the event handlers have been implemented, nothing would
16506 * actually happen if you were to run the code above. Normally you would
16507 * override this class or one of the default implementations, but you can
16508 * also override the methods you want on an instance of the class...
16510 * dd.onDragDrop = function(e, id) {
16511 * alert("dd was dropped on " + id);
16515 * @param {String} id of the element that is linked to this instance
16516 * @param {String} sGroup the group of related DragDrop objects
16517 * @param {object} config an object containing configurable attributes
16518 * Valid properties for DragDrop:
16519 * padding, isTarget, maintainOffset, primaryButtonOnly
16521 Roo.dd.DragDrop = function(id, sGroup, config) {
16523 this.init(id, sGroup, config);
16528 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16531 * The id of the element associated with this object. This is what we
16532 * refer to as the "linked element" because the size and position of
16533 * this element is used to determine when the drag and drop objects have
16541 * Configuration attributes passed into the constructor
16548 * The id of the element that will be dragged. By default this is same
16549 * as the linked element , but could be changed to another element. Ex:
16551 * @property dragElId
16558 * the id of the element that initiates the drag operation. By default
16559 * this is the linked element, but could be changed to be a child of this
16560 * element. This lets us do things like only starting the drag when the
16561 * header element within the linked html element is clicked.
16562 * @property handleElId
16569 * An associative array of HTML tags that will be ignored if clicked.
16570 * @property invalidHandleTypes
16571 * @type {string: string}
16573 invalidHandleTypes: null,
16576 * An associative array of ids for elements that will be ignored if clicked
16577 * @property invalidHandleIds
16578 * @type {string: string}
16580 invalidHandleIds: null,
16583 * An indexted array of css class names for elements that will be ignored
16585 * @property invalidHandleClasses
16588 invalidHandleClasses: null,
16591 * The linked element's absolute X position at the time the drag was
16593 * @property startPageX
16600 * The linked element's absolute X position at the time the drag was
16602 * @property startPageY
16609 * The group defines a logical collection of DragDrop objects that are
16610 * related. Instances only get events when interacting with other
16611 * DragDrop object in the same group. This lets us define multiple
16612 * groups using a single DragDrop subclass if we want.
16614 * @type {string: string}
16619 * Individual drag/drop instances can be locked. This will prevent
16620 * onmousedown start drag.
16628 * Lock this instance
16631 lock: function() { this.locked = true; },
16634 * Unlock this instace
16637 unlock: function() { this.locked = false; },
16640 * By default, all insances can be a drop target. This can be disabled by
16641 * setting isTarget to false.
16648 * The padding configured for this drag and drop object for calculating
16649 * the drop zone intersection with this object.
16656 * Cached reference to the linked element
16657 * @property _domRef
16663 * Internal typeof flag
16664 * @property __ygDragDrop
16667 __ygDragDrop: true,
16670 * Set to true when horizontal contraints are applied
16671 * @property constrainX
16678 * Set to true when vertical contraints are applied
16679 * @property constrainY
16686 * The left constraint
16694 * The right constraint
16702 * The up constraint
16711 * The down constraint
16719 * Maintain offsets when we resetconstraints. Set to true when you want
16720 * the position of the element relative to its parent to stay the same
16721 * when the page changes
16723 * @property maintainOffset
16726 maintainOffset: false,
16729 * Array of pixel locations the element will snap to if we specified a
16730 * horizontal graduation/interval. This array is generated automatically
16731 * when you define a tick interval.
16738 * Array of pixel locations the element will snap to if we specified a
16739 * vertical graduation/interval. This array is generated automatically
16740 * when you define a tick interval.
16747 * By default the drag and drop instance will only respond to the primary
16748 * button click (left button for a right-handed mouse). Set to true to
16749 * allow drag and drop to start with any mouse click that is propogated
16751 * @property primaryButtonOnly
16754 primaryButtonOnly: true,
16757 * The availabe property is false until the linked dom element is accessible.
16758 * @property available
16764 * By default, drags can only be initiated if the mousedown occurs in the
16765 * region the linked element is. This is done in part to work around a
16766 * bug in some browsers that mis-report the mousedown if the previous
16767 * mouseup happened outside of the window. This property is set to true
16768 * if outer handles are defined.
16770 * @property hasOuterHandles
16774 hasOuterHandles: false,
16777 * Code that executes immediately before the startDrag event
16778 * @method b4StartDrag
16781 b4StartDrag: function(x, y) { },
16784 * Abstract method called after a drag/drop object is clicked
16785 * and the drag or mousedown time thresholds have beeen met.
16786 * @method startDrag
16787 * @param {int} X click location
16788 * @param {int} Y click location
16790 startDrag: function(x, y) { /* override this */ },
16793 * Code that executes immediately before the onDrag event
16797 b4Drag: function(e) { },
16800 * Abstract method called during the onMouseMove event while dragging an
16803 * @param {Event} e the mousemove event
16805 onDrag: function(e) { /* override this */ },
16808 * Abstract method called when this element fist begins hovering over
16809 * another DragDrop obj
16810 * @method onDragEnter
16811 * @param {Event} e the mousemove event
16812 * @param {String|DragDrop[]} id In POINT mode, the element
16813 * id this is hovering over. In INTERSECT mode, an array of one or more
16814 * dragdrop items being hovered over.
16816 onDragEnter: function(e, id) { /* override this */ },
16819 * Code that executes immediately before the onDragOver event
16820 * @method b4DragOver
16823 b4DragOver: function(e) { },
16826 * Abstract method called when this element is hovering over another
16828 * @method onDragOver
16829 * @param {Event} e the mousemove event
16830 * @param {String|DragDrop[]} id In POINT mode, the element
16831 * id this is hovering over. In INTERSECT mode, an array of dd items
16832 * being hovered over.
16834 onDragOver: function(e, id) { /* override this */ },
16837 * Code that executes immediately before the onDragOut event
16838 * @method b4DragOut
16841 b4DragOut: function(e) { },
16844 * Abstract method called when we are no longer hovering over an element
16845 * @method onDragOut
16846 * @param {Event} e the mousemove event
16847 * @param {String|DragDrop[]} id In POINT mode, the element
16848 * id this was hovering over. In INTERSECT mode, an array of dd items
16849 * that the mouse is no longer over.
16851 onDragOut: function(e, id) { /* override this */ },
16854 * Code that executes immediately before the onDragDrop event
16855 * @method b4DragDrop
16858 b4DragDrop: function(e) { },
16861 * Abstract method called when this item is dropped on another DragDrop
16863 * @method onDragDrop
16864 * @param {Event} e the mouseup event
16865 * @param {String|DragDrop[]} id In POINT mode, the element
16866 * id this was dropped on. In INTERSECT mode, an array of dd items this
16869 onDragDrop: function(e, id) { /* override this */ },
16872 * Abstract method called when this item is dropped on an area with no
16874 * @method onInvalidDrop
16875 * @param {Event} e the mouseup event
16877 onInvalidDrop: function(e) { /* override this */ },
16880 * Code that executes immediately before the endDrag event
16881 * @method b4EndDrag
16884 b4EndDrag: function(e) { },
16887 * Fired when we are done dragging the object
16889 * @param {Event} e the mouseup event
16891 endDrag: function(e) { /* override this */ },
16894 * Code executed immediately before the onMouseDown event
16895 * @method b4MouseDown
16896 * @param {Event} e the mousedown event
16899 b4MouseDown: function(e) { },
16902 * Event handler that fires when a drag/drop obj gets a mousedown
16903 * @method onMouseDown
16904 * @param {Event} e the mousedown event
16906 onMouseDown: function(e) { /* override this */ },
16909 * Event handler that fires when a drag/drop obj gets a mouseup
16910 * @method onMouseUp
16911 * @param {Event} e the mouseup event
16913 onMouseUp: function(e) { /* override this */ },
16916 * Override the onAvailable method to do what is needed after the initial
16917 * position was determined.
16918 * @method onAvailable
16920 onAvailable: function () {
16924 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16927 defaultPadding : {left:0, right:0, top:0, bottom:0},
16930 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16934 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16935 { dragElId: "existingProxyDiv" });
16936 dd.startDrag = function(){
16937 this.constrainTo("parent-id");
16940 * Or you can initalize it using the {@link Roo.Element} object:
16942 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16943 startDrag : function(){
16944 this.constrainTo("parent-id");
16948 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16949 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16950 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16951 * an object containing the sides to pad. For example: {right:10, bottom:10}
16952 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16954 constrainTo : function(constrainTo, pad, inContent){
16955 if(typeof pad == "number"){
16956 pad = {left: pad, right:pad, top:pad, bottom:pad};
16958 pad = pad || this.defaultPadding;
16959 var b = Roo.get(this.getEl()).getBox();
16960 var ce = Roo.get(constrainTo);
16961 var s = ce.getScroll();
16962 var c, cd = ce.dom;
16963 if(cd == document.body){
16964 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16967 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16971 var topSpace = b.y - c.y;
16972 var leftSpace = b.x - c.x;
16974 this.resetConstraints();
16975 this.setXConstraint(leftSpace - (pad.left||0), // left
16976 c.width - leftSpace - b.width - (pad.right||0) //right
16978 this.setYConstraint(topSpace - (pad.top||0), //top
16979 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16984 * Returns a reference to the linked element
16986 * @return {HTMLElement} the html element
16988 getEl: function() {
16989 if (!this._domRef) {
16990 this._domRef = Roo.getDom(this.id);
16993 return this._domRef;
16997 * Returns a reference to the actual element to drag. By default this is
16998 * the same as the html element, but it can be assigned to another
16999 * element. An example of this can be found in Roo.dd.DDProxy
17000 * @method getDragEl
17001 * @return {HTMLElement} the html element
17003 getDragEl: function() {
17004 return Roo.getDom(this.dragElId);
17008 * Sets up the DragDrop object. Must be called in the constructor of any
17009 * Roo.dd.DragDrop subclass
17011 * @param id the id of the linked element
17012 * @param {String} sGroup the group of related items
17013 * @param {object} config configuration attributes
17015 init: function(id, sGroup, config) {
17016 this.initTarget(id, sGroup, config);
17017 if (!Roo.isTouch) {
17018 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17020 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17021 // Event.on(this.id, "selectstart", Event.preventDefault);
17025 * Initializes Targeting functionality only... the object does not
17026 * get a mousedown handler.
17027 * @method initTarget
17028 * @param id the id of the linked element
17029 * @param {String} sGroup the group of related items
17030 * @param {object} config configuration attributes
17032 initTarget: function(id, sGroup, config) {
17034 // configuration attributes
17035 this.config = config || {};
17037 // create a local reference to the drag and drop manager
17038 this.DDM = Roo.dd.DDM;
17039 // initialize the groups array
17042 // assume that we have an element reference instead of an id if the
17043 // parameter is not a string
17044 if (typeof id !== "string") {
17051 // add to an interaction group
17052 this.addToGroup((sGroup) ? sGroup : "default");
17054 // We don't want to register this as the handle with the manager
17055 // so we just set the id rather than calling the setter.
17056 this.handleElId = id;
17058 // the linked element is the element that gets dragged by default
17059 this.setDragElId(id);
17061 // by default, clicked anchors will not start drag operations.
17062 this.invalidHandleTypes = { A: "A" };
17063 this.invalidHandleIds = {};
17064 this.invalidHandleClasses = [];
17066 this.applyConfig();
17068 this.handleOnAvailable();
17072 * Applies the configuration parameters that were passed into the constructor.
17073 * This is supposed to happen at each level through the inheritance chain. So
17074 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17075 * DragDrop in order to get all of the parameters that are available in
17077 * @method applyConfig
17079 applyConfig: function() {
17081 // configurable properties:
17082 // padding, isTarget, maintainOffset, primaryButtonOnly
17083 this.padding = this.config.padding || [0, 0, 0, 0];
17084 this.isTarget = (this.config.isTarget !== false);
17085 this.maintainOffset = (this.config.maintainOffset);
17086 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17091 * Executed when the linked element is available
17092 * @method handleOnAvailable
17095 handleOnAvailable: function() {
17096 this.available = true;
17097 this.resetConstraints();
17098 this.onAvailable();
17102 * Configures the padding for the target zone in px. Effectively expands
17103 * (or reduces) the virtual object size for targeting calculations.
17104 * Supports css-style shorthand; if only one parameter is passed, all sides
17105 * will have that padding, and if only two are passed, the top and bottom
17106 * will have the first param, the left and right the second.
17107 * @method setPadding
17108 * @param {int} iTop Top pad
17109 * @param {int} iRight Right pad
17110 * @param {int} iBot Bot pad
17111 * @param {int} iLeft Left pad
17113 setPadding: function(iTop, iRight, iBot, iLeft) {
17114 // this.padding = [iLeft, iRight, iTop, iBot];
17115 if (!iRight && 0 !== iRight) {
17116 this.padding = [iTop, iTop, iTop, iTop];
17117 } else if (!iBot && 0 !== iBot) {
17118 this.padding = [iTop, iRight, iTop, iRight];
17120 this.padding = [iTop, iRight, iBot, iLeft];
17125 * Stores the initial placement of the linked element.
17126 * @method setInitialPosition
17127 * @param {int} diffX the X offset, default 0
17128 * @param {int} diffY the Y offset, default 0
17130 setInitPosition: function(diffX, diffY) {
17131 var el = this.getEl();
17133 if (!this.DDM.verifyEl(el)) {
17137 var dx = diffX || 0;
17138 var dy = diffY || 0;
17140 var p = Dom.getXY( el );
17142 this.initPageX = p[0] - dx;
17143 this.initPageY = p[1] - dy;
17145 this.lastPageX = p[0];
17146 this.lastPageY = p[1];
17149 this.setStartPosition(p);
17153 * Sets the start position of the element. This is set when the obj
17154 * is initialized, the reset when a drag is started.
17155 * @method setStartPosition
17156 * @param pos current position (from previous lookup)
17159 setStartPosition: function(pos) {
17160 var p = pos || Dom.getXY( this.getEl() );
17161 this.deltaSetXY = null;
17163 this.startPageX = p[0];
17164 this.startPageY = p[1];
17168 * Add this instance to a group of related drag/drop objects. All
17169 * instances belong to at least one group, and can belong to as many
17170 * groups as needed.
17171 * @method addToGroup
17172 * @param sGroup {string} the name of the group
17174 addToGroup: function(sGroup) {
17175 this.groups[sGroup] = true;
17176 this.DDM.regDragDrop(this, sGroup);
17180 * Remove's this instance from the supplied interaction group
17181 * @method removeFromGroup
17182 * @param {string} sGroup The group to drop
17184 removeFromGroup: function(sGroup) {
17185 if (this.groups[sGroup]) {
17186 delete this.groups[sGroup];
17189 this.DDM.removeDDFromGroup(this, sGroup);
17193 * Allows you to specify that an element other than the linked element
17194 * will be moved with the cursor during a drag
17195 * @method setDragElId
17196 * @param id {string} the id of the element that will be used to initiate the drag
17198 setDragElId: function(id) {
17199 this.dragElId = id;
17203 * Allows you to specify a child of the linked element that should be
17204 * used to initiate the drag operation. An example of this would be if
17205 * you have a content div with text and links. Clicking anywhere in the
17206 * content area would normally start the drag operation. Use this method
17207 * to specify that an element inside of the content div is the element
17208 * that starts the drag operation.
17209 * @method setHandleElId
17210 * @param id {string} the id of the element that will be used to
17211 * initiate the drag.
17213 setHandleElId: function(id) {
17214 if (typeof id !== "string") {
17217 this.handleElId = id;
17218 this.DDM.regHandle(this.id, id);
17222 * Allows you to set an element outside of the linked element as a drag
17224 * @method setOuterHandleElId
17225 * @param id the id of the element that will be used to initiate the drag
17227 setOuterHandleElId: function(id) {
17228 if (typeof id !== "string") {
17231 Event.on(id, "mousedown",
17232 this.handleMouseDown, this);
17233 this.setHandleElId(id);
17235 this.hasOuterHandles = true;
17239 * Remove all drag and drop hooks for this element
17242 unreg: function() {
17243 Event.un(this.id, "mousedown",
17244 this.handleMouseDown);
17245 Event.un(this.id, "touchstart",
17246 this.handleMouseDown);
17247 this._domRef = null;
17248 this.DDM._remove(this);
17251 destroy : function(){
17256 * Returns true if this instance is locked, or the drag drop mgr is locked
17257 * (meaning that all drag/drop is disabled on the page.)
17259 * @return {boolean} true if this obj or all drag/drop is locked, else
17262 isLocked: function() {
17263 return (this.DDM.isLocked() || this.locked);
17267 * Fired when this object is clicked
17268 * @method handleMouseDown
17270 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17273 handleMouseDown: function(e, oDD){
17275 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17276 //Roo.log('not touch/ button !=0');
17279 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17280 return; // double touch..
17284 if (this.isLocked()) {
17285 //Roo.log('locked');
17289 this.DDM.refreshCache(this.groups);
17290 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17291 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17292 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17293 //Roo.log('no outer handes or not over target');
17296 // Roo.log('check validator');
17297 if (this.clickValidator(e)) {
17298 // Roo.log('validate success');
17299 // set the initial element position
17300 this.setStartPosition();
17303 this.b4MouseDown(e);
17304 this.onMouseDown(e);
17306 this.DDM.handleMouseDown(e, this);
17308 this.DDM.stopEvent(e);
17316 clickValidator: function(e) {
17317 var target = e.getTarget();
17318 return ( this.isValidHandleChild(target) &&
17319 (this.id == this.handleElId ||
17320 this.DDM.handleWasClicked(target, this.id)) );
17324 * Allows you to specify a tag name that should not start a drag operation
17325 * when clicked. This is designed to facilitate embedding links within a
17326 * drag handle that do something other than start the drag.
17327 * @method addInvalidHandleType
17328 * @param {string} tagName the type of element to exclude
17330 addInvalidHandleType: function(tagName) {
17331 var type = tagName.toUpperCase();
17332 this.invalidHandleTypes[type] = type;
17336 * Lets you to specify an element id for a child of a drag handle
17337 * that should not initiate a drag
17338 * @method addInvalidHandleId
17339 * @param {string} id the element id of the element you wish to ignore
17341 addInvalidHandleId: function(id) {
17342 if (typeof id !== "string") {
17345 this.invalidHandleIds[id] = id;
17349 * Lets you specify a css class of elements that will not initiate a drag
17350 * @method addInvalidHandleClass
17351 * @param {string} cssClass the class of the elements you wish to ignore
17353 addInvalidHandleClass: function(cssClass) {
17354 this.invalidHandleClasses.push(cssClass);
17358 * Unsets an excluded tag name set by addInvalidHandleType
17359 * @method removeInvalidHandleType
17360 * @param {string} tagName the type of element to unexclude
17362 removeInvalidHandleType: function(tagName) {
17363 var type = tagName.toUpperCase();
17364 // this.invalidHandleTypes[type] = null;
17365 delete this.invalidHandleTypes[type];
17369 * Unsets an invalid handle id
17370 * @method removeInvalidHandleId
17371 * @param {string} id the id of the element to re-enable
17373 removeInvalidHandleId: function(id) {
17374 if (typeof id !== "string") {
17377 delete this.invalidHandleIds[id];
17381 * Unsets an invalid css class
17382 * @method removeInvalidHandleClass
17383 * @param {string} cssClass the class of the element(s) you wish to
17386 removeInvalidHandleClass: function(cssClass) {
17387 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17388 if (this.invalidHandleClasses[i] == cssClass) {
17389 delete this.invalidHandleClasses[i];
17395 * Checks the tag exclusion list to see if this click should be ignored
17396 * @method isValidHandleChild
17397 * @param {HTMLElement} node the HTMLElement to evaluate
17398 * @return {boolean} true if this is a valid tag type, false if not
17400 isValidHandleChild: function(node) {
17403 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17406 nodeName = node.nodeName.toUpperCase();
17408 nodeName = node.nodeName;
17410 valid = valid && !this.invalidHandleTypes[nodeName];
17411 valid = valid && !this.invalidHandleIds[node.id];
17413 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17414 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17423 * Create the array of horizontal tick marks if an interval was specified
17424 * in setXConstraint().
17425 * @method setXTicks
17428 setXTicks: function(iStartX, iTickSize) {
17430 this.xTickSize = iTickSize;
17434 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17436 this.xTicks[this.xTicks.length] = i;
17441 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17443 this.xTicks[this.xTicks.length] = i;
17448 this.xTicks.sort(this.DDM.numericSort) ;
17452 * Create the array of vertical tick marks if an interval was specified in
17453 * setYConstraint().
17454 * @method setYTicks
17457 setYTicks: function(iStartY, iTickSize) {
17459 this.yTickSize = iTickSize;
17463 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17465 this.yTicks[this.yTicks.length] = i;
17470 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17472 this.yTicks[this.yTicks.length] = i;
17477 this.yTicks.sort(this.DDM.numericSort) ;
17481 * By default, the element can be dragged any place on the screen. Use
17482 * this method to limit the horizontal travel of the element. Pass in
17483 * 0,0 for the parameters if you want to lock the drag to the y axis.
17484 * @method setXConstraint
17485 * @param {int} iLeft the number of pixels the element can move to the left
17486 * @param {int} iRight the number of pixels the element can move to the
17488 * @param {int} iTickSize optional parameter for specifying that the
17490 * should move iTickSize pixels at a time.
17492 setXConstraint: function(iLeft, iRight, iTickSize) {
17493 this.leftConstraint = iLeft;
17494 this.rightConstraint = iRight;
17496 this.minX = this.initPageX - iLeft;
17497 this.maxX = this.initPageX + iRight;
17498 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17500 this.constrainX = true;
17504 * Clears any constraints applied to this instance. Also clears ticks
17505 * since they can't exist independent of a constraint at this time.
17506 * @method clearConstraints
17508 clearConstraints: function() {
17509 this.constrainX = false;
17510 this.constrainY = false;
17515 * Clears any tick interval defined for this instance
17516 * @method clearTicks
17518 clearTicks: function() {
17519 this.xTicks = null;
17520 this.yTicks = null;
17521 this.xTickSize = 0;
17522 this.yTickSize = 0;
17526 * By default, the element can be dragged any place on the screen. Set
17527 * this to limit the vertical travel of the element. Pass in 0,0 for the
17528 * parameters if you want to lock the drag to the x axis.
17529 * @method setYConstraint
17530 * @param {int} iUp the number of pixels the element can move up
17531 * @param {int} iDown the number of pixels the element can move down
17532 * @param {int} iTickSize optional parameter for specifying that the
17533 * element should move iTickSize pixels at a time.
17535 setYConstraint: function(iUp, iDown, iTickSize) {
17536 this.topConstraint = iUp;
17537 this.bottomConstraint = iDown;
17539 this.minY = this.initPageY - iUp;
17540 this.maxY = this.initPageY + iDown;
17541 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17543 this.constrainY = true;
17548 * resetConstraints must be called if you manually reposition a dd element.
17549 * @method resetConstraints
17550 * @param {boolean} maintainOffset
17552 resetConstraints: function() {
17555 // Maintain offsets if necessary
17556 if (this.initPageX || this.initPageX === 0) {
17557 // figure out how much this thing has moved
17558 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17559 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17561 this.setInitPosition(dx, dy);
17563 // This is the first time we have detected the element's position
17565 this.setInitPosition();
17568 if (this.constrainX) {
17569 this.setXConstraint( this.leftConstraint,
17570 this.rightConstraint,
17574 if (this.constrainY) {
17575 this.setYConstraint( this.topConstraint,
17576 this.bottomConstraint,
17582 * Normally the drag element is moved pixel by pixel, but we can specify
17583 * that it move a number of pixels at a time. This method resolves the
17584 * location when we have it set up like this.
17586 * @param {int} val where we want to place the object
17587 * @param {int[]} tickArray sorted array of valid points
17588 * @return {int} the closest tick
17591 getTick: function(val, tickArray) {
17594 // If tick interval is not defined, it is effectively 1 pixel,
17595 // so we return the value passed to us.
17597 } else if (tickArray[0] >= val) {
17598 // The value is lower than the first tick, so we return the first
17600 return tickArray[0];
17602 for (var i=0, len=tickArray.length; i<len; ++i) {
17604 if (tickArray[next] && tickArray[next] >= val) {
17605 var diff1 = val - tickArray[i];
17606 var diff2 = tickArray[next] - val;
17607 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17611 // The value is larger than the last tick, so we return the last
17613 return tickArray[tickArray.length - 1];
17620 * @return {string} string representation of the dd obj
17622 toString: function() {
17623 return ("DragDrop " + this.id);
17631 * Ext JS Library 1.1.1
17632 * Copyright(c) 2006-2007, Ext JS, LLC.
17634 * Originally Released Under LGPL - original licence link has changed is not relivant.
17637 * <script type="text/javascript">
17642 * The drag and drop utility provides a framework for building drag and drop
17643 * applications. In addition to enabling drag and drop for specific elements,
17644 * the drag and drop elements are tracked by the manager class, and the
17645 * interactions between the various elements are tracked during the drag and
17646 * the implementing code is notified about these important moments.
17649 // Only load the library once. Rewriting the manager class would orphan
17650 // existing drag and drop instances.
17651 if (!Roo.dd.DragDropMgr) {
17654 * @class Roo.dd.DragDropMgr
17655 * DragDropMgr is a singleton that tracks the element interaction for
17656 * all DragDrop items in the window. Generally, you will not call
17657 * this class directly, but it does have helper methods that could
17658 * be useful in your DragDrop implementations.
17661 Roo.dd.DragDropMgr = function() {
17663 var Event = Roo.EventManager;
17668 * Two dimensional Array of registered DragDrop objects. The first
17669 * dimension is the DragDrop item group, the second the DragDrop
17672 * @type {string: string}
17679 * Array of element ids defined as drag handles. Used to determine
17680 * if the element that generated the mousedown event is actually the
17681 * handle and not the html element itself.
17682 * @property handleIds
17683 * @type {string: string}
17690 * the DragDrop object that is currently being dragged
17691 * @property dragCurrent
17699 * the DragDrop object(s) that are being hovered over
17700 * @property dragOvers
17708 * the X distance between the cursor and the object being dragged
17717 * the Y distance between the cursor and the object being dragged
17726 * Flag to determine if we should prevent the default behavior of the
17727 * events we define. By default this is true, but this can be set to
17728 * false if you need the default behavior (not recommended)
17729 * @property preventDefault
17733 preventDefault: true,
17736 * Flag to determine if we should stop the propagation of the events
17737 * we generate. This is true by default but you may want to set it to
17738 * false if the html element contains other features that require the
17740 * @property stopPropagation
17744 stopPropagation: true,
17747 * Internal flag that is set to true when drag and drop has been
17749 * @property initialized
17756 * All drag and drop can be disabled.
17764 * Called the first time an element is registered.
17770 this.initialized = true;
17774 * In point mode, drag and drop interaction is defined by the
17775 * location of the cursor during the drag/drop
17783 * In intersect mode, drag and drop interactio nis defined by the
17784 * overlap of two or more drag and drop objects.
17785 * @property INTERSECT
17792 * The current drag and drop mode. Default: POINT
17800 * Runs method on all drag and drop objects
17801 * @method _execOnAll
17805 _execOnAll: function(sMethod, args) {
17806 for (var i in this.ids) {
17807 for (var j in this.ids[i]) {
17808 var oDD = this.ids[i][j];
17809 if (! this.isTypeOfDD(oDD)) {
17812 oDD[sMethod].apply(oDD, args);
17818 * Drag and drop initialization. Sets up the global event handlers
17823 _onLoad: function() {
17827 if (!Roo.isTouch) {
17828 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17829 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17831 Event.on(document, "touchend", this.handleMouseUp, this, true);
17832 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17834 Event.on(window, "unload", this._onUnload, this, true);
17835 Event.on(window, "resize", this._onResize, this, true);
17836 // Event.on(window, "mouseout", this._test);
17841 * Reset constraints on all drag and drop objs
17842 * @method _onResize
17846 _onResize: function(e) {
17847 this._execOnAll("resetConstraints", []);
17851 * Lock all drag and drop functionality
17855 lock: function() { this.locked = true; },
17858 * Unlock all drag and drop functionality
17862 unlock: function() { this.locked = false; },
17865 * Is drag and drop locked?
17867 * @return {boolean} True if drag and drop is locked, false otherwise.
17870 isLocked: function() { return this.locked; },
17873 * Location cache that is set for all drag drop objects when a drag is
17874 * initiated, cleared when the drag is finished.
17875 * @property locationCache
17882 * Set useCache to false if you want to force object the lookup of each
17883 * drag and drop linked element constantly during a drag.
17884 * @property useCache
17891 * The number of pixels that the mouse needs to move after the
17892 * mousedown before the drag is initiated. Default=3;
17893 * @property clickPixelThresh
17897 clickPixelThresh: 3,
17900 * The number of milliseconds after the mousedown event to initiate the
17901 * drag if we don't get a mouseup event. Default=1000
17902 * @property clickTimeThresh
17906 clickTimeThresh: 350,
17909 * Flag that indicates that either the drag pixel threshold or the
17910 * mousdown time threshold has been met
17911 * @property dragThreshMet
17916 dragThreshMet: false,
17919 * Timeout used for the click time threshold
17920 * @property clickTimeout
17925 clickTimeout: null,
17928 * The X position of the mousedown event stored for later use when a
17929 * drag threshold is met.
17938 * The Y position of the mousedown event stored for later use when a
17939 * drag threshold is met.
17948 * Each DragDrop instance must be registered with the DragDropMgr.
17949 * This is executed in DragDrop.init()
17950 * @method regDragDrop
17951 * @param {DragDrop} oDD the DragDrop object to register
17952 * @param {String} sGroup the name of the group this element belongs to
17955 regDragDrop: function(oDD, sGroup) {
17956 if (!this.initialized) { this.init(); }
17958 if (!this.ids[sGroup]) {
17959 this.ids[sGroup] = {};
17961 this.ids[sGroup][oDD.id] = oDD;
17965 * Removes the supplied dd instance from the supplied group. Executed
17966 * by DragDrop.removeFromGroup, so don't call this function directly.
17967 * @method removeDDFromGroup
17971 removeDDFromGroup: function(oDD, sGroup) {
17972 if (!this.ids[sGroup]) {
17973 this.ids[sGroup] = {};
17976 var obj = this.ids[sGroup];
17977 if (obj && obj[oDD.id]) {
17978 delete obj[oDD.id];
17983 * Unregisters a drag and drop item. This is executed in
17984 * DragDrop.unreg, use that method instead of calling this directly.
17989 _remove: function(oDD) {
17990 for (var g in oDD.groups) {
17991 if (g && this.ids[g][oDD.id]) {
17992 delete this.ids[g][oDD.id];
17995 delete this.handleIds[oDD.id];
17999 * Each DragDrop handle element must be registered. This is done
18000 * automatically when executing DragDrop.setHandleElId()
18001 * @method regHandle
18002 * @param {String} sDDId the DragDrop id this element is a handle for
18003 * @param {String} sHandleId the id of the element that is the drag
18007 regHandle: function(sDDId, sHandleId) {
18008 if (!this.handleIds[sDDId]) {
18009 this.handleIds[sDDId] = {};
18011 this.handleIds[sDDId][sHandleId] = sHandleId;
18015 * Utility function to determine if a given element has been
18016 * registered as a drag drop item.
18017 * @method isDragDrop
18018 * @param {String} id the element id to check
18019 * @return {boolean} true if this element is a DragDrop item,
18023 isDragDrop: function(id) {
18024 return ( this.getDDById(id) ) ? true : false;
18028 * Returns the drag and drop instances that are in all groups the
18029 * passed in instance belongs to.
18030 * @method getRelated
18031 * @param {DragDrop} p_oDD the obj to get related data for
18032 * @param {boolean} bTargetsOnly if true, only return targetable objs
18033 * @return {DragDrop[]} the related instances
18036 getRelated: function(p_oDD, bTargetsOnly) {
18038 for (var i in p_oDD.groups) {
18039 for (j in this.ids[i]) {
18040 var dd = this.ids[i][j];
18041 if (! this.isTypeOfDD(dd)) {
18044 if (!bTargetsOnly || dd.isTarget) {
18045 oDDs[oDDs.length] = dd;
18054 * Returns true if the specified dd target is a legal target for
18055 * the specifice drag obj
18056 * @method isLegalTarget
18057 * @param {DragDrop} the drag obj
18058 * @param {DragDrop} the target
18059 * @return {boolean} true if the target is a legal target for the
18063 isLegalTarget: function (oDD, oTargetDD) {
18064 var targets = this.getRelated(oDD, true);
18065 for (var i=0, len=targets.length;i<len;++i) {
18066 if (targets[i].id == oTargetDD.id) {
18075 * My goal is to be able to transparently determine if an object is
18076 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18077 * returns "object", oDD.constructor.toString() always returns
18078 * "DragDrop" and not the name of the subclass. So for now it just
18079 * evaluates a well-known variable in DragDrop.
18080 * @method isTypeOfDD
18081 * @param {Object} the object to evaluate
18082 * @return {boolean} true if typeof oDD = DragDrop
18085 isTypeOfDD: function (oDD) {
18086 return (oDD && oDD.__ygDragDrop);
18090 * Utility function to determine if a given element has been
18091 * registered as a drag drop handle for the given Drag Drop object.
18093 * @param {String} id the element id to check
18094 * @return {boolean} true if this element is a DragDrop handle, false
18098 isHandle: function(sDDId, sHandleId) {
18099 return ( this.handleIds[sDDId] &&
18100 this.handleIds[sDDId][sHandleId] );
18104 * Returns the DragDrop instance for a given id
18105 * @method getDDById
18106 * @param {String} id the id of the DragDrop object
18107 * @return {DragDrop} the drag drop object, null if it is not found
18110 getDDById: function(id) {
18111 for (var i in this.ids) {
18112 if (this.ids[i][id]) {
18113 return this.ids[i][id];
18120 * Fired after a registered DragDrop object gets the mousedown event.
18121 * Sets up the events required to track the object being dragged
18122 * @method handleMouseDown
18123 * @param {Event} e the event
18124 * @param oDD the DragDrop object being dragged
18128 handleMouseDown: function(e, oDD) {
18130 Roo.QuickTips.disable();
18132 this.currentTarget = e.getTarget();
18134 this.dragCurrent = oDD;
18136 var el = oDD.getEl();
18138 // track start position
18139 this.startX = e.getPageX();
18140 this.startY = e.getPageY();
18142 this.deltaX = this.startX - el.offsetLeft;
18143 this.deltaY = this.startY - el.offsetTop;
18145 this.dragThreshMet = false;
18147 this.clickTimeout = setTimeout(
18149 var DDM = Roo.dd.DDM;
18150 DDM.startDrag(DDM.startX, DDM.startY);
18152 this.clickTimeThresh );
18156 * Fired when either the drag pixel threshol or the mousedown hold
18157 * time threshold has been met.
18158 * @method startDrag
18159 * @param x {int} the X position of the original mousedown
18160 * @param y {int} the Y position of the original mousedown
18163 startDrag: function(x, y) {
18164 clearTimeout(this.clickTimeout);
18165 if (this.dragCurrent) {
18166 this.dragCurrent.b4StartDrag(x, y);
18167 this.dragCurrent.startDrag(x, y);
18169 this.dragThreshMet = true;
18173 * Internal function to handle the mouseup event. Will be invoked
18174 * from the context of the document.
18175 * @method handleMouseUp
18176 * @param {Event} e the event
18180 handleMouseUp: function(e) {
18183 Roo.QuickTips.enable();
18185 if (! this.dragCurrent) {
18189 clearTimeout(this.clickTimeout);
18191 if (this.dragThreshMet) {
18192 this.fireEvents(e, true);
18202 * Utility to stop event propagation and event default, if these
18203 * features are turned on.
18204 * @method stopEvent
18205 * @param {Event} e the event as returned by this.getEvent()
18208 stopEvent: function(e){
18209 if(this.stopPropagation) {
18210 e.stopPropagation();
18213 if (this.preventDefault) {
18214 e.preventDefault();
18219 * Internal function to clean up event handlers after the drag
18220 * operation is complete
18222 * @param {Event} e the event
18226 stopDrag: function(e) {
18227 // Fire the drag end event for the item that was dragged
18228 if (this.dragCurrent) {
18229 if (this.dragThreshMet) {
18230 this.dragCurrent.b4EndDrag(e);
18231 this.dragCurrent.endDrag(e);
18234 this.dragCurrent.onMouseUp(e);
18237 this.dragCurrent = null;
18238 this.dragOvers = {};
18242 * Internal function to handle the mousemove event. Will be invoked
18243 * from the context of the html element.
18245 * @TODO figure out what we can do about mouse events lost when the
18246 * user drags objects beyond the window boundary. Currently we can
18247 * detect this in internet explorer by verifying that the mouse is
18248 * down during the mousemove event. Firefox doesn't give us the
18249 * button state on the mousemove event.
18250 * @method handleMouseMove
18251 * @param {Event} e the event
18255 handleMouseMove: function(e) {
18256 if (! this.dragCurrent) {
18260 // var button = e.which || e.button;
18262 // check for IE mouseup outside of page boundary
18263 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18265 return this.handleMouseUp(e);
18268 if (!this.dragThreshMet) {
18269 var diffX = Math.abs(this.startX - e.getPageX());
18270 var diffY = Math.abs(this.startY - e.getPageY());
18271 if (diffX > this.clickPixelThresh ||
18272 diffY > this.clickPixelThresh) {
18273 this.startDrag(this.startX, this.startY);
18277 if (this.dragThreshMet) {
18278 this.dragCurrent.b4Drag(e);
18279 this.dragCurrent.onDrag(e);
18280 if(!this.dragCurrent.moveOnly){
18281 this.fireEvents(e, false);
18291 * Iterates over all of the DragDrop elements to find ones we are
18292 * hovering over or dropping on
18293 * @method fireEvents
18294 * @param {Event} e the event
18295 * @param {boolean} isDrop is this a drop op or a mouseover op?
18299 fireEvents: function(e, isDrop) {
18300 var dc = this.dragCurrent;
18302 // If the user did the mouse up outside of the window, we could
18303 // get here even though we have ended the drag.
18304 if (!dc || dc.isLocked()) {
18308 var pt = e.getPoint();
18310 // cache the previous dragOver array
18316 var enterEvts = [];
18318 // Check to see if the object(s) we were hovering over is no longer
18319 // being hovered over so we can fire the onDragOut event
18320 for (var i in this.dragOvers) {
18322 var ddo = this.dragOvers[i];
18324 if (! this.isTypeOfDD(ddo)) {
18328 if (! this.isOverTarget(pt, ddo, this.mode)) {
18329 outEvts.push( ddo );
18332 oldOvers[i] = true;
18333 delete this.dragOvers[i];
18336 for (var sGroup in dc.groups) {
18338 if ("string" != typeof sGroup) {
18342 for (i in this.ids[sGroup]) {
18343 var oDD = this.ids[sGroup][i];
18344 if (! this.isTypeOfDD(oDD)) {
18348 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18349 if (this.isOverTarget(pt, oDD, this.mode)) {
18350 // look for drop interactions
18352 dropEvts.push( oDD );
18353 // look for drag enter and drag over interactions
18356 // initial drag over: dragEnter fires
18357 if (!oldOvers[oDD.id]) {
18358 enterEvts.push( oDD );
18359 // subsequent drag overs: dragOver fires
18361 overEvts.push( oDD );
18364 this.dragOvers[oDD.id] = oDD;
18372 if (outEvts.length) {
18373 dc.b4DragOut(e, outEvts);
18374 dc.onDragOut(e, outEvts);
18377 if (enterEvts.length) {
18378 dc.onDragEnter(e, enterEvts);
18381 if (overEvts.length) {
18382 dc.b4DragOver(e, overEvts);
18383 dc.onDragOver(e, overEvts);
18386 if (dropEvts.length) {
18387 dc.b4DragDrop(e, dropEvts);
18388 dc.onDragDrop(e, dropEvts);
18392 // fire dragout events
18394 for (i=0, len=outEvts.length; i<len; ++i) {
18395 dc.b4DragOut(e, outEvts[i].id);
18396 dc.onDragOut(e, outEvts[i].id);
18399 // fire enter events
18400 for (i=0,len=enterEvts.length; i<len; ++i) {
18401 // dc.b4DragEnter(e, oDD.id);
18402 dc.onDragEnter(e, enterEvts[i].id);
18405 // fire over events
18406 for (i=0,len=overEvts.length; i<len; ++i) {
18407 dc.b4DragOver(e, overEvts[i].id);
18408 dc.onDragOver(e, overEvts[i].id);
18411 // fire drop events
18412 for (i=0, len=dropEvts.length; i<len; ++i) {
18413 dc.b4DragDrop(e, dropEvts[i].id);
18414 dc.onDragDrop(e, dropEvts[i].id);
18419 // notify about a drop that did not find a target
18420 if (isDrop && !dropEvts.length) {
18421 dc.onInvalidDrop(e);
18427 * Helper function for getting the best match from the list of drag
18428 * and drop objects returned by the drag and drop events when we are
18429 * in INTERSECT mode. It returns either the first object that the
18430 * cursor is over, or the object that has the greatest overlap with
18431 * the dragged element.
18432 * @method getBestMatch
18433 * @param {DragDrop[]} dds The array of drag and drop objects
18435 * @return {DragDrop} The best single match
18438 getBestMatch: function(dds) {
18440 // Return null if the input is not what we expect
18441 //if (!dds || !dds.length || dds.length == 0) {
18443 // If there is only one item, it wins
18444 //} else if (dds.length == 1) {
18446 var len = dds.length;
18451 // Loop through the targeted items
18452 for (var i=0; i<len; ++i) {
18454 // If the cursor is over the object, it wins. If the
18455 // cursor is over multiple matches, the first one we come
18457 if (dd.cursorIsOver) {
18460 // Otherwise the object with the most overlap wins
18463 winner.overlap.getArea() < dd.overlap.getArea()) {
18474 * Refreshes the cache of the top-left and bottom-right points of the
18475 * drag and drop objects in the specified group(s). This is in the
18476 * format that is stored in the drag and drop instance, so typical
18479 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18483 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18485 * @TODO this really should be an indexed array. Alternatively this
18486 * method could accept both.
18487 * @method refreshCache
18488 * @param {Object} groups an associative array of groups to refresh
18491 refreshCache: function(groups) {
18492 for (var sGroup in groups) {
18493 if ("string" != typeof sGroup) {
18496 for (var i in this.ids[sGroup]) {
18497 var oDD = this.ids[sGroup][i];
18499 if (this.isTypeOfDD(oDD)) {
18500 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18501 var loc = this.getLocation(oDD);
18503 this.locationCache[oDD.id] = loc;
18505 delete this.locationCache[oDD.id];
18506 // this will unregister the drag and drop object if
18507 // the element is not in a usable state
18516 * This checks to make sure an element exists and is in the DOM. The
18517 * main purpose is to handle cases where innerHTML is used to remove
18518 * drag and drop objects from the DOM. IE provides an 'unspecified
18519 * error' when trying to access the offsetParent of such an element
18521 * @param {HTMLElement} el the element to check
18522 * @return {boolean} true if the element looks usable
18525 verifyEl: function(el) {
18530 parent = el.offsetParent;
18533 parent = el.offsetParent;
18544 * Returns a Region object containing the drag and drop element's position
18545 * and size, including the padding configured for it
18546 * @method getLocation
18547 * @param {DragDrop} oDD the drag and drop object to get the
18549 * @return {Roo.lib.Region} a Region object representing the total area
18550 * the element occupies, including any padding
18551 * the instance is configured for.
18554 getLocation: function(oDD) {
18555 if (! this.isTypeOfDD(oDD)) {
18559 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18562 pos= Roo.lib.Dom.getXY(el);
18570 x2 = x1 + el.offsetWidth;
18572 y2 = y1 + el.offsetHeight;
18574 t = y1 - oDD.padding[0];
18575 r = x2 + oDD.padding[1];
18576 b = y2 + oDD.padding[2];
18577 l = x1 - oDD.padding[3];
18579 return new Roo.lib.Region( t, r, b, l );
18583 * Checks the cursor location to see if it over the target
18584 * @method isOverTarget
18585 * @param {Roo.lib.Point} pt The point to evaluate
18586 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18587 * @return {boolean} true if the mouse is over the target
18591 isOverTarget: function(pt, oTarget, intersect) {
18592 // use cache if available
18593 var loc = this.locationCache[oTarget.id];
18594 if (!loc || !this.useCache) {
18595 loc = this.getLocation(oTarget);
18596 this.locationCache[oTarget.id] = loc;
18604 oTarget.cursorIsOver = loc.contains( pt );
18606 // DragDrop is using this as a sanity check for the initial mousedown
18607 // in this case we are done. In POINT mode, if the drag obj has no
18608 // contraints, we are also done. Otherwise we need to evaluate the
18609 // location of the target as related to the actual location of the
18610 // dragged element.
18611 var dc = this.dragCurrent;
18612 if (!dc || !dc.getTargetCoord ||
18613 (!intersect && !dc.constrainX && !dc.constrainY)) {
18614 return oTarget.cursorIsOver;
18617 oTarget.overlap = null;
18619 // Get the current location of the drag element, this is the
18620 // location of the mouse event less the delta that represents
18621 // where the original mousedown happened on the element. We
18622 // need to consider constraints and ticks as well.
18623 var pos = dc.getTargetCoord(pt.x, pt.y);
18625 var el = dc.getDragEl();
18626 var curRegion = new Roo.lib.Region( pos.y,
18627 pos.x + el.offsetWidth,
18628 pos.y + el.offsetHeight,
18631 var overlap = curRegion.intersect(loc);
18634 oTarget.overlap = overlap;
18635 return (intersect) ? true : oTarget.cursorIsOver;
18642 * unload event handler
18643 * @method _onUnload
18647 _onUnload: function(e, me) {
18648 Roo.dd.DragDropMgr.unregAll();
18652 * Cleans up the drag and drop events and objects.
18657 unregAll: function() {
18659 if (this.dragCurrent) {
18661 this.dragCurrent = null;
18664 this._execOnAll("unreg", []);
18666 for (i in this.elementCache) {
18667 delete this.elementCache[i];
18670 this.elementCache = {};
18675 * A cache of DOM elements
18676 * @property elementCache
18683 * Get the wrapper for the DOM element specified
18684 * @method getElWrapper
18685 * @param {String} id the id of the element to get
18686 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18688 * @deprecated This wrapper isn't that useful
18691 getElWrapper: function(id) {
18692 var oWrapper = this.elementCache[id];
18693 if (!oWrapper || !oWrapper.el) {
18694 oWrapper = this.elementCache[id] =
18695 new this.ElementWrapper(Roo.getDom(id));
18701 * Returns the actual DOM element
18702 * @method getElement
18703 * @param {String} id the id of the elment to get
18704 * @return {Object} The element
18705 * @deprecated use Roo.getDom instead
18708 getElement: function(id) {
18709 return Roo.getDom(id);
18713 * Returns the style property for the DOM element (i.e.,
18714 * document.getElById(id).style)
18716 * @param {String} id the id of the elment to get
18717 * @return {Object} The style property of the element
18718 * @deprecated use Roo.getDom instead
18721 getCss: function(id) {
18722 var el = Roo.getDom(id);
18723 return (el) ? el.style : null;
18727 * Inner class for cached elements
18728 * @class DragDropMgr.ElementWrapper
18733 ElementWrapper: function(el) {
18738 this.el = el || null;
18743 this.id = this.el && el.id;
18745 * A reference to the style property
18748 this.css = this.el && el.style;
18752 * Returns the X position of an html element
18754 * @param el the element for which to get the position
18755 * @return {int} the X coordinate
18757 * @deprecated use Roo.lib.Dom.getX instead
18760 getPosX: function(el) {
18761 return Roo.lib.Dom.getX(el);
18765 * Returns the Y position of an html element
18767 * @param el the element for which to get the position
18768 * @return {int} the Y coordinate
18769 * @deprecated use Roo.lib.Dom.getY instead
18772 getPosY: function(el) {
18773 return Roo.lib.Dom.getY(el);
18777 * Swap two nodes. In IE, we use the native method, for others we
18778 * emulate the IE behavior
18780 * @param n1 the first node to swap
18781 * @param n2 the other node to swap
18784 swapNode: function(n1, n2) {
18788 var p = n2.parentNode;
18789 var s = n2.nextSibling;
18792 p.insertBefore(n1, n2);
18793 } else if (n2 == n1.nextSibling) {
18794 p.insertBefore(n2, n1);
18796 n1.parentNode.replaceChild(n2, n1);
18797 p.insertBefore(n1, s);
18803 * Returns the current scroll position
18804 * @method getScroll
18808 getScroll: function () {
18809 var t, l, dde=document.documentElement, db=document.body;
18810 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18812 l = dde.scrollLeft;
18819 return { top: t, left: l };
18823 * Returns the specified element style property
18825 * @param {HTMLElement} el the element
18826 * @param {string} styleProp the style property
18827 * @return {string} The value of the style property
18828 * @deprecated use Roo.lib.Dom.getStyle
18831 getStyle: function(el, styleProp) {
18832 return Roo.fly(el).getStyle(styleProp);
18836 * Gets the scrollTop
18837 * @method getScrollTop
18838 * @return {int} the document's scrollTop
18841 getScrollTop: function () { return this.getScroll().top; },
18844 * Gets the scrollLeft
18845 * @method getScrollLeft
18846 * @return {int} the document's scrollTop
18849 getScrollLeft: function () { return this.getScroll().left; },
18852 * Sets the x/y position of an element to the location of the
18855 * @param {HTMLElement} moveEl The element to move
18856 * @param {HTMLElement} targetEl The position reference element
18859 moveToEl: function (moveEl, targetEl) {
18860 var aCoord = Roo.lib.Dom.getXY(targetEl);
18861 Roo.lib.Dom.setXY(moveEl, aCoord);
18865 * Numeric array sort function
18866 * @method numericSort
18869 numericSort: function(a, b) { return (a - b); },
18873 * @property _timeoutCount
18880 * Trying to make the load order less important. Without this we get
18881 * an error if this file is loaded before the Event Utility.
18882 * @method _addListeners
18886 _addListeners: function() {
18887 var DDM = Roo.dd.DDM;
18888 if ( Roo.lib.Event && document ) {
18891 if (DDM._timeoutCount > 2000) {
18893 setTimeout(DDM._addListeners, 10);
18894 if (document && document.body) {
18895 DDM._timeoutCount += 1;
18902 * Recursively searches the immediate parent and all child nodes for
18903 * the handle element in order to determine wheter or not it was
18905 * @method handleWasClicked
18906 * @param node the html element to inspect
18909 handleWasClicked: function(node, id) {
18910 if (this.isHandle(id, node.id)) {
18913 // check to see if this is a text node child of the one we want
18914 var p = node.parentNode;
18917 if (this.isHandle(id, p.id)) {
18932 // shorter alias, save a few bytes
18933 Roo.dd.DDM = Roo.dd.DragDropMgr;
18934 Roo.dd.DDM._addListeners();
18938 * Ext JS Library 1.1.1
18939 * Copyright(c) 2006-2007, Ext JS, LLC.
18941 * Originally Released Under LGPL - original licence link has changed is not relivant.
18944 * <script type="text/javascript">
18949 * A DragDrop implementation where the linked element follows the
18950 * mouse cursor during a drag.
18951 * @extends Roo.dd.DragDrop
18953 * @param {String} id the id of the linked element
18954 * @param {String} sGroup the group of related DragDrop items
18955 * @param {object} config an object containing configurable attributes
18956 * Valid properties for DD:
18959 Roo.dd.DD = function(id, sGroup, config) {
18961 this.init(id, sGroup, config);
18965 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18968 * When set to true, the utility automatically tries to scroll the browser
18969 * window wehn a drag and drop element is dragged near the viewport boundary.
18970 * Defaults to true.
18977 * Sets the pointer offset to the distance between the linked element's top
18978 * left corner and the location the element was clicked
18979 * @method autoOffset
18980 * @param {int} iPageX the X coordinate of the click
18981 * @param {int} iPageY the Y coordinate of the click
18983 autoOffset: function(iPageX, iPageY) {
18984 var x = iPageX - this.startPageX;
18985 var y = iPageY - this.startPageY;
18986 this.setDelta(x, y);
18990 * Sets the pointer offset. You can call this directly to force the
18991 * offset to be in a particular location (e.g., pass in 0,0 to set it
18992 * to the center of the object)
18994 * @param {int} iDeltaX the distance from the left
18995 * @param {int} iDeltaY the distance from the top
18997 setDelta: function(iDeltaX, iDeltaY) {
18998 this.deltaX = iDeltaX;
18999 this.deltaY = iDeltaY;
19003 * Sets the drag element to the location of the mousedown or click event,
19004 * maintaining the cursor location relative to the location on the element
19005 * that was clicked. Override this if you want to place the element in a
19006 * location other than where the cursor is.
19007 * @method setDragElPos
19008 * @param {int} iPageX the X coordinate of the mousedown or drag event
19009 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19011 setDragElPos: function(iPageX, iPageY) {
19012 // the first time we do this, we are going to check to make sure
19013 // the element has css positioning
19015 var el = this.getDragEl();
19016 this.alignElWithMouse(el, iPageX, iPageY);
19020 * Sets the element to the location of the mousedown or click event,
19021 * maintaining the cursor location relative to the location on the element
19022 * that was clicked. Override this if you want to place the element in a
19023 * location other than where the cursor is.
19024 * @method alignElWithMouse
19025 * @param {HTMLElement} el the element to move
19026 * @param {int} iPageX the X coordinate of the mousedown or drag event
19027 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19029 alignElWithMouse: function(el, iPageX, iPageY) {
19030 var oCoord = this.getTargetCoord(iPageX, iPageY);
19031 var fly = el.dom ? el : Roo.fly(el);
19032 if (!this.deltaSetXY) {
19033 var aCoord = [oCoord.x, oCoord.y];
19035 var newLeft = fly.getLeft(true);
19036 var newTop = fly.getTop(true);
19037 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19039 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19042 this.cachePosition(oCoord.x, oCoord.y);
19043 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19048 * Saves the most recent position so that we can reset the constraints and
19049 * tick marks on-demand. We need to know this so that we can calculate the
19050 * number of pixels the element is offset from its original position.
19051 * @method cachePosition
19052 * @param iPageX the current x position (optional, this just makes it so we
19053 * don't have to look it up again)
19054 * @param iPageY the current y position (optional, this just makes it so we
19055 * don't have to look it up again)
19057 cachePosition: function(iPageX, iPageY) {
19059 this.lastPageX = iPageX;
19060 this.lastPageY = iPageY;
19062 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19063 this.lastPageX = aCoord[0];
19064 this.lastPageY = aCoord[1];
19069 * Auto-scroll the window if the dragged object has been moved beyond the
19070 * visible window boundary.
19071 * @method autoScroll
19072 * @param {int} x the drag element's x position
19073 * @param {int} y the drag element's y position
19074 * @param {int} h the height of the drag element
19075 * @param {int} w the width of the drag element
19078 autoScroll: function(x, y, h, w) {
19081 // The client height
19082 var clientH = Roo.lib.Dom.getViewWidth();
19084 // The client width
19085 var clientW = Roo.lib.Dom.getViewHeight();
19087 // The amt scrolled down
19088 var st = this.DDM.getScrollTop();
19090 // The amt scrolled right
19091 var sl = this.DDM.getScrollLeft();
19093 // Location of the bottom of the element
19096 // Location of the right of the element
19099 // The distance from the cursor to the bottom of the visible area,
19100 // adjusted so that we don't scroll if the cursor is beyond the
19101 // element drag constraints
19102 var toBot = (clientH + st - y - this.deltaY);
19104 // The distance from the cursor to the right of the visible area
19105 var toRight = (clientW + sl - x - this.deltaX);
19108 // How close to the edge the cursor must be before we scroll
19109 // var thresh = (document.all) ? 100 : 40;
19112 // How many pixels to scroll per autoscroll op. This helps to reduce
19113 // clunky scrolling. IE is more sensitive about this ... it needs this
19114 // value to be higher.
19115 var scrAmt = (document.all) ? 80 : 30;
19117 // Scroll down if we are near the bottom of the visible page and the
19118 // obj extends below the crease
19119 if ( bot > clientH && toBot < thresh ) {
19120 window.scrollTo(sl, st + scrAmt);
19123 // Scroll up if the window is scrolled down and the top of the object
19124 // goes above the top border
19125 if ( y < st && st > 0 && y - st < thresh ) {
19126 window.scrollTo(sl, st - scrAmt);
19129 // Scroll right if the obj is beyond the right border and the cursor is
19130 // near the border.
19131 if ( right > clientW && toRight < thresh ) {
19132 window.scrollTo(sl + scrAmt, st);
19135 // Scroll left if the window has been scrolled to the right and the obj
19136 // extends past the left border
19137 if ( x < sl && sl > 0 && x - sl < thresh ) {
19138 window.scrollTo(sl - scrAmt, st);
19144 * Finds the location the element should be placed if we want to move
19145 * it to where the mouse location less the click offset would place us.
19146 * @method getTargetCoord
19147 * @param {int} iPageX the X coordinate of the click
19148 * @param {int} iPageY the Y coordinate of the click
19149 * @return an object that contains the coordinates (Object.x and Object.y)
19152 getTargetCoord: function(iPageX, iPageY) {
19155 var x = iPageX - this.deltaX;
19156 var y = iPageY - this.deltaY;
19158 if (this.constrainX) {
19159 if (x < this.minX) { x = this.minX; }
19160 if (x > this.maxX) { x = this.maxX; }
19163 if (this.constrainY) {
19164 if (y < this.minY) { y = this.minY; }
19165 if (y > this.maxY) { y = this.maxY; }
19168 x = this.getTick(x, this.xTicks);
19169 y = this.getTick(y, this.yTicks);
19176 * Sets up config options specific to this class. Overrides
19177 * Roo.dd.DragDrop, but all versions of this method through the
19178 * inheritance chain are called
19180 applyConfig: function() {
19181 Roo.dd.DD.superclass.applyConfig.call(this);
19182 this.scroll = (this.config.scroll !== false);
19186 * Event that fires prior to the onMouseDown event. Overrides
19189 b4MouseDown: function(e) {
19190 // this.resetConstraints();
19191 this.autoOffset(e.getPageX(),
19196 * Event that fires prior to the onDrag event. Overrides
19199 b4Drag: function(e) {
19200 this.setDragElPos(e.getPageX(),
19204 toString: function() {
19205 return ("DD " + this.id);
19208 //////////////////////////////////////////////////////////////////////////
19209 // Debugging ygDragDrop events that can be overridden
19210 //////////////////////////////////////////////////////////////////////////
19212 startDrag: function(x, y) {
19215 onDrag: function(e) {
19218 onDragEnter: function(e, id) {
19221 onDragOver: function(e, id) {
19224 onDragOut: function(e, id) {
19227 onDragDrop: function(e, id) {
19230 endDrag: function(e) {
19237 * Ext JS Library 1.1.1
19238 * Copyright(c) 2006-2007, Ext JS, LLC.
19240 * Originally Released Under LGPL - original licence link has changed is not relivant.
19243 * <script type="text/javascript">
19247 * @class Roo.dd.DDProxy
19248 * A DragDrop implementation that inserts an empty, bordered div into
19249 * the document that follows the cursor during drag operations. At the time of
19250 * the click, the frame div is resized to the dimensions of the linked html
19251 * element, and moved to the exact location of the linked element.
19253 * References to the "frame" element refer to the single proxy element that
19254 * was created to be dragged in place of all DDProxy elements on the
19257 * @extends Roo.dd.DD
19259 * @param {String} id the id of the linked html element
19260 * @param {String} sGroup the group of related DragDrop objects
19261 * @param {object} config an object containing configurable attributes
19262 * Valid properties for DDProxy in addition to those in DragDrop:
19263 * resizeFrame, centerFrame, dragElId
19265 Roo.dd.DDProxy = function(id, sGroup, config) {
19267 this.init(id, sGroup, config);
19273 * The default drag frame div id
19274 * @property Roo.dd.DDProxy.dragElId
19278 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19280 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19283 * By default we resize the drag frame to be the same size as the element
19284 * we want to drag (this is to get the frame effect). We can turn it off
19285 * if we want a different behavior.
19286 * @property resizeFrame
19292 * By default the frame is positioned exactly where the drag element is, so
19293 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19294 * you do not have constraints on the obj is to have the drag frame centered
19295 * around the cursor. Set centerFrame to true for this effect.
19296 * @property centerFrame
19299 centerFrame: false,
19302 * Creates the proxy element if it does not yet exist
19303 * @method createFrame
19305 createFrame: function() {
19307 var body = document.body;
19309 if (!body || !body.firstChild) {
19310 setTimeout( function() { self.createFrame(); }, 50 );
19314 var div = this.getDragEl();
19317 div = document.createElement("div");
19318 div.id = this.dragElId;
19321 s.position = "absolute";
19322 s.visibility = "hidden";
19324 s.border = "2px solid #aaa";
19327 // appendChild can blow up IE if invoked prior to the window load event
19328 // while rendering a table. It is possible there are other scenarios
19329 // that would cause this to happen as well.
19330 body.insertBefore(div, body.firstChild);
19335 * Initialization for the drag frame element. Must be called in the
19336 * constructor of all subclasses
19337 * @method initFrame
19339 initFrame: function() {
19340 this.createFrame();
19343 applyConfig: function() {
19344 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19346 this.resizeFrame = (this.config.resizeFrame !== false);
19347 this.centerFrame = (this.config.centerFrame);
19348 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19352 * Resizes the drag frame to the dimensions of the clicked object, positions
19353 * it over the object, and finally displays it
19354 * @method showFrame
19355 * @param {int} iPageX X click position
19356 * @param {int} iPageY Y click position
19359 showFrame: function(iPageX, iPageY) {
19360 var el = this.getEl();
19361 var dragEl = this.getDragEl();
19362 var s = dragEl.style;
19364 this._resizeProxy();
19366 if (this.centerFrame) {
19367 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19368 Math.round(parseInt(s.height, 10)/2) );
19371 this.setDragElPos(iPageX, iPageY);
19373 Roo.fly(dragEl).show();
19377 * The proxy is automatically resized to the dimensions of the linked
19378 * element when a drag is initiated, unless resizeFrame is set to false
19379 * @method _resizeProxy
19382 _resizeProxy: function() {
19383 if (this.resizeFrame) {
19384 var el = this.getEl();
19385 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19389 // overrides Roo.dd.DragDrop
19390 b4MouseDown: function(e) {
19391 var x = e.getPageX();
19392 var y = e.getPageY();
19393 this.autoOffset(x, y);
19394 this.setDragElPos(x, y);
19397 // overrides Roo.dd.DragDrop
19398 b4StartDrag: function(x, y) {
19399 // show the drag frame
19400 this.showFrame(x, y);
19403 // overrides Roo.dd.DragDrop
19404 b4EndDrag: function(e) {
19405 Roo.fly(this.getDragEl()).hide();
19408 // overrides Roo.dd.DragDrop
19409 // By default we try to move the element to the last location of the frame.
19410 // This is so that the default behavior mirrors that of Roo.dd.DD.
19411 endDrag: function(e) {
19413 var lel = this.getEl();
19414 var del = this.getDragEl();
19416 // Show the drag frame briefly so we can get its position
19417 del.style.visibility = "";
19420 // Hide the linked element before the move to get around a Safari
19422 lel.style.visibility = "hidden";
19423 Roo.dd.DDM.moveToEl(lel, del);
19424 del.style.visibility = "hidden";
19425 lel.style.visibility = "";
19430 beforeMove : function(){
19434 afterDrag : function(){
19438 toString: function() {
19439 return ("DDProxy " + this.id);
19445 * Ext JS Library 1.1.1
19446 * Copyright(c) 2006-2007, Ext JS, LLC.
19448 * Originally Released Under LGPL - original licence link has changed is not relivant.
19451 * <script type="text/javascript">
19455 * @class Roo.dd.DDTarget
19456 * A DragDrop implementation that does not move, but can be a drop
19457 * target. You would get the same result by simply omitting implementation
19458 * for the event callbacks, but this way we reduce the processing cost of the
19459 * event listener and the callbacks.
19460 * @extends Roo.dd.DragDrop
19462 * @param {String} id the id of the element that is a drop target
19463 * @param {String} sGroup the group of related DragDrop objects
19464 * @param {object} config an object containing configurable attributes
19465 * Valid properties for DDTarget in addition to those in
19469 Roo.dd.DDTarget = function(id, sGroup, config) {
19471 this.initTarget(id, sGroup, config);
19473 if (config.listeners || config.events) {
19474 Roo.dd.DragDrop.superclass.constructor.call(this, {
19475 listeners : config.listeners || {},
19476 events : config.events || {}
19481 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19482 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19483 toString: function() {
19484 return ("DDTarget " + this.id);
19489 * Ext JS Library 1.1.1
19490 * Copyright(c) 2006-2007, Ext JS, LLC.
19492 * Originally Released Under LGPL - original licence link has changed is not relivant.
19495 * <script type="text/javascript">
19500 * @class Roo.dd.ScrollManager
19501 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19502 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19505 Roo.dd.ScrollManager = function(){
19506 var ddm = Roo.dd.DragDropMgr;
19513 var onStop = function(e){
19518 var triggerRefresh = function(){
19519 if(ddm.dragCurrent){
19520 ddm.refreshCache(ddm.dragCurrent.groups);
19524 var doScroll = function(){
19525 if(ddm.dragCurrent){
19526 var dds = Roo.dd.ScrollManager;
19528 if(proc.el.scroll(proc.dir, dds.increment)){
19532 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19537 var clearProc = function(){
19539 clearInterval(proc.id);
19546 var startProc = function(el, dir){
19547 Roo.log('scroll startproc');
19551 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19554 var onFire = function(e, isDrop){
19556 if(isDrop || !ddm.dragCurrent){ return; }
19557 var dds = Roo.dd.ScrollManager;
19558 if(!dragEl || dragEl != ddm.dragCurrent){
19559 dragEl = ddm.dragCurrent;
19560 // refresh regions on drag start
19561 dds.refreshCache();
19564 var xy = Roo.lib.Event.getXY(e);
19565 var pt = new Roo.lib.Point(xy[0], xy[1]);
19566 for(var id in els){
19567 var el = els[id], r = el._region;
19568 if(r && r.contains(pt) && el.isScrollable()){
19569 if(r.bottom - pt.y <= dds.thresh){
19571 startProc(el, "down");
19574 }else if(r.right - pt.x <= dds.thresh){
19576 startProc(el, "left");
19579 }else if(pt.y - r.top <= dds.thresh){
19581 startProc(el, "up");
19584 }else if(pt.x - r.left <= dds.thresh){
19586 startProc(el, "right");
19595 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19596 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19600 * Registers new overflow element(s) to auto scroll
19601 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19603 register : function(el){
19604 if(el instanceof Array){
19605 for(var i = 0, len = el.length; i < len; i++) {
19606 this.register(el[i]);
19612 Roo.dd.ScrollManager.els = els;
19616 * Unregisters overflow element(s) so they are no longer scrolled
19617 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19619 unregister : function(el){
19620 if(el instanceof Array){
19621 for(var i = 0, len = el.length; i < len; i++) {
19622 this.unregister(el[i]);
19631 * The number of pixels from the edge of a container the pointer needs to be to
19632 * trigger scrolling (defaults to 25)
19638 * The number of pixels to scroll in each scroll increment (defaults to 50)
19644 * The frequency of scrolls in milliseconds (defaults to 500)
19650 * True to animate the scroll (defaults to true)
19656 * The animation duration in seconds -
19657 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19663 * Manually trigger a cache refresh.
19665 refreshCache : function(){
19666 for(var id in els){
19667 if(typeof els[id] == 'object'){ // for people extending the object prototype
19668 els[id]._region = els[id].getRegion();
19675 * Ext JS Library 1.1.1
19676 * Copyright(c) 2006-2007, Ext JS, LLC.
19678 * Originally Released Under LGPL - original licence link has changed is not relivant.
19681 * <script type="text/javascript">
19686 * @class Roo.dd.Registry
19687 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19688 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19691 Roo.dd.Registry = function(){
19694 var autoIdSeed = 0;
19696 var getId = function(el, autogen){
19697 if(typeof el == "string"){
19701 if(!id && autogen !== false){
19702 id = "roodd-" + (++autoIdSeed);
19710 * Register a drag drop element
19711 * @param {String|HTMLElement} element The id or DOM node to register
19712 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19713 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19714 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19715 * populated in the data object (if applicable):
19717 Value Description<br />
19718 --------- ------------------------------------------<br />
19719 handles Array of DOM nodes that trigger dragging<br />
19720 for the element being registered<br />
19721 isHandle True if the element passed in triggers<br />
19722 dragging itself, else false
19725 register : function(el, data){
19727 if(typeof el == "string"){
19728 el = document.getElementById(el);
19731 elements[getId(el)] = data;
19732 if(data.isHandle !== false){
19733 handles[data.ddel.id] = data;
19736 var hs = data.handles;
19737 for(var i = 0, len = hs.length; i < len; i++){
19738 handles[getId(hs[i])] = data;
19744 * Unregister a drag drop element
19745 * @param {String|HTMLElement} element The id or DOM node to unregister
19747 unregister : function(el){
19748 var id = getId(el, false);
19749 var data = elements[id];
19751 delete elements[id];
19753 var hs = data.handles;
19754 for(var i = 0, len = hs.length; i < len; i++){
19755 delete handles[getId(hs[i], false)];
19762 * Returns the handle registered for a DOM Node by id
19763 * @param {String|HTMLElement} id The DOM node or id to look up
19764 * @return {Object} handle The custom handle data
19766 getHandle : function(id){
19767 if(typeof id != "string"){ // must be element?
19770 return handles[id];
19774 * Returns the handle that is registered for the DOM node that is the target of the event
19775 * @param {Event} e The event
19776 * @return {Object} handle The custom handle data
19778 getHandleFromEvent : function(e){
19779 var t = Roo.lib.Event.getTarget(e);
19780 return t ? handles[t.id] : null;
19784 * Returns a custom data object that is registered for a DOM node by id
19785 * @param {String|HTMLElement} id The DOM node or id to look up
19786 * @return {Object} data The custom data
19788 getTarget : function(id){
19789 if(typeof id != "string"){ // must be element?
19792 return elements[id];
19796 * Returns a custom data object that is registered for the DOM node that is the target of the event
19797 * @param {Event} e The event
19798 * @return {Object} data The custom data
19800 getTargetFromEvent : function(e){
19801 var t = Roo.lib.Event.getTarget(e);
19802 return t ? elements[t.id] || handles[t.id] : null;
19807 * Ext JS Library 1.1.1
19808 * Copyright(c) 2006-2007, Ext JS, LLC.
19810 * Originally Released Under LGPL - original licence link has changed is not relivant.
19813 * <script type="text/javascript">
19818 * @class Roo.dd.StatusProxy
19819 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19820 * default drag proxy used by all Roo.dd components.
19822 * @param {Object} config
19824 Roo.dd.StatusProxy = function(config){
19825 Roo.apply(this, config);
19826 this.id = this.id || Roo.id();
19827 this.el = new Roo.Layer({
19829 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19830 {tag: "div", cls: "x-dd-drop-icon"},
19831 {tag: "div", cls: "x-dd-drag-ghost"}
19834 shadow: !config || config.shadow !== false
19836 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19837 this.dropStatus = this.dropNotAllowed;
19840 Roo.dd.StatusProxy.prototype = {
19842 * @cfg {String} dropAllowed
19843 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19845 dropAllowed : "x-dd-drop-ok",
19847 * @cfg {String} dropNotAllowed
19848 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19850 dropNotAllowed : "x-dd-drop-nodrop",
19853 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19854 * over the current target element.
19855 * @param {String} cssClass The css class for the new drop status indicator image
19857 setStatus : function(cssClass){
19858 cssClass = cssClass || this.dropNotAllowed;
19859 if(this.dropStatus != cssClass){
19860 this.el.replaceClass(this.dropStatus, cssClass);
19861 this.dropStatus = cssClass;
19866 * Resets the status indicator to the default dropNotAllowed value
19867 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19869 reset : function(clearGhost){
19870 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19871 this.dropStatus = this.dropNotAllowed;
19873 this.ghost.update("");
19878 * Updates the contents of the ghost element
19879 * @param {String} html The html that will replace the current innerHTML of the ghost element
19881 update : function(html){
19882 if(typeof html == "string"){
19883 this.ghost.update(html);
19885 this.ghost.update("");
19886 html.style.margin = "0";
19887 this.ghost.dom.appendChild(html);
19889 // ensure float = none set?? cant remember why though.
19890 var el = this.ghost.dom.firstChild;
19892 Roo.fly(el).setStyle('float', 'none');
19897 * Returns the underlying proxy {@link Roo.Layer}
19898 * @return {Roo.Layer} el
19900 getEl : function(){
19905 * Returns the ghost element
19906 * @return {Roo.Element} el
19908 getGhost : function(){
19914 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19916 hide : function(clear){
19924 * Stops the repair animation if it's currently running
19927 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19933 * Displays this proxy
19940 * Force the Layer to sync its shadow and shim positions to the element
19947 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19948 * invalid drop operation by the item being dragged.
19949 * @param {Array} xy The XY position of the element ([x, y])
19950 * @param {Function} callback The function to call after the repair is complete
19951 * @param {Object} scope The scope in which to execute the callback
19953 repair : function(xy, callback, scope){
19954 this.callback = callback;
19955 this.scope = scope;
19956 if(xy && this.animRepair !== false){
19957 this.el.addClass("x-dd-drag-repair");
19958 this.el.hideUnders(true);
19959 this.anim = this.el.shift({
19960 duration: this.repairDuration || .5,
19964 callback: this.afterRepair,
19968 this.afterRepair();
19973 afterRepair : function(){
19975 if(typeof this.callback == "function"){
19976 this.callback.call(this.scope || this);
19978 this.callback = null;
19983 * Ext JS Library 1.1.1
19984 * Copyright(c) 2006-2007, Ext JS, LLC.
19986 * Originally Released Under LGPL - original licence link has changed is not relivant.
19989 * <script type="text/javascript">
19993 * @class Roo.dd.DragSource
19994 * @extends Roo.dd.DDProxy
19995 * A simple class that provides the basic implementation needed to make any element draggable.
19997 * @param {String/HTMLElement/Element} el The container element
19998 * @param {Object} config
20000 Roo.dd.DragSource = function(el, config){
20001 this.el = Roo.get(el);
20002 this.dragData = {};
20004 Roo.apply(this, config);
20007 this.proxy = new Roo.dd.StatusProxy();
20010 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20011 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20013 this.dragging = false;
20016 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20018 * @cfg {String} dropAllowed
20019 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20021 dropAllowed : "x-dd-drop-ok",
20023 * @cfg {String} dropNotAllowed
20024 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20026 dropNotAllowed : "x-dd-drop-nodrop",
20029 * Returns the data object associated with this drag source
20030 * @return {Object} data An object containing arbitrary data
20032 getDragData : function(e){
20033 return this.dragData;
20037 onDragEnter : function(e, id){
20038 var target = Roo.dd.DragDropMgr.getDDById(id);
20039 this.cachedTarget = target;
20040 if(this.beforeDragEnter(target, e, id) !== false){
20041 if(target.isNotifyTarget){
20042 var status = target.notifyEnter(this, e, this.dragData);
20043 this.proxy.setStatus(status);
20045 this.proxy.setStatus(this.dropAllowed);
20048 if(this.afterDragEnter){
20050 * An empty function by default, but provided so that you can perform a custom action
20051 * when the dragged item enters the drop target by providing an implementation.
20052 * @param {Roo.dd.DragDrop} target The drop target
20053 * @param {Event} e The event object
20054 * @param {String} id The id of the dragged element
20055 * @method afterDragEnter
20057 this.afterDragEnter(target, e, id);
20063 * An empty function by default, but provided so that you can perform a custom action
20064 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20065 * @param {Roo.dd.DragDrop} target The drop target
20066 * @param {Event} e The event object
20067 * @param {String} id The id of the dragged element
20068 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20070 beforeDragEnter : function(target, e, id){
20075 alignElWithMouse: function() {
20076 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20081 onDragOver : function(e, id){
20082 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20083 if(this.beforeDragOver(target, e, id) !== false){
20084 if(target.isNotifyTarget){
20085 var status = target.notifyOver(this, e, this.dragData);
20086 this.proxy.setStatus(status);
20089 if(this.afterDragOver){
20091 * An empty function by default, but provided so that you can perform a custom action
20092 * while the dragged item is over the drop target by providing an implementation.
20093 * @param {Roo.dd.DragDrop} target The drop target
20094 * @param {Event} e The event object
20095 * @param {String} id The id of the dragged element
20096 * @method afterDragOver
20098 this.afterDragOver(target, e, id);
20104 * An empty function by default, but provided so that you can perform a custom action
20105 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20106 * @param {Roo.dd.DragDrop} target The drop target
20107 * @param {Event} e The event object
20108 * @param {String} id The id of the dragged element
20109 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20111 beforeDragOver : function(target, e, id){
20116 onDragOut : function(e, id){
20117 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20118 if(this.beforeDragOut(target, e, id) !== false){
20119 if(target.isNotifyTarget){
20120 target.notifyOut(this, e, this.dragData);
20122 this.proxy.reset();
20123 if(this.afterDragOut){
20125 * An empty function by default, but provided so that you can perform a custom action
20126 * after the dragged item is dragged out of the target without dropping.
20127 * @param {Roo.dd.DragDrop} target The drop target
20128 * @param {Event} e The event object
20129 * @param {String} id The id of the dragged element
20130 * @method afterDragOut
20132 this.afterDragOut(target, e, id);
20135 this.cachedTarget = null;
20139 * An empty function by default, but provided so that you can perform a custom action before the dragged
20140 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20141 * @param {Roo.dd.DragDrop} target The drop target
20142 * @param {Event} e The event object
20143 * @param {String} id The id of the dragged element
20144 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20146 beforeDragOut : function(target, e, id){
20151 onDragDrop : function(e, id){
20152 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20153 if(this.beforeDragDrop(target, e, id) !== false){
20154 if(target.isNotifyTarget){
20155 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20156 this.onValidDrop(target, e, id);
20158 this.onInvalidDrop(target, e, id);
20161 this.onValidDrop(target, e, id);
20164 if(this.afterDragDrop){
20166 * An empty function by default, but provided so that you can perform a custom action
20167 * after a valid drag drop has occurred by providing an implementation.
20168 * @param {Roo.dd.DragDrop} target The drop target
20169 * @param {Event} e The event object
20170 * @param {String} id The id of the dropped element
20171 * @method afterDragDrop
20173 this.afterDragDrop(target, e, id);
20176 delete this.cachedTarget;
20180 * An empty function by default, but provided so that you can perform a custom action before the dragged
20181 * item is dropped onto the target and optionally cancel the onDragDrop.
20182 * @param {Roo.dd.DragDrop} target The drop target
20183 * @param {Event} e The event object
20184 * @param {String} id The id of the dragged element
20185 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20187 beforeDragDrop : function(target, e, id){
20192 onValidDrop : function(target, e, id){
20194 if(this.afterValidDrop){
20196 * An empty function by default, but provided so that you can perform a custom action
20197 * after a valid drop has occurred by providing an implementation.
20198 * @param {Object} target The target DD
20199 * @param {Event} e The event object
20200 * @param {String} id The id of the dropped element
20201 * @method afterInvalidDrop
20203 this.afterValidDrop(target, e, id);
20208 getRepairXY : function(e, data){
20209 return this.el.getXY();
20213 onInvalidDrop : function(target, e, id){
20214 this.beforeInvalidDrop(target, e, id);
20215 if(this.cachedTarget){
20216 if(this.cachedTarget.isNotifyTarget){
20217 this.cachedTarget.notifyOut(this, e, this.dragData);
20219 this.cacheTarget = null;
20221 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20223 if(this.afterInvalidDrop){
20225 * An empty function by default, but provided so that you can perform a custom action
20226 * after an invalid drop has occurred by providing an implementation.
20227 * @param {Event} e The event object
20228 * @param {String} id The id of the dropped element
20229 * @method afterInvalidDrop
20231 this.afterInvalidDrop(e, id);
20236 afterRepair : function(){
20238 this.el.highlight(this.hlColor || "c3daf9");
20240 this.dragging = false;
20244 * An empty function by default, but provided so that you can perform a custom action after an invalid
20245 * drop has occurred.
20246 * @param {Roo.dd.DragDrop} target The drop target
20247 * @param {Event} e The event object
20248 * @param {String} id The id of the dragged element
20249 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20251 beforeInvalidDrop : function(target, e, id){
20256 handleMouseDown : function(e){
20257 if(this.dragging) {
20260 var data = this.getDragData(e);
20261 if(data && this.onBeforeDrag(data, e) !== false){
20262 this.dragData = data;
20264 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20269 * An empty function by default, but provided so that you can perform a custom action before the initial
20270 * drag event begins and optionally cancel it.
20271 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20272 * @param {Event} e The event object
20273 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20275 onBeforeDrag : function(data, e){
20280 * An empty function by default, but provided so that you can perform a custom action once the initial
20281 * drag event has begun. The drag cannot be canceled from this function.
20282 * @param {Number} x The x position of the click on the dragged object
20283 * @param {Number} y The y position of the click on the dragged object
20285 onStartDrag : Roo.emptyFn,
20287 // private - YUI override
20288 startDrag : function(x, y){
20289 this.proxy.reset();
20290 this.dragging = true;
20291 this.proxy.update("");
20292 this.onInitDrag(x, y);
20297 onInitDrag : function(x, y){
20298 var clone = this.el.dom.cloneNode(true);
20299 clone.id = Roo.id(); // prevent duplicate ids
20300 this.proxy.update(clone);
20301 this.onStartDrag(x, y);
20306 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20307 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20309 getProxy : function(){
20314 * Hides the drag source's {@link Roo.dd.StatusProxy}
20316 hideProxy : function(){
20318 this.proxy.reset(true);
20319 this.dragging = false;
20323 triggerCacheRefresh : function(){
20324 Roo.dd.DDM.refreshCache(this.groups);
20327 // private - override to prevent hiding
20328 b4EndDrag: function(e) {
20331 // private - override to prevent moving
20332 endDrag : function(e){
20333 this.onEndDrag(this.dragData, e);
20337 onEndDrag : function(data, e){
20340 // private - pin to cursor
20341 autoOffset : function(x, y) {
20342 this.setDelta(-12, -20);
20346 * Ext JS Library 1.1.1
20347 * Copyright(c) 2006-2007, Ext JS, LLC.
20349 * Originally Released Under LGPL - original licence link has changed is not relivant.
20352 * <script type="text/javascript">
20357 * @class Roo.dd.DropTarget
20358 * @extends Roo.dd.DDTarget
20359 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20360 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20362 * @param {String/HTMLElement/Element} el The container element
20363 * @param {Object} config
20365 Roo.dd.DropTarget = function(el, config){
20366 this.el = Roo.get(el);
20368 var listeners = false; ;
20369 if (config && config.listeners) {
20370 listeners= config.listeners;
20371 delete config.listeners;
20373 Roo.apply(this, config);
20375 if(this.containerScroll){
20376 Roo.dd.ScrollManager.register(this.el);
20380 * @scope Roo.dd.DropTarget
20385 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20386 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20387 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20389 * IMPORTANT : it should set this.overClass and this.dropAllowed
20391 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20392 * @param {Event} e The event
20393 * @param {Object} data An object containing arbitrary data supplied by the drag source
20399 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20400 * This method will be called on every mouse movement while the drag source is over the drop target.
20401 * This default implementation simply returns the dropAllowed config value.
20403 * IMPORTANT : it should set this.dropAllowed
20405 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20406 * @param {Event} e The event
20407 * @param {Object} data An object containing arbitrary data supplied by the drag source
20413 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20414 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20415 * overClass (if any) from the drop element.
20417 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20418 * @param {Event} e The event
20419 * @param {Object} data An object containing arbitrary data supplied by the drag source
20425 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20426 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20427 * implementation that does something to process the drop event and returns true so that the drag source's
20428 * repair action does not run.
20430 * IMPORTANT : it should set this.success
20432 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20433 * @param {Event} e The event
20434 * @param {Object} data An object containing arbitrary data supplied by the drag source
20440 Roo.dd.DropTarget.superclass.constructor.call( this,
20442 this.ddGroup || this.group,
20445 listeners : listeners || {}
20453 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20455 * @cfg {String} overClass
20456 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20459 * @cfg {String} ddGroup
20460 * The drag drop group to handle drop events for
20464 * @cfg {String} dropAllowed
20465 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20467 dropAllowed : "x-dd-drop-ok",
20469 * @cfg {String} dropNotAllowed
20470 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20472 dropNotAllowed : "x-dd-drop-nodrop",
20474 * @cfg {boolean} success
20475 * set this after drop listener..
20479 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20480 * if the drop point is valid for over/enter..
20487 isNotifyTarget : true,
20492 notifyEnter : function(dd, e, data)
20495 this.fireEvent('enter', dd, e, data);
20496 if(this.overClass){
20497 this.el.addClass(this.overClass);
20499 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20500 this.valid ? this.dropAllowed : this.dropNotAllowed
20507 notifyOver : function(dd, e, data)
20510 this.fireEvent('over', dd, e, data);
20511 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20512 this.valid ? this.dropAllowed : this.dropNotAllowed
20519 notifyOut : function(dd, e, data)
20521 this.fireEvent('out', dd, e, data);
20522 if(this.overClass){
20523 this.el.removeClass(this.overClass);
20530 notifyDrop : function(dd, e, data)
20532 this.success = false;
20533 this.fireEvent('drop', dd, e, data);
20534 return this.success;
20538 * Ext JS Library 1.1.1
20539 * Copyright(c) 2006-2007, Ext JS, LLC.
20541 * Originally Released Under LGPL - original licence link has changed is not relivant.
20544 * <script type="text/javascript">
20549 * @class Roo.dd.DragZone
20550 * @extends Roo.dd.DragSource
20551 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20552 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20554 * @param {String/HTMLElement/Element} el The container element
20555 * @param {Object} config
20557 Roo.dd.DragZone = function(el, config){
20558 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20559 if(this.containerScroll){
20560 Roo.dd.ScrollManager.register(this.el);
20564 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20566 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20567 * for auto scrolling during drag operations.
20570 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20571 * method after a failed drop (defaults to "c3daf9" - light blue)
20575 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20576 * for a valid target to drag based on the mouse down. Override this method
20577 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20578 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20579 * @param {EventObject} e The mouse down event
20580 * @return {Object} The dragData
20582 getDragData : function(e){
20583 return Roo.dd.Registry.getHandleFromEvent(e);
20587 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20588 * this.dragData.ddel
20589 * @param {Number} x The x position of the click on the dragged object
20590 * @param {Number} y The y position of the click on the dragged object
20591 * @return {Boolean} true to continue the drag, false to cancel
20593 onInitDrag : function(x, y){
20594 this.proxy.update(this.dragData.ddel.cloneNode(true));
20595 this.onStartDrag(x, y);
20600 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20602 afterRepair : function(){
20604 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20606 this.dragging = false;
20610 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20611 * the XY of this.dragData.ddel
20612 * @param {EventObject} e The mouse up event
20613 * @return {Array} The xy location (e.g. [100, 200])
20615 getRepairXY : function(e){
20616 return Roo.Element.fly(this.dragData.ddel).getXY();
20620 * Ext JS Library 1.1.1
20621 * Copyright(c) 2006-2007, Ext JS, LLC.
20623 * Originally Released Under LGPL - original licence link has changed is not relivant.
20626 * <script type="text/javascript">
20629 * @class Roo.dd.DropZone
20630 * @extends Roo.dd.DropTarget
20631 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20632 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20634 * @param {String/HTMLElement/Element} el The container element
20635 * @param {Object} config
20637 Roo.dd.DropZone = function(el, config){
20638 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20641 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20643 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20644 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20645 * provide your own custom lookup.
20646 * @param {Event} e The event
20647 * @return {Object} data The custom data
20649 getTargetFromEvent : function(e){
20650 return Roo.dd.Registry.getTargetFromEvent(e);
20654 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20655 * that it has registered. This method has no default implementation and should be overridden to provide
20656 * node-specific processing if necessary.
20657 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20658 * {@link #getTargetFromEvent} for this node)
20659 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20660 * @param {Event} e The event
20661 * @param {Object} data An object containing arbitrary data supplied by the drag source
20663 onNodeEnter : function(n, dd, e, data){
20668 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20669 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20670 * overridden to provide the proper feedback.
20671 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20672 * {@link #getTargetFromEvent} for this node)
20673 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20674 * @param {Event} e The event
20675 * @param {Object} data An object containing arbitrary data supplied by the drag source
20676 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20677 * underlying {@link Roo.dd.StatusProxy} can be updated
20679 onNodeOver : function(n, dd, e, data){
20680 return this.dropAllowed;
20684 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20685 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20686 * node-specific processing if necessary.
20687 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20688 * {@link #getTargetFromEvent} for this node)
20689 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20690 * @param {Event} e The event
20691 * @param {Object} data An object containing arbitrary data supplied by the drag source
20693 onNodeOut : function(n, dd, e, data){
20698 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20699 * the drop node. The default implementation returns false, so it should be overridden to provide the
20700 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20701 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20702 * {@link #getTargetFromEvent} for this node)
20703 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20704 * @param {Event} e The event
20705 * @param {Object} data An object containing arbitrary data supplied by the drag source
20706 * @return {Boolean} True if the drop was valid, else false
20708 onNodeDrop : function(n, dd, e, data){
20713 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20714 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20715 * it should be overridden to provide the proper feedback if necessary.
20716 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20717 * @param {Event} e The event
20718 * @param {Object} data An object containing arbitrary data supplied by the drag source
20719 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20720 * underlying {@link Roo.dd.StatusProxy} can be updated
20722 onContainerOver : function(dd, e, data){
20723 return this.dropNotAllowed;
20727 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20728 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20729 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20730 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20731 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20732 * @param {Event} e The event
20733 * @param {Object} data An object containing arbitrary data supplied by the drag source
20734 * @return {Boolean} True if the drop was valid, else false
20736 onContainerDrop : function(dd, e, data){
20741 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20742 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20743 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20744 * you should override this method and provide a custom implementation.
20745 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20746 * @param {Event} e The event
20747 * @param {Object} data An object containing arbitrary data supplied by the drag source
20748 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20749 * underlying {@link Roo.dd.StatusProxy} can be updated
20751 notifyEnter : function(dd, e, data){
20752 return this.dropNotAllowed;
20756 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20757 * This method will be called on every mouse movement while the drag source is over the drop zone.
20758 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20759 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20760 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20761 * registered node, it will call {@link #onContainerOver}.
20762 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20763 * @param {Event} e The event
20764 * @param {Object} data An object containing arbitrary data supplied by the drag source
20765 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20766 * underlying {@link Roo.dd.StatusProxy} can be updated
20768 notifyOver : function(dd, e, data){
20769 var n = this.getTargetFromEvent(e);
20770 if(!n){ // not over valid drop target
20771 if(this.lastOverNode){
20772 this.onNodeOut(this.lastOverNode, dd, e, data);
20773 this.lastOverNode = null;
20775 return this.onContainerOver(dd, e, data);
20777 if(this.lastOverNode != n){
20778 if(this.lastOverNode){
20779 this.onNodeOut(this.lastOverNode, dd, e, data);
20781 this.onNodeEnter(n, dd, e, data);
20782 this.lastOverNode = n;
20784 return this.onNodeOver(n, dd, e, data);
20788 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20789 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20790 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20791 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20792 * @param {Event} e The event
20793 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20795 notifyOut : function(dd, e, data){
20796 if(this.lastOverNode){
20797 this.onNodeOut(this.lastOverNode, dd, e, data);
20798 this.lastOverNode = null;
20803 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20804 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20805 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20806 * otherwise it will call {@link #onContainerDrop}.
20807 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20808 * @param {Event} e The event
20809 * @param {Object} data An object containing arbitrary data supplied by the drag source
20810 * @return {Boolean} True if the drop was valid, else false
20812 notifyDrop : function(dd, e, data){
20813 if(this.lastOverNode){
20814 this.onNodeOut(this.lastOverNode, dd, e, data);
20815 this.lastOverNode = null;
20817 var n = this.getTargetFromEvent(e);
20819 this.onNodeDrop(n, dd, e, data) :
20820 this.onContainerDrop(dd, e, data);
20824 triggerCacheRefresh : function(){
20825 Roo.dd.DDM.refreshCache(this.groups);
20829 * Ext JS Library 1.1.1
20830 * Copyright(c) 2006-2007, Ext JS, LLC.
20832 * Originally Released Under LGPL - original licence link has changed is not relivant.
20835 * <script type="text/javascript">
20840 * @class Roo.data.SortTypes
20842 * Defines the default sorting (casting?) comparison functions used when sorting data.
20844 Roo.data.SortTypes = {
20846 * Default sort that does nothing
20847 * @param {Mixed} s The value being converted
20848 * @return {Mixed} The comparison value
20850 none : function(s){
20855 * The regular expression used to strip tags
20859 stripTagsRE : /<\/?[^>]+>/gi,
20862 * Strips all HTML tags to sort on text only
20863 * @param {Mixed} s The value being converted
20864 * @return {String} The comparison value
20866 asText : function(s){
20867 return String(s).replace(this.stripTagsRE, "");
20871 * Strips all HTML tags to sort on text only - Case insensitive
20872 * @param {Mixed} s The value being converted
20873 * @return {String} The comparison value
20875 asUCText : function(s){
20876 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20880 * Case insensitive string
20881 * @param {Mixed} s The value being converted
20882 * @return {String} The comparison value
20884 asUCString : function(s) {
20885 return String(s).toUpperCase();
20890 * @param {Mixed} s The value being converted
20891 * @return {Number} The comparison value
20893 asDate : function(s) {
20897 if(s instanceof Date){
20898 return s.getTime();
20900 return Date.parse(String(s));
20905 * @param {Mixed} s The value being converted
20906 * @return {Float} The comparison value
20908 asFloat : function(s) {
20909 var val = parseFloat(String(s).replace(/,/g, ""));
20910 if(isNaN(val)) val = 0;
20916 * @param {Mixed} s The value being converted
20917 * @return {Number} The comparison value
20919 asInt : function(s) {
20920 var val = parseInt(String(s).replace(/,/g, ""));
20921 if(isNaN(val)) val = 0;
20926 * Ext JS Library 1.1.1
20927 * Copyright(c) 2006-2007, Ext JS, LLC.
20929 * Originally Released Under LGPL - original licence link has changed is not relivant.
20932 * <script type="text/javascript">
20936 * @class Roo.data.Record
20937 * Instances of this class encapsulate both record <em>definition</em> information, and record
20938 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20939 * to access Records cached in an {@link Roo.data.Store} object.<br>
20941 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20942 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20945 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20947 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20948 * {@link #create}. The parameters are the same.
20949 * @param {Array} data An associative Array of data values keyed by the field name.
20950 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20951 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20952 * not specified an integer id is generated.
20954 Roo.data.Record = function(data, id){
20955 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20960 * Generate a constructor for a specific record layout.
20961 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20962 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20963 * Each field definition object may contain the following properties: <ul>
20964 * <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,
20965 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20966 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20967 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20968 * is being used, then this is a string containing the javascript expression to reference the data relative to
20969 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20970 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20971 * this may be omitted.</p></li>
20972 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20973 * <ul><li>auto (Default, implies no conversion)</li>
20978 * <li>date</li></ul></p></li>
20979 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20980 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20981 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20982 * by the Reader into an object that will be stored in the Record. It is passed the
20983 * following parameters:<ul>
20984 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20986 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20988 * <br>usage:<br><pre><code>
20989 var TopicRecord = Roo.data.Record.create(
20990 {name: 'title', mapping: 'topic_title'},
20991 {name: 'author', mapping: 'username'},
20992 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20993 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20994 {name: 'lastPoster', mapping: 'user2'},
20995 {name: 'excerpt', mapping: 'post_text'}
20998 var myNewRecord = new TopicRecord({
20999 title: 'Do my job please',
21002 lastPost: new Date(),
21003 lastPoster: 'Animal',
21004 excerpt: 'No way dude!'
21006 myStore.add(myNewRecord);
21011 Roo.data.Record.create = function(o){
21012 var f = function(){
21013 f.superclass.constructor.apply(this, arguments);
21015 Roo.extend(f, Roo.data.Record);
21016 var p = f.prototype;
21017 p.fields = new Roo.util.MixedCollection(false, function(field){
21020 for(var i = 0, len = o.length; i < len; i++){
21021 p.fields.add(new Roo.data.Field(o[i]));
21023 f.getField = function(name){
21024 return p.fields.get(name);
21029 Roo.data.Record.AUTO_ID = 1000;
21030 Roo.data.Record.EDIT = 'edit';
21031 Roo.data.Record.REJECT = 'reject';
21032 Roo.data.Record.COMMIT = 'commit';
21034 Roo.data.Record.prototype = {
21036 * Readonly flag - true if this record has been modified.
21045 join : function(store){
21046 this.store = store;
21050 * Set the named field to the specified value.
21051 * @param {String} name The name of the field to set.
21052 * @param {Object} value The value to set the field to.
21054 set : function(name, value){
21055 if(this.data[name] == value){
21059 if(!this.modified){
21060 this.modified = {};
21062 if(typeof this.modified[name] == 'undefined'){
21063 this.modified[name] = this.data[name];
21065 this.data[name] = value;
21066 if(!this.editing && this.store){
21067 this.store.afterEdit(this);
21072 * Get the value of the named field.
21073 * @param {String} name The name of the field to get the value of.
21074 * @return {Object} The value of the field.
21076 get : function(name){
21077 return this.data[name];
21081 beginEdit : function(){
21082 this.editing = true;
21083 this.modified = {};
21087 cancelEdit : function(){
21088 this.editing = false;
21089 delete this.modified;
21093 endEdit : function(){
21094 this.editing = false;
21095 if(this.dirty && this.store){
21096 this.store.afterEdit(this);
21101 * Usually called by the {@link Roo.data.Store} which owns the Record.
21102 * Rejects all changes made to the Record since either creation, or the last commit operation.
21103 * Modified fields are reverted to their original values.
21105 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21106 * of reject operations.
21108 reject : function(){
21109 var m = this.modified;
21111 if(typeof m[n] != "function"){
21112 this.data[n] = m[n];
21115 this.dirty = false;
21116 delete this.modified;
21117 this.editing = false;
21119 this.store.afterReject(this);
21124 * Usually called by the {@link Roo.data.Store} which owns the Record.
21125 * Commits all changes made to the Record since either creation, or the last commit operation.
21127 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21128 * of commit operations.
21130 commit : function(){
21131 this.dirty = false;
21132 delete this.modified;
21133 this.editing = false;
21135 this.store.afterCommit(this);
21140 hasError : function(){
21141 return this.error != null;
21145 clearError : function(){
21150 * Creates a copy of this record.
21151 * @param {String} id (optional) A new record id if you don't want to use this record's id
21154 copy : function(newId) {
21155 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21159 * Ext JS Library 1.1.1
21160 * Copyright(c) 2006-2007, Ext JS, LLC.
21162 * Originally Released Under LGPL - original licence link has changed is not relivant.
21165 * <script type="text/javascript">
21171 * @class Roo.data.Store
21172 * @extends Roo.util.Observable
21173 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21174 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21176 * 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
21177 * has no knowledge of the format of the data returned by the Proxy.<br>
21179 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21180 * instances from the data object. These records are cached and made available through accessor functions.
21182 * Creates a new Store.
21183 * @param {Object} config A config object containing the objects needed for the Store to access data,
21184 * and read the data into Records.
21186 Roo.data.Store = function(config){
21187 this.data = new Roo.util.MixedCollection(false);
21188 this.data.getKey = function(o){
21191 this.baseParams = {};
21193 this.paramNames = {
21198 "multisort" : "_multisort"
21201 if(config && config.data){
21202 this.inlineData = config.data;
21203 delete config.data;
21206 Roo.apply(this, config);
21208 if(this.reader){ // reader passed
21209 this.reader = Roo.factory(this.reader, Roo.data);
21210 this.reader.xmodule = this.xmodule || false;
21211 if(!this.recordType){
21212 this.recordType = this.reader.recordType;
21214 if(this.reader.onMetaChange){
21215 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21219 if(this.recordType){
21220 this.fields = this.recordType.prototype.fields;
21222 this.modified = [];
21226 * @event datachanged
21227 * Fires when the data cache has changed, and a widget which is using this Store
21228 * as a Record cache should refresh its view.
21229 * @param {Store} this
21231 datachanged : true,
21233 * @event metachange
21234 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21235 * @param {Store} this
21236 * @param {Object} meta The JSON metadata
21241 * Fires when Records have been added to the Store
21242 * @param {Store} this
21243 * @param {Roo.data.Record[]} records The array of Records added
21244 * @param {Number} index The index at which the record(s) were added
21249 * Fires when a Record has been removed from the Store
21250 * @param {Store} this
21251 * @param {Roo.data.Record} record The Record that was removed
21252 * @param {Number} index The index at which the record was removed
21257 * Fires when a Record has been updated
21258 * @param {Store} this
21259 * @param {Roo.data.Record} record The Record that was updated
21260 * @param {String} operation The update operation being performed. Value may be one of:
21262 Roo.data.Record.EDIT
21263 Roo.data.Record.REJECT
21264 Roo.data.Record.COMMIT
21270 * Fires when the data cache has been cleared.
21271 * @param {Store} this
21275 * @event beforeload
21276 * Fires before a request is made for a new data object. If the beforeload handler returns false
21277 * the load action will be canceled.
21278 * @param {Store} this
21279 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21283 * @event beforeloadadd
21284 * Fires after a new set of Records has been loaded.
21285 * @param {Store} this
21286 * @param {Roo.data.Record[]} records The Records that were loaded
21287 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21289 beforeloadadd : true,
21292 * Fires after a new set of Records has been loaded, before they are added to the store.
21293 * @param {Store} this
21294 * @param {Roo.data.Record[]} records The Records that were loaded
21295 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21296 * @params {Object} return from reader
21300 * @event loadexception
21301 * Fires if an exception occurs in the Proxy during loading.
21302 * Called with the signature of the Proxy's "loadexception" event.
21303 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21306 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21307 * @param {Object} load options
21308 * @param {Object} jsonData from your request (normally this contains the Exception)
21310 loadexception : true
21314 this.proxy = Roo.factory(this.proxy, Roo.data);
21315 this.proxy.xmodule = this.xmodule || false;
21316 this.relayEvents(this.proxy, ["loadexception"]);
21318 this.sortToggle = {};
21319 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21321 Roo.data.Store.superclass.constructor.call(this);
21323 if(this.inlineData){
21324 this.loadData(this.inlineData);
21325 delete this.inlineData;
21329 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21331 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21332 * without a remote query - used by combo/forms at present.
21336 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21339 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21342 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21343 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21346 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21347 * on any HTTP request
21350 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21353 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21357 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21358 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21360 remoteSort : false,
21363 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21364 * loaded or when a record is removed. (defaults to false).
21366 pruneModifiedRecords : false,
21369 lastOptions : null,
21372 * Add Records to the Store and fires the add event.
21373 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21375 add : function(records){
21376 records = [].concat(records);
21377 for(var i = 0, len = records.length; i < len; i++){
21378 records[i].join(this);
21380 var index = this.data.length;
21381 this.data.addAll(records);
21382 this.fireEvent("add", this, records, index);
21386 * Remove a Record from the Store and fires the remove event.
21387 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21389 remove : function(record){
21390 var index = this.data.indexOf(record);
21391 this.data.removeAt(index);
21392 if(this.pruneModifiedRecords){
21393 this.modified.remove(record);
21395 this.fireEvent("remove", this, record, index);
21399 * Remove all Records from the Store and fires the clear event.
21401 removeAll : function(){
21403 if(this.pruneModifiedRecords){
21404 this.modified = [];
21406 this.fireEvent("clear", this);
21410 * Inserts Records to the Store at the given index and fires the add event.
21411 * @param {Number} index The start index at which to insert the passed Records.
21412 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21414 insert : function(index, records){
21415 records = [].concat(records);
21416 for(var i = 0, len = records.length; i < len; i++){
21417 this.data.insert(index, records[i]);
21418 records[i].join(this);
21420 this.fireEvent("add", this, records, index);
21424 * Get the index within the cache of the passed Record.
21425 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21426 * @return {Number} The index of the passed Record. Returns -1 if not found.
21428 indexOf : function(record){
21429 return this.data.indexOf(record);
21433 * Get the index within the cache of the Record with the passed id.
21434 * @param {String} id The id of the Record to find.
21435 * @return {Number} The index of the Record. Returns -1 if not found.
21437 indexOfId : function(id){
21438 return this.data.indexOfKey(id);
21442 * Get the Record with the specified id.
21443 * @param {String} id The id of the Record to find.
21444 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21446 getById : function(id){
21447 return this.data.key(id);
21451 * Get the Record at the specified index.
21452 * @param {Number} index The index of the Record to find.
21453 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21455 getAt : function(index){
21456 return this.data.itemAt(index);
21460 * Returns a range of Records between specified indices.
21461 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21462 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21463 * @return {Roo.data.Record[]} An array of Records
21465 getRange : function(start, end){
21466 return this.data.getRange(start, end);
21470 storeOptions : function(o){
21471 o = Roo.apply({}, o);
21474 this.lastOptions = o;
21478 * Loads the Record cache from the configured Proxy using the configured Reader.
21480 * If using remote paging, then the first load call must specify the <em>start</em>
21481 * and <em>limit</em> properties in the options.params property to establish the initial
21482 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21484 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21485 * and this call will return before the new data has been loaded. Perform any post-processing
21486 * in a callback function, or in a "load" event handler.</strong>
21488 * @param {Object} options An object containing properties which control loading options:<ul>
21489 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21490 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21491 * passed the following arguments:<ul>
21492 * <li>r : Roo.data.Record[]</li>
21493 * <li>options: Options object from the load call</li>
21494 * <li>success: Boolean success indicator</li></ul></li>
21495 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21496 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21499 load : function(options){
21500 options = options || {};
21501 if(this.fireEvent("beforeload", this, options) !== false){
21502 this.storeOptions(options);
21503 var p = Roo.apply(options.params || {}, this.baseParams);
21504 // if meta was not loaded from remote source.. try requesting it.
21505 if (!this.reader.metaFromRemote) {
21506 p._requestMeta = 1;
21508 if(this.sortInfo && this.remoteSort){
21509 var pn = this.paramNames;
21510 p[pn["sort"]] = this.sortInfo.field;
21511 p[pn["dir"]] = this.sortInfo.direction;
21513 if (this.multiSort) {
21514 var pn = this.paramNames;
21515 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21518 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21523 * Reloads the Record cache from the configured Proxy using the configured Reader and
21524 * the options from the last load operation performed.
21525 * @param {Object} options (optional) An object containing properties which may override the options
21526 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21527 * the most recently used options are reused).
21529 reload : function(options){
21530 this.load(Roo.applyIf(options||{}, this.lastOptions));
21534 // Called as a callback by the Reader during a load operation.
21535 loadRecords : function(o, options, success){
21536 if(!o || success === false){
21537 if(success !== false){
21538 this.fireEvent("load", this, [], options, o);
21540 if(options.callback){
21541 options.callback.call(options.scope || this, [], options, false);
21545 // if data returned failure - throw an exception.
21546 if (o.success === false) {
21547 // show a message if no listener is registered.
21548 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21549 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21551 // loadmask wil be hooked into this..
21552 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21555 var r = o.records, t = o.totalRecords || r.length;
21557 this.fireEvent("beforeloadadd", this, r, options, o);
21559 if(!options || options.add !== true){
21560 if(this.pruneModifiedRecords){
21561 this.modified = [];
21563 for(var i = 0, len = r.length; i < len; i++){
21567 this.data = this.snapshot;
21568 delete this.snapshot;
21571 this.data.addAll(r);
21572 this.totalLength = t;
21574 this.fireEvent("datachanged", this);
21576 this.totalLength = Math.max(t, this.data.length+r.length);
21579 this.fireEvent("load", this, r, options, o);
21580 if(options.callback){
21581 options.callback.call(options.scope || this, r, options, true);
21587 * Loads data from a passed data block. A Reader which understands the format of the data
21588 * must have been configured in the constructor.
21589 * @param {Object} data The data block from which to read the Records. The format of the data expected
21590 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21591 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21593 loadData : function(o, append){
21594 var r = this.reader.readRecords(o);
21595 this.loadRecords(r, {add: append}, true);
21599 * Gets the number of cached records.
21601 * <em>If using paging, this may not be the total size of the dataset. If the data object
21602 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21603 * the data set size</em>
21605 getCount : function(){
21606 return this.data.length || 0;
21610 * Gets the total number of records in the dataset as returned by the server.
21612 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21613 * the dataset size</em>
21615 getTotalCount : function(){
21616 return this.totalLength || 0;
21620 * Returns the sort state of the Store as an object with two properties:
21622 field {String} The name of the field by which the Records are sorted
21623 direction {String} The sort order, "ASC" or "DESC"
21626 getSortState : function(){
21627 return this.sortInfo;
21631 applySort : function(){
21632 if(this.sortInfo && !this.remoteSort){
21633 var s = this.sortInfo, f = s.field;
21634 var st = this.fields.get(f).sortType;
21635 var fn = function(r1, r2){
21636 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21637 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21639 this.data.sort(s.direction, fn);
21640 if(this.snapshot && this.snapshot != this.data){
21641 this.snapshot.sort(s.direction, fn);
21647 * Sets the default sort column and order to be used by the next load operation.
21648 * @param {String} fieldName The name of the field to sort by.
21649 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21651 setDefaultSort : function(field, dir){
21652 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21656 * Sort the Records.
21657 * If remote sorting is used, the sort is performed on the server, and the cache is
21658 * reloaded. If local sorting is used, the cache is sorted internally.
21659 * @param {String} fieldName The name of the field to sort by.
21660 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21662 sort : function(fieldName, dir){
21663 var f = this.fields.get(fieldName);
21665 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21667 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21668 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21673 this.sortToggle[f.name] = dir;
21674 this.sortInfo = {field: f.name, direction: dir};
21675 if(!this.remoteSort){
21677 this.fireEvent("datachanged", this);
21679 this.load(this.lastOptions);
21684 * Calls the specified function for each of the Records in the cache.
21685 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21686 * Returning <em>false</em> aborts and exits the iteration.
21687 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21689 each : function(fn, scope){
21690 this.data.each(fn, scope);
21694 * Gets all records modified since the last commit. Modified records are persisted across load operations
21695 * (e.g., during paging).
21696 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21698 getModifiedRecords : function(){
21699 return this.modified;
21703 createFilterFn : function(property, value, anyMatch){
21704 if(!value.exec){ // not a regex
21705 value = String(value);
21706 if(value.length == 0){
21709 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21711 return function(r){
21712 return value.test(r.data[property]);
21717 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21718 * @param {String} property A field on your records
21719 * @param {Number} start The record index to start at (defaults to 0)
21720 * @param {Number} end The last record index to include (defaults to length - 1)
21721 * @return {Number} The sum
21723 sum : function(property, start, end){
21724 var rs = this.data.items, v = 0;
21725 start = start || 0;
21726 end = (end || end === 0) ? end : rs.length-1;
21728 for(var i = start; i <= end; i++){
21729 v += (rs[i].data[property] || 0);
21735 * Filter the records by a specified property.
21736 * @param {String} field A field on your records
21737 * @param {String/RegExp} value Either a string that the field
21738 * should start with or a RegExp to test against the field
21739 * @param {Boolean} anyMatch True to match any part not just the beginning
21741 filter : function(property, value, anyMatch){
21742 var fn = this.createFilterFn(property, value, anyMatch);
21743 return fn ? this.filterBy(fn) : this.clearFilter();
21747 * Filter by a function. The specified function will be called with each
21748 * record in this data source. If the function returns true the record is included,
21749 * otherwise it is filtered.
21750 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21751 * @param {Object} scope (optional) The scope of the function (defaults to this)
21753 filterBy : function(fn, scope){
21754 this.snapshot = this.snapshot || this.data;
21755 this.data = this.queryBy(fn, scope||this);
21756 this.fireEvent("datachanged", this);
21760 * Query the records by a specified property.
21761 * @param {String} field A field on your records
21762 * @param {String/RegExp} value Either a string that the field
21763 * should start with or a RegExp to test against the field
21764 * @param {Boolean} anyMatch True to match any part not just the beginning
21765 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21767 query : function(property, value, anyMatch){
21768 var fn = this.createFilterFn(property, value, anyMatch);
21769 return fn ? this.queryBy(fn) : this.data.clone();
21773 * Query by a function. The specified function will be called with each
21774 * record in this data source. If the function returns true the record is included
21776 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21777 * @param {Object} scope (optional) The scope of the function (defaults to this)
21778 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21780 queryBy : function(fn, scope){
21781 var data = this.snapshot || this.data;
21782 return data.filterBy(fn, scope||this);
21786 * Collects unique values for a particular dataIndex from this store.
21787 * @param {String} dataIndex The property to collect
21788 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21789 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21790 * @return {Array} An array of the unique values
21792 collect : function(dataIndex, allowNull, bypassFilter){
21793 var d = (bypassFilter === true && this.snapshot) ?
21794 this.snapshot.items : this.data.items;
21795 var v, sv, r = [], l = {};
21796 for(var i = 0, len = d.length; i < len; i++){
21797 v = d[i].data[dataIndex];
21799 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21808 * Revert to a view of the Record cache with no filtering applied.
21809 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21811 clearFilter : function(suppressEvent){
21812 if(this.snapshot && this.snapshot != this.data){
21813 this.data = this.snapshot;
21814 delete this.snapshot;
21815 if(suppressEvent !== true){
21816 this.fireEvent("datachanged", this);
21822 afterEdit : function(record){
21823 if(this.modified.indexOf(record) == -1){
21824 this.modified.push(record);
21826 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21830 afterReject : function(record){
21831 this.modified.remove(record);
21832 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21836 afterCommit : function(record){
21837 this.modified.remove(record);
21838 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21842 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21843 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21845 commitChanges : function(){
21846 var m = this.modified.slice(0);
21847 this.modified = [];
21848 for(var i = 0, len = m.length; i < len; i++){
21854 * Cancel outstanding changes on all changed records.
21856 rejectChanges : function(){
21857 var m = this.modified.slice(0);
21858 this.modified = [];
21859 for(var i = 0, len = m.length; i < len; i++){
21864 onMetaChange : function(meta, rtype, o){
21865 this.recordType = rtype;
21866 this.fields = rtype.prototype.fields;
21867 delete this.snapshot;
21868 this.sortInfo = meta.sortInfo || this.sortInfo;
21869 this.modified = [];
21870 this.fireEvent('metachange', this, this.reader.meta);
21873 moveIndex : function(data, type)
21875 var index = this.indexOf(data);
21877 var newIndex = index + type;
21881 this.insert(newIndex, data);
21886 * Ext JS Library 1.1.1
21887 * Copyright(c) 2006-2007, Ext JS, LLC.
21889 * Originally Released Under LGPL - original licence link has changed is not relivant.
21892 * <script type="text/javascript">
21896 * @class Roo.data.SimpleStore
21897 * @extends Roo.data.Store
21898 * Small helper class to make creating Stores from Array data easier.
21899 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21900 * @cfg {Array} fields An array of field definition objects, or field name strings.
21901 * @cfg {Array} data The multi-dimensional array of data
21903 * @param {Object} config
21905 Roo.data.SimpleStore = function(config){
21906 Roo.data.SimpleStore.superclass.constructor.call(this, {
21908 reader: new Roo.data.ArrayReader({
21911 Roo.data.Record.create(config.fields)
21913 proxy : new Roo.data.MemoryProxy(config.data)
21917 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21919 * Ext JS Library 1.1.1
21920 * Copyright(c) 2006-2007, Ext JS, LLC.
21922 * Originally Released Under LGPL - original licence link has changed is not relivant.
21925 * <script type="text/javascript">
21930 * @extends Roo.data.Store
21931 * @class Roo.data.JsonStore
21932 * Small helper class to make creating Stores for JSON data easier. <br/>
21934 var store = new Roo.data.JsonStore({
21935 url: 'get-images.php',
21937 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21940 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21941 * JsonReader and HttpProxy (unless inline data is provided).</b>
21942 * @cfg {Array} fields An array of field definition objects, or field name strings.
21944 * @param {Object} config
21946 Roo.data.JsonStore = function(c){
21947 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21948 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21949 reader: new Roo.data.JsonReader(c, c.fields)
21952 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21954 * Ext JS Library 1.1.1
21955 * Copyright(c) 2006-2007, Ext JS, LLC.
21957 * Originally Released Under LGPL - original licence link has changed is not relivant.
21960 * <script type="text/javascript">
21964 Roo.data.Field = function(config){
21965 if(typeof config == "string"){
21966 config = {name: config};
21968 Roo.apply(this, config);
21971 this.type = "auto";
21974 var st = Roo.data.SortTypes;
21975 // named sortTypes are supported, here we look them up
21976 if(typeof this.sortType == "string"){
21977 this.sortType = st[this.sortType];
21980 // set default sortType for strings and dates
21981 if(!this.sortType){
21984 this.sortType = st.asUCString;
21987 this.sortType = st.asDate;
21990 this.sortType = st.none;
21995 var stripRe = /[\$,%]/g;
21997 // prebuilt conversion function for this field, instead of
21998 // switching every time we're reading a value
22000 var cv, dateFormat = this.dateFormat;
22005 cv = function(v){ return v; };
22008 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22012 return v !== undefined && v !== null && v !== '' ?
22013 parseInt(String(v).replace(stripRe, ""), 10) : '';
22018 return v !== undefined && v !== null && v !== '' ?
22019 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22024 cv = function(v){ return v === true || v === "true" || v == 1; };
22031 if(v instanceof Date){
22035 if(dateFormat == "timestamp"){
22036 return new Date(v*1000);
22038 return Date.parseDate(v, dateFormat);
22040 var parsed = Date.parse(v);
22041 return parsed ? new Date(parsed) : null;
22050 Roo.data.Field.prototype = {
22058 * Ext JS Library 1.1.1
22059 * Copyright(c) 2006-2007, Ext JS, LLC.
22061 * Originally Released Under LGPL - original licence link has changed is not relivant.
22064 * <script type="text/javascript">
22067 // Base class for reading structured data from a data source. This class is intended to be
22068 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22071 * @class Roo.data.DataReader
22072 * Base class for reading structured data from a data source. This class is intended to be
22073 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22076 Roo.data.DataReader = function(meta, recordType){
22080 this.recordType = recordType instanceof Array ?
22081 Roo.data.Record.create(recordType) : recordType;
22084 Roo.data.DataReader.prototype = {
22086 * Create an empty record
22087 * @param {Object} data (optional) - overlay some values
22088 * @return {Roo.data.Record} record created.
22090 newRow : function(d) {
22092 this.recordType.prototype.fields.each(function(c) {
22094 case 'int' : da[c.name] = 0; break;
22095 case 'date' : da[c.name] = new Date(); break;
22096 case 'float' : da[c.name] = 0.0; break;
22097 case 'boolean' : da[c.name] = false; break;
22098 default : da[c.name] = ""; break;
22102 return new this.recordType(Roo.apply(da, d));
22107 * Ext JS Library 1.1.1
22108 * Copyright(c) 2006-2007, Ext JS, LLC.
22110 * Originally Released Under LGPL - original licence link has changed is not relivant.
22113 * <script type="text/javascript">
22117 * @class Roo.data.DataProxy
22118 * @extends Roo.data.Observable
22119 * This class is an abstract base class for implementations which provide retrieval of
22120 * unformatted data objects.<br>
22122 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22123 * (of the appropriate type which knows how to parse the data object) to provide a block of
22124 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22126 * Custom implementations must implement the load method as described in
22127 * {@link Roo.data.HttpProxy#load}.
22129 Roo.data.DataProxy = function(){
22132 * @event beforeload
22133 * Fires before a network request is made to retrieve a data object.
22134 * @param {Object} This DataProxy object.
22135 * @param {Object} params The params parameter to the load function.
22140 * Fires before the load method's callback is called.
22141 * @param {Object} This DataProxy object.
22142 * @param {Object} o The data object.
22143 * @param {Object} arg The callback argument object passed to the load function.
22147 * @event loadexception
22148 * Fires if an Exception occurs during data retrieval.
22149 * @param {Object} This DataProxy object.
22150 * @param {Object} o The data object.
22151 * @param {Object} arg The callback argument object passed to the load function.
22152 * @param {Object} e The Exception.
22154 loadexception : true
22156 Roo.data.DataProxy.superclass.constructor.call(this);
22159 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22162 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22166 * Ext JS Library 1.1.1
22167 * Copyright(c) 2006-2007, Ext JS, LLC.
22169 * Originally Released Under LGPL - original licence link has changed is not relivant.
22172 * <script type="text/javascript">
22175 * @class Roo.data.MemoryProxy
22176 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22177 * to the Reader when its load method is called.
22179 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22181 Roo.data.MemoryProxy = function(data){
22185 Roo.data.MemoryProxy.superclass.constructor.call(this);
22189 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22191 * Load data from the requested source (in this case an in-memory
22192 * data object passed to the constructor), read the data object into
22193 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22194 * process that block using the passed callback.
22195 * @param {Object} params This parameter is not used by the MemoryProxy class.
22196 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22197 * object into a block of Roo.data.Records.
22198 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22199 * The function must be passed <ul>
22200 * <li>The Record block object</li>
22201 * <li>The "arg" argument from the load function</li>
22202 * <li>A boolean success indicator</li>
22204 * @param {Object} scope The scope in which to call the callback
22205 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22207 load : function(params, reader, callback, scope, arg){
22208 params = params || {};
22211 result = reader.readRecords(this.data);
22213 this.fireEvent("loadexception", this, arg, null, e);
22214 callback.call(scope, null, arg, false);
22217 callback.call(scope, result, arg, true);
22221 update : function(params, records){
22226 * Ext JS Library 1.1.1
22227 * Copyright(c) 2006-2007, Ext JS, LLC.
22229 * Originally Released Under LGPL - original licence link has changed is not relivant.
22232 * <script type="text/javascript">
22235 * @class Roo.data.HttpProxy
22236 * @extends Roo.data.DataProxy
22237 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22238 * configured to reference a certain URL.<br><br>
22240 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22241 * from which the running page was served.<br><br>
22243 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22245 * Be aware that to enable the browser to parse an XML document, the server must set
22246 * the Content-Type header in the HTTP response to "text/xml".
22248 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22249 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22250 * will be used to make the request.
22252 Roo.data.HttpProxy = function(conn){
22253 Roo.data.HttpProxy.superclass.constructor.call(this);
22254 // is conn a conn config or a real conn?
22256 this.useAjax = !conn || !conn.events;
22260 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22261 // thse are take from connection...
22264 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22267 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22268 * extra parameters to each request made by this object. (defaults to undefined)
22271 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22272 * to each request made by this object. (defaults to undefined)
22275 * @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)
22278 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22281 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22287 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22291 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22292 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22293 * a finer-grained basis than the DataProxy events.
22295 getConnection : function(){
22296 return this.useAjax ? Roo.Ajax : this.conn;
22300 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22301 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22302 * process that block using the passed callback.
22303 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22304 * for the request to the remote server.
22305 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22306 * object into a block of Roo.data.Records.
22307 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22308 * The function must be passed <ul>
22309 * <li>The Record block object</li>
22310 * <li>The "arg" argument from the load function</li>
22311 * <li>A boolean success indicator</li>
22313 * @param {Object} scope The scope in which to call the callback
22314 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22316 load : function(params, reader, callback, scope, arg){
22317 if(this.fireEvent("beforeload", this, params) !== false){
22319 params : params || {},
22321 callback : callback,
22326 callback : this.loadResponse,
22330 Roo.applyIf(o, this.conn);
22331 if(this.activeRequest){
22332 Roo.Ajax.abort(this.activeRequest);
22334 this.activeRequest = Roo.Ajax.request(o);
22336 this.conn.request(o);
22339 callback.call(scope||this, null, arg, false);
22344 loadResponse : function(o, success, response){
22345 delete this.activeRequest;
22347 this.fireEvent("loadexception", this, o, response);
22348 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22353 result = o.reader.read(response);
22355 this.fireEvent("loadexception", this, o, response, e);
22356 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22360 this.fireEvent("load", this, o, o.request.arg);
22361 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22365 update : function(dataSet){
22370 updateResponse : function(dataSet){
22375 * Ext JS Library 1.1.1
22376 * Copyright(c) 2006-2007, Ext JS, LLC.
22378 * Originally Released Under LGPL - original licence link has changed is not relivant.
22381 * <script type="text/javascript">
22385 * @class Roo.data.ScriptTagProxy
22386 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22387 * other than the originating domain of the running page.<br><br>
22389 * <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
22390 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22392 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22393 * source code that is used as the source inside a <script> tag.<br><br>
22395 * In order for the browser to process the returned data, the server must wrap the data object
22396 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22397 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22398 * depending on whether the callback name was passed:
22401 boolean scriptTag = false;
22402 String cb = request.getParameter("callback");
22405 response.setContentType("text/javascript");
22407 response.setContentType("application/x-json");
22409 Writer out = response.getWriter();
22411 out.write(cb + "(");
22413 out.print(dataBlock.toJsonString());
22420 * @param {Object} config A configuration object.
22422 Roo.data.ScriptTagProxy = function(config){
22423 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22424 Roo.apply(this, config);
22425 this.head = document.getElementsByTagName("head")[0];
22428 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22430 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22432 * @cfg {String} url The URL from which to request the data object.
22435 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22439 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22440 * the server the name of the callback function set up by the load call to process the returned data object.
22441 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22442 * javascript output which calls this named function passing the data object as its only parameter.
22444 callbackParam : "callback",
22446 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22447 * name to the request.
22452 * Load data from the configured URL, read the data object into
22453 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22454 * process that block using the passed callback.
22455 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22456 * for the request to the remote server.
22457 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22458 * object into a block of Roo.data.Records.
22459 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22460 * The function must be passed <ul>
22461 * <li>The Record block object</li>
22462 * <li>The "arg" argument from the load function</li>
22463 * <li>A boolean success indicator</li>
22465 * @param {Object} scope The scope in which to call the callback
22466 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22468 load : function(params, reader, callback, scope, arg){
22469 if(this.fireEvent("beforeload", this, params) !== false){
22471 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22473 var url = this.url;
22474 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22476 url += "&_dc=" + (new Date().getTime());
22478 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22481 cb : "stcCallback"+transId,
22482 scriptId : "stcScript"+transId,
22486 callback : callback,
22492 window[trans.cb] = function(o){
22493 conn.handleResponse(o, trans);
22496 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22498 if(this.autoAbort !== false){
22502 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22504 var script = document.createElement("script");
22505 script.setAttribute("src", url);
22506 script.setAttribute("type", "text/javascript");
22507 script.setAttribute("id", trans.scriptId);
22508 this.head.appendChild(script);
22510 this.trans = trans;
22512 callback.call(scope||this, null, arg, false);
22517 isLoading : function(){
22518 return this.trans ? true : false;
22522 * Abort the current server request.
22524 abort : function(){
22525 if(this.isLoading()){
22526 this.destroyTrans(this.trans);
22531 destroyTrans : function(trans, isLoaded){
22532 this.head.removeChild(document.getElementById(trans.scriptId));
22533 clearTimeout(trans.timeoutId);
22535 window[trans.cb] = undefined;
22537 delete window[trans.cb];
22540 // if hasn't been loaded, wait for load to remove it to prevent script error
22541 window[trans.cb] = function(){
22542 window[trans.cb] = undefined;
22544 delete window[trans.cb];
22551 handleResponse : function(o, trans){
22552 this.trans = false;
22553 this.destroyTrans(trans, true);
22556 result = trans.reader.readRecords(o);
22558 this.fireEvent("loadexception", this, o, trans.arg, e);
22559 trans.callback.call(trans.scope||window, null, trans.arg, false);
22562 this.fireEvent("load", this, o, trans.arg);
22563 trans.callback.call(trans.scope||window, result, trans.arg, true);
22567 handleFailure : function(trans){
22568 this.trans = false;
22569 this.destroyTrans(trans, false);
22570 this.fireEvent("loadexception", this, null, trans.arg);
22571 trans.callback.call(trans.scope||window, null, trans.arg, false);
22575 * Ext JS Library 1.1.1
22576 * Copyright(c) 2006-2007, Ext JS, LLC.
22578 * Originally Released Under LGPL - original licence link has changed is not relivant.
22581 * <script type="text/javascript">
22585 * @class Roo.data.JsonReader
22586 * @extends Roo.data.DataReader
22587 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22588 * based on mappings in a provided Roo.data.Record constructor.
22590 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22591 * in the reply previously.
22596 var RecordDef = Roo.data.Record.create([
22597 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22598 {name: 'occupation'} // This field will use "occupation" as the mapping.
22600 var myReader = new Roo.data.JsonReader({
22601 totalProperty: "results", // The property which contains the total dataset size (optional)
22602 root: "rows", // The property which contains an Array of row objects
22603 id: "id" // The property within each row object that provides an ID for the record (optional)
22607 * This would consume a JSON file like this:
22609 { 'results': 2, 'rows': [
22610 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22611 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22614 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22615 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22616 * paged from the remote server.
22617 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22618 * @cfg {String} root name of the property which contains the Array of row objects.
22619 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22620 * @cfg {Array} fields Array of field definition objects
22622 * Create a new JsonReader
22623 * @param {Object} meta Metadata configuration options
22624 * @param {Object} recordType Either an Array of field definition objects,
22625 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22627 Roo.data.JsonReader = function(meta, recordType){
22630 // set some defaults:
22631 Roo.applyIf(meta, {
22632 totalProperty: 'total',
22633 successProperty : 'success',
22638 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22640 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22643 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22644 * Used by Store query builder to append _requestMeta to params.
22647 metaFromRemote : false,
22649 * This method is only used by a DataProxy which has retrieved data from a remote server.
22650 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22651 * @return {Object} data A data block which is used by an Roo.data.Store object as
22652 * a cache of Roo.data.Records.
22654 read : function(response){
22655 var json = response.responseText;
22657 var o = /* eval:var:o */ eval("("+json+")");
22659 throw {message: "JsonReader.read: Json object not found"};
22665 this.metaFromRemote = true;
22666 this.meta = o.metaData;
22667 this.recordType = Roo.data.Record.create(o.metaData.fields);
22668 this.onMetaChange(this.meta, this.recordType, o);
22670 return this.readRecords(o);
22673 // private function a store will implement
22674 onMetaChange : function(meta, recordType, o){
22681 simpleAccess: function(obj, subsc) {
22688 getJsonAccessor: function(){
22690 return function(expr) {
22692 return(re.test(expr))
22693 ? new Function("obj", "return obj." + expr)
22698 return Roo.emptyFn;
22703 * Create a data block containing Roo.data.Records from an XML document.
22704 * @param {Object} o An object which contains an Array of row objects in the property specified
22705 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22706 * which contains the total size of the dataset.
22707 * @return {Object} data A data block which is used by an Roo.data.Store object as
22708 * a cache of Roo.data.Records.
22710 readRecords : function(o){
22712 * After any data loads, the raw JSON data is available for further custom processing.
22716 var s = this.meta, Record = this.recordType,
22717 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22719 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22721 if(s.totalProperty) {
22722 this.getTotal = this.getJsonAccessor(s.totalProperty);
22724 if(s.successProperty) {
22725 this.getSuccess = this.getJsonAccessor(s.successProperty);
22727 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22729 var g = this.getJsonAccessor(s.id);
22730 this.getId = function(rec) {
22732 return (r === undefined || r === "") ? null : r;
22735 this.getId = function(){return null;};
22738 for(var jj = 0; jj < fl; jj++){
22740 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22741 this.ef[jj] = this.getJsonAccessor(map);
22745 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22746 if(s.totalProperty){
22747 var vt = parseInt(this.getTotal(o), 10);
22752 if(s.successProperty){
22753 var vs = this.getSuccess(o);
22754 if(vs === false || vs === 'false'){
22759 for(var i = 0; i < c; i++){
22762 var id = this.getId(n);
22763 for(var j = 0; j < fl; j++){
22765 var v = this.ef[j](n);
22767 Roo.log('missing convert for ' + f.name);
22771 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22773 var record = new Record(values, id);
22775 records[i] = record;
22781 totalRecords : totalRecords
22786 * Ext JS Library 1.1.1
22787 * Copyright(c) 2006-2007, Ext JS, LLC.
22789 * Originally Released Under LGPL - original licence link has changed is not relivant.
22792 * <script type="text/javascript">
22796 * @class Roo.data.XmlReader
22797 * @extends Roo.data.DataReader
22798 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22799 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22801 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22802 * header in the HTTP response must be set to "text/xml".</em>
22806 var RecordDef = Roo.data.Record.create([
22807 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22808 {name: 'occupation'} // This field will use "occupation" as the mapping.
22810 var myReader = new Roo.data.XmlReader({
22811 totalRecords: "results", // The element which contains the total dataset size (optional)
22812 record: "row", // The repeated element which contains row information
22813 id: "id" // The element within the row that provides an ID for the record (optional)
22817 * This would consume an XML file like this:
22821 <results>2</results>
22824 <name>Bill</name>
22825 <occupation>Gardener</occupation>
22829 <name>Ben</name>
22830 <occupation>Horticulturalist</occupation>
22834 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22835 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22836 * paged from the remote server.
22837 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22838 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22839 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22840 * a record identifier value.
22842 * Create a new XmlReader
22843 * @param {Object} meta Metadata configuration options
22844 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22845 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22846 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22848 Roo.data.XmlReader = function(meta, recordType){
22850 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22852 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22854 * This method is only used by a DataProxy which has retrieved data from a remote server.
22855 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22856 * to contain a method called 'responseXML' that returns an XML document object.
22857 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22858 * a cache of Roo.data.Records.
22860 read : function(response){
22861 var doc = response.responseXML;
22863 throw {message: "XmlReader.read: XML Document not available"};
22865 return this.readRecords(doc);
22869 * Create a data block containing Roo.data.Records from an XML document.
22870 * @param {Object} doc A parsed XML document.
22871 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22872 * a cache of Roo.data.Records.
22874 readRecords : function(doc){
22876 * After any data loads/reads, the raw XML Document is available for further custom processing.
22877 * @type XMLDocument
22879 this.xmlData = doc;
22880 var root = doc.documentElement || doc;
22881 var q = Roo.DomQuery;
22882 var recordType = this.recordType, fields = recordType.prototype.fields;
22883 var sid = this.meta.id;
22884 var totalRecords = 0, success = true;
22885 if(this.meta.totalRecords){
22886 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22889 if(this.meta.success){
22890 var sv = q.selectValue(this.meta.success, root, true);
22891 success = sv !== false && sv !== 'false';
22894 var ns = q.select(this.meta.record, root);
22895 for(var i = 0, len = ns.length; i < len; i++) {
22898 var id = sid ? q.selectValue(sid, n) : undefined;
22899 for(var j = 0, jlen = fields.length; j < jlen; j++){
22900 var f = fields.items[j];
22901 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22903 values[f.name] = v;
22905 var record = new recordType(values, id);
22907 records[records.length] = record;
22913 totalRecords : totalRecords || records.length
22918 * Ext JS Library 1.1.1
22919 * Copyright(c) 2006-2007, Ext JS, LLC.
22921 * Originally Released Under LGPL - original licence link has changed is not relivant.
22924 * <script type="text/javascript">
22928 * @class Roo.data.ArrayReader
22929 * @extends Roo.data.DataReader
22930 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22931 * Each element of that Array represents a row of data fields. The
22932 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22933 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22937 var RecordDef = Roo.data.Record.create([
22938 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22939 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22941 var myReader = new Roo.data.ArrayReader({
22942 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22946 * This would consume an Array like this:
22948 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22950 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22952 * Create a new JsonReader
22953 * @param {Object} meta Metadata configuration options.
22954 * @param {Object} recordType Either an Array of field definition objects
22955 * as specified to {@link Roo.data.Record#create},
22956 * or an {@link Roo.data.Record} object
22957 * created using {@link Roo.data.Record#create}.
22959 Roo.data.ArrayReader = function(meta, recordType){
22960 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22963 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22965 * Create a data block containing Roo.data.Records from an XML document.
22966 * @param {Object} o An Array of row objects which represents the dataset.
22967 * @return {Object} data A data block which is used by an Roo.data.Store object as
22968 * a cache of Roo.data.Records.
22970 readRecords : function(o){
22971 var sid = this.meta ? this.meta.id : null;
22972 var recordType = this.recordType, fields = recordType.prototype.fields;
22975 for(var i = 0; i < root.length; i++){
22978 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22979 for(var j = 0, jlen = fields.length; j < jlen; j++){
22980 var f = fields.items[j];
22981 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22982 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22984 values[f.name] = v;
22986 var record = new recordType(values, id);
22988 records[records.length] = record;
22992 totalRecords : records.length
22997 * Ext JS Library 1.1.1
22998 * Copyright(c) 2006-2007, Ext JS, LLC.
23000 * Originally Released Under LGPL - original licence link has changed is not relivant.
23003 * <script type="text/javascript">
23008 * @class Roo.data.Tree
23009 * @extends Roo.util.Observable
23010 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23011 * in the tree have most standard DOM functionality.
23013 * @param {Node} root (optional) The root node
23015 Roo.data.Tree = function(root){
23016 this.nodeHash = {};
23018 * The root node for this tree
23023 this.setRootNode(root);
23028 * Fires when a new child node is appended to a node in this tree.
23029 * @param {Tree} tree The owner tree
23030 * @param {Node} parent The parent node
23031 * @param {Node} node The newly appended node
23032 * @param {Number} index The index of the newly appended node
23037 * Fires when a child node is removed from a node in this tree.
23038 * @param {Tree} tree The owner tree
23039 * @param {Node} parent The parent node
23040 * @param {Node} node The child node removed
23045 * Fires when a node is moved to a new location in the tree
23046 * @param {Tree} tree The owner tree
23047 * @param {Node} node The node moved
23048 * @param {Node} oldParent The old parent of this node
23049 * @param {Node} newParent The new parent of this node
23050 * @param {Number} index The index it was moved to
23055 * Fires when a new child node is inserted in a node in this tree.
23056 * @param {Tree} tree The owner tree
23057 * @param {Node} parent The parent node
23058 * @param {Node} node The child node inserted
23059 * @param {Node} refNode The child node the node was inserted before
23063 * @event beforeappend
23064 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23065 * @param {Tree} tree The owner tree
23066 * @param {Node} parent The parent node
23067 * @param {Node} node The child node to be appended
23069 "beforeappend" : true,
23071 * @event beforeremove
23072 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23073 * @param {Tree} tree The owner tree
23074 * @param {Node} parent The parent node
23075 * @param {Node} node The child node to be removed
23077 "beforeremove" : true,
23079 * @event beforemove
23080 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23081 * @param {Tree} tree The owner tree
23082 * @param {Node} node The node being moved
23083 * @param {Node} oldParent The parent of the node
23084 * @param {Node} newParent The new parent the node is moving to
23085 * @param {Number} index The index it is being moved to
23087 "beforemove" : true,
23089 * @event beforeinsert
23090 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23091 * @param {Tree} tree The owner tree
23092 * @param {Node} parent The parent node
23093 * @param {Node} node The child node to be inserted
23094 * @param {Node} refNode The child node the node is being inserted before
23096 "beforeinsert" : true
23099 Roo.data.Tree.superclass.constructor.call(this);
23102 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23103 pathSeparator: "/",
23105 proxyNodeEvent : function(){
23106 return this.fireEvent.apply(this, arguments);
23110 * Returns the root node for this tree.
23113 getRootNode : function(){
23118 * Sets the root node for this tree.
23119 * @param {Node} node
23122 setRootNode : function(node){
23124 node.ownerTree = this;
23125 node.isRoot = true;
23126 this.registerNode(node);
23131 * Gets a node in this tree by its id.
23132 * @param {String} id
23135 getNodeById : function(id){
23136 return this.nodeHash[id];
23139 registerNode : function(node){
23140 this.nodeHash[node.id] = node;
23143 unregisterNode : function(node){
23144 delete this.nodeHash[node.id];
23147 toString : function(){
23148 return "[Tree"+(this.id?" "+this.id:"")+"]";
23153 * @class Roo.data.Node
23154 * @extends Roo.util.Observable
23155 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23156 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23158 * @param {Object} attributes The attributes/config for the node
23160 Roo.data.Node = function(attributes){
23162 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23165 this.attributes = attributes || {};
23166 this.leaf = this.attributes.leaf;
23168 * The node id. @type String
23170 this.id = this.attributes.id;
23172 this.id = Roo.id(null, "ynode-");
23173 this.attributes.id = this.id;
23178 * All child nodes of this node. @type Array
23180 this.childNodes = [];
23181 if(!this.childNodes.indexOf){ // indexOf is a must
23182 this.childNodes.indexOf = function(o){
23183 for(var i = 0, len = this.length; i < len; i++){
23192 * The parent node for this node. @type Node
23194 this.parentNode = null;
23196 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23198 this.firstChild = null;
23200 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23202 this.lastChild = null;
23204 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23206 this.previousSibling = null;
23208 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23210 this.nextSibling = null;
23215 * Fires when a new child node is appended
23216 * @param {Tree} tree The owner tree
23217 * @param {Node} this This node
23218 * @param {Node} node The newly appended node
23219 * @param {Number} index The index of the newly appended node
23224 * Fires when a child node is removed
23225 * @param {Tree} tree The owner tree
23226 * @param {Node} this This node
23227 * @param {Node} node The removed node
23232 * Fires when this node is moved to a new location in the tree
23233 * @param {Tree} tree The owner tree
23234 * @param {Node} this This node
23235 * @param {Node} oldParent The old parent of this node
23236 * @param {Node} newParent The new parent of this node
23237 * @param {Number} index The index it was moved to
23242 * Fires when a new child node is inserted.
23243 * @param {Tree} tree The owner tree
23244 * @param {Node} this This node
23245 * @param {Node} node The child node inserted
23246 * @param {Node} refNode The child node the node was inserted before
23250 * @event beforeappend
23251 * Fires before a new child is appended, return false to cancel the append.
23252 * @param {Tree} tree The owner tree
23253 * @param {Node} this This node
23254 * @param {Node} node The child node to be appended
23256 "beforeappend" : true,
23258 * @event beforeremove
23259 * Fires before a child is removed, return false to cancel the remove.
23260 * @param {Tree} tree The owner tree
23261 * @param {Node} this This node
23262 * @param {Node} node The child node to be removed
23264 "beforeremove" : true,
23266 * @event beforemove
23267 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23268 * @param {Tree} tree The owner tree
23269 * @param {Node} this This node
23270 * @param {Node} oldParent The parent of this node
23271 * @param {Node} newParent The new parent this node is moving to
23272 * @param {Number} index The index it is being moved to
23274 "beforemove" : true,
23276 * @event beforeinsert
23277 * Fires before a new child is inserted, return false to cancel the insert.
23278 * @param {Tree} tree The owner tree
23279 * @param {Node} this This node
23280 * @param {Node} node The child node to be inserted
23281 * @param {Node} refNode The child node the node is being inserted before
23283 "beforeinsert" : true
23285 this.listeners = this.attributes.listeners;
23286 Roo.data.Node.superclass.constructor.call(this);
23289 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23290 fireEvent : function(evtName){
23291 // first do standard event for this node
23292 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23295 // then bubble it up to the tree if the event wasn't cancelled
23296 var ot = this.getOwnerTree();
23298 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23306 * Returns true if this node is a leaf
23307 * @return {Boolean}
23309 isLeaf : function(){
23310 return this.leaf === true;
23314 setFirstChild : function(node){
23315 this.firstChild = node;
23319 setLastChild : function(node){
23320 this.lastChild = node;
23325 * Returns true if this node is the last child of its parent
23326 * @return {Boolean}
23328 isLast : function(){
23329 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23333 * Returns true if this node is the first child of its parent
23334 * @return {Boolean}
23336 isFirst : function(){
23337 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23340 hasChildNodes : function(){
23341 return !this.isLeaf() && this.childNodes.length > 0;
23345 * Insert node(s) as the last child node of this node.
23346 * @param {Node/Array} node The node or Array of nodes to append
23347 * @return {Node} The appended node if single append, or null if an array was passed
23349 appendChild : function(node){
23351 if(node instanceof Array){
23353 }else if(arguments.length > 1){
23356 // if passed an array or multiple args do them one by one
23358 for(var i = 0, len = multi.length; i < len; i++) {
23359 this.appendChild(multi[i]);
23362 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23365 var index = this.childNodes.length;
23366 var oldParent = node.parentNode;
23367 // it's a move, make sure we move it cleanly
23369 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23372 oldParent.removeChild(node);
23374 index = this.childNodes.length;
23376 this.setFirstChild(node);
23378 this.childNodes.push(node);
23379 node.parentNode = this;
23380 var ps = this.childNodes[index-1];
23382 node.previousSibling = ps;
23383 ps.nextSibling = node;
23385 node.previousSibling = null;
23387 node.nextSibling = null;
23388 this.setLastChild(node);
23389 node.setOwnerTree(this.getOwnerTree());
23390 this.fireEvent("append", this.ownerTree, this, node, index);
23392 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23399 * Removes a child node from this node.
23400 * @param {Node} node The node to remove
23401 * @return {Node} The removed node
23403 removeChild : function(node){
23404 var index = this.childNodes.indexOf(node);
23408 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23412 // remove it from childNodes collection
23413 this.childNodes.splice(index, 1);
23416 if(node.previousSibling){
23417 node.previousSibling.nextSibling = node.nextSibling;
23419 if(node.nextSibling){
23420 node.nextSibling.previousSibling = node.previousSibling;
23423 // update child refs
23424 if(this.firstChild == node){
23425 this.setFirstChild(node.nextSibling);
23427 if(this.lastChild == node){
23428 this.setLastChild(node.previousSibling);
23431 node.setOwnerTree(null);
23432 // clear any references from the node
23433 node.parentNode = null;
23434 node.previousSibling = null;
23435 node.nextSibling = null;
23436 this.fireEvent("remove", this.ownerTree, this, node);
23441 * Inserts the first node before the second node in this nodes childNodes collection.
23442 * @param {Node} node The node to insert
23443 * @param {Node} refNode The node to insert before (if null the node is appended)
23444 * @return {Node} The inserted node
23446 insertBefore : function(node, refNode){
23447 if(!refNode){ // like standard Dom, refNode can be null for append
23448 return this.appendChild(node);
23451 if(node == refNode){
23455 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23458 var index = this.childNodes.indexOf(refNode);
23459 var oldParent = node.parentNode;
23460 var refIndex = index;
23462 // when moving internally, indexes will change after remove
23463 if(oldParent == this && this.childNodes.indexOf(node) < index){
23467 // it's a move, make sure we move it cleanly
23469 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23472 oldParent.removeChild(node);
23475 this.setFirstChild(node);
23477 this.childNodes.splice(refIndex, 0, node);
23478 node.parentNode = this;
23479 var ps = this.childNodes[refIndex-1];
23481 node.previousSibling = ps;
23482 ps.nextSibling = node;
23484 node.previousSibling = null;
23486 node.nextSibling = refNode;
23487 refNode.previousSibling = node;
23488 node.setOwnerTree(this.getOwnerTree());
23489 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23491 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23497 * Returns the child node at the specified index.
23498 * @param {Number} index
23501 item : function(index){
23502 return this.childNodes[index];
23506 * Replaces one child node in this node with another.
23507 * @param {Node} newChild The replacement node
23508 * @param {Node} oldChild The node to replace
23509 * @return {Node} The replaced node
23511 replaceChild : function(newChild, oldChild){
23512 this.insertBefore(newChild, oldChild);
23513 this.removeChild(oldChild);
23518 * Returns the index of a child node
23519 * @param {Node} node
23520 * @return {Number} The index of the node or -1 if it was not found
23522 indexOf : function(child){
23523 return this.childNodes.indexOf(child);
23527 * Returns the tree this node is in.
23530 getOwnerTree : function(){
23531 // if it doesn't have one, look for one
23532 if(!this.ownerTree){
23536 this.ownerTree = p.ownerTree;
23542 return this.ownerTree;
23546 * Returns depth of this node (the root node has a depth of 0)
23549 getDepth : function(){
23552 while(p.parentNode){
23560 setOwnerTree : function(tree){
23561 // if it's move, we need to update everyone
23562 if(tree != this.ownerTree){
23563 if(this.ownerTree){
23564 this.ownerTree.unregisterNode(this);
23566 this.ownerTree = tree;
23567 var cs = this.childNodes;
23568 for(var i = 0, len = cs.length; i < len; i++) {
23569 cs[i].setOwnerTree(tree);
23572 tree.registerNode(this);
23578 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23579 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23580 * @return {String} The path
23582 getPath : function(attr){
23583 attr = attr || "id";
23584 var p = this.parentNode;
23585 var b = [this.attributes[attr]];
23587 b.unshift(p.attributes[attr]);
23590 var sep = this.getOwnerTree().pathSeparator;
23591 return sep + b.join(sep);
23595 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23596 * function call will be the scope provided or the current node. The arguments to the function
23597 * will be the args provided or the current node. If the function returns false at any point,
23598 * the bubble is stopped.
23599 * @param {Function} fn The function to call
23600 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23601 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23603 bubble : function(fn, scope, args){
23606 if(fn.call(scope || p, args || p) === false){
23614 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23615 * function call will be the scope provided or the current node. The arguments to the function
23616 * will be the args provided or the current node. If the function returns false at any point,
23617 * the cascade is stopped on that branch.
23618 * @param {Function} fn The function to call
23619 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23620 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23622 cascade : function(fn, scope, args){
23623 if(fn.call(scope || this, args || this) !== false){
23624 var cs = this.childNodes;
23625 for(var i = 0, len = cs.length; i < len; i++) {
23626 cs[i].cascade(fn, scope, args);
23632 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23633 * function call will be the scope provided or the current node. The arguments to the function
23634 * will be the args provided or the current node. If the function returns false at any point,
23635 * the iteration stops.
23636 * @param {Function} fn The function to call
23637 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23638 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23640 eachChild : function(fn, scope, args){
23641 var cs = this.childNodes;
23642 for(var i = 0, len = cs.length; i < len; i++) {
23643 if(fn.call(scope || this, args || cs[i]) === false){
23650 * Finds the first child that has the attribute with the specified value.
23651 * @param {String} attribute The attribute name
23652 * @param {Mixed} value The value to search for
23653 * @return {Node} The found child or null if none was found
23655 findChild : function(attribute, value){
23656 var cs = this.childNodes;
23657 for(var i = 0, len = cs.length; i < len; i++) {
23658 if(cs[i].attributes[attribute] == value){
23666 * Finds the first child by a custom function. The child matches if the function passed
23668 * @param {Function} fn
23669 * @param {Object} scope (optional)
23670 * @return {Node} The found child or null if none was found
23672 findChildBy : function(fn, scope){
23673 var cs = this.childNodes;
23674 for(var i = 0, len = cs.length; i < len; i++) {
23675 if(fn.call(scope||cs[i], cs[i]) === true){
23683 * Sorts this nodes children using the supplied sort function
23684 * @param {Function} fn
23685 * @param {Object} scope (optional)
23687 sort : function(fn, scope){
23688 var cs = this.childNodes;
23689 var len = cs.length;
23691 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23693 for(var i = 0; i < len; i++){
23695 n.previousSibling = cs[i-1];
23696 n.nextSibling = cs[i+1];
23698 this.setFirstChild(n);
23701 this.setLastChild(n);
23708 * Returns true if this node is an ancestor (at any point) of the passed node.
23709 * @param {Node} node
23710 * @return {Boolean}
23712 contains : function(node){
23713 return node.isAncestor(this);
23717 * Returns true if the passed node is an ancestor (at any point) of this node.
23718 * @param {Node} node
23719 * @return {Boolean}
23721 isAncestor : function(node){
23722 var p = this.parentNode;
23732 toString : function(){
23733 return "[Node"+(this.id?" "+this.id:"")+"]";
23737 * Ext JS Library 1.1.1
23738 * Copyright(c) 2006-2007, Ext JS, LLC.
23740 * Originally Released Under LGPL - original licence link has changed is not relivant.
23743 * <script type="text/javascript">
23748 * @extends Roo.Element
23749 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23750 * automatic maintaining of shadow/shim positions.
23751 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23752 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23753 * you can pass a string with a CSS class name. False turns off the shadow.
23754 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23755 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23756 * @cfg {String} cls CSS class to add to the element
23757 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23758 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23760 * @param {Object} config An object with config options.
23761 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23764 Roo.Layer = function(config, existingEl){
23765 config = config || {};
23766 var dh = Roo.DomHelper;
23767 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23769 this.dom = Roo.getDom(existingEl);
23772 var o = config.dh || {tag: "div", cls: "x-layer"};
23773 this.dom = dh.append(pel, o);
23776 this.addClass(config.cls);
23778 this.constrain = config.constrain !== false;
23779 this.visibilityMode = Roo.Element.VISIBILITY;
23781 this.id = this.dom.id = config.id;
23783 this.id = Roo.id(this.dom);
23785 this.zindex = config.zindex || this.getZIndex();
23786 this.position("absolute", this.zindex);
23788 this.shadowOffset = config.shadowOffset || 4;
23789 this.shadow = new Roo.Shadow({
23790 offset : this.shadowOffset,
23791 mode : config.shadow
23794 this.shadowOffset = 0;
23796 this.useShim = config.shim !== false && Roo.useShims;
23797 this.useDisplay = config.useDisplay;
23801 var supr = Roo.Element.prototype;
23803 // shims are shared among layer to keep from having 100 iframes
23806 Roo.extend(Roo.Layer, Roo.Element, {
23808 getZIndex : function(){
23809 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23812 getShim : function(){
23819 var shim = shims.shift();
23821 shim = this.createShim();
23822 shim.enableDisplayMode('block');
23823 shim.dom.style.display = 'none';
23824 shim.dom.style.visibility = 'visible';
23826 var pn = this.dom.parentNode;
23827 if(shim.dom.parentNode != pn){
23828 pn.insertBefore(shim.dom, this.dom);
23830 shim.setStyle('z-index', this.getZIndex()-2);
23835 hideShim : function(){
23837 this.shim.setDisplayed(false);
23838 shims.push(this.shim);
23843 disableShadow : function(){
23845 this.shadowDisabled = true;
23846 this.shadow.hide();
23847 this.lastShadowOffset = this.shadowOffset;
23848 this.shadowOffset = 0;
23852 enableShadow : function(show){
23854 this.shadowDisabled = false;
23855 this.shadowOffset = this.lastShadowOffset;
23856 delete this.lastShadowOffset;
23864 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23865 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23866 sync : function(doShow){
23867 var sw = this.shadow;
23868 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23869 var sh = this.getShim();
23871 var w = this.getWidth(),
23872 h = this.getHeight();
23874 var l = this.getLeft(true),
23875 t = this.getTop(true);
23877 if(sw && !this.shadowDisabled){
23878 if(doShow && !sw.isVisible()){
23881 sw.realign(l, t, w, h);
23887 // fit the shim behind the shadow, so it is shimmed too
23888 var a = sw.adjusts, s = sh.dom.style;
23889 s.left = (Math.min(l, l+a.l))+"px";
23890 s.top = (Math.min(t, t+a.t))+"px";
23891 s.width = (w+a.w)+"px";
23892 s.height = (h+a.h)+"px";
23899 sh.setLeftTop(l, t);
23906 destroy : function(){
23909 this.shadow.hide();
23911 this.removeAllListeners();
23912 var pn = this.dom.parentNode;
23914 pn.removeChild(this.dom);
23916 Roo.Element.uncache(this.id);
23919 remove : function(){
23924 beginUpdate : function(){
23925 this.updating = true;
23929 endUpdate : function(){
23930 this.updating = false;
23935 hideUnders : function(negOffset){
23937 this.shadow.hide();
23943 constrainXY : function(){
23944 if(this.constrain){
23945 var vw = Roo.lib.Dom.getViewWidth(),
23946 vh = Roo.lib.Dom.getViewHeight();
23947 var s = Roo.get(document).getScroll();
23949 var xy = this.getXY();
23950 var x = xy[0], y = xy[1];
23951 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23952 // only move it if it needs it
23954 // first validate right/bottom
23955 if((x + w) > vw+s.left){
23956 x = vw - w - this.shadowOffset;
23959 if((y + h) > vh+s.top){
23960 y = vh - h - this.shadowOffset;
23963 // then make sure top/left isn't negative
23974 var ay = this.avoidY;
23975 if(y <= ay && (y+h) >= ay){
23981 supr.setXY.call(this, xy);
23987 isVisible : function(){
23988 return this.visible;
23992 showAction : function(){
23993 this.visible = true; // track visibility to prevent getStyle calls
23994 if(this.useDisplay === true){
23995 this.setDisplayed("");
23996 }else if(this.lastXY){
23997 supr.setXY.call(this, this.lastXY);
23998 }else if(this.lastLT){
23999 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24004 hideAction : function(){
24005 this.visible = false;
24006 if(this.useDisplay === true){
24007 this.setDisplayed(false);
24009 this.setLeftTop(-10000,-10000);
24013 // overridden Element method
24014 setVisible : function(v, a, d, c, e){
24019 var cb = function(){
24024 }.createDelegate(this);
24025 supr.setVisible.call(this, true, true, d, cb, e);
24028 this.hideUnders(true);
24037 }.createDelegate(this);
24039 supr.setVisible.call(this, v, a, d, cb, e);
24048 storeXY : function(xy){
24049 delete this.lastLT;
24053 storeLeftTop : function(left, top){
24054 delete this.lastXY;
24055 this.lastLT = [left, top];
24059 beforeFx : function(){
24060 this.beforeAction();
24061 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24065 afterFx : function(){
24066 Roo.Layer.superclass.afterFx.apply(this, arguments);
24067 this.sync(this.isVisible());
24071 beforeAction : function(){
24072 if(!this.updating && this.shadow){
24073 this.shadow.hide();
24077 // overridden Element method
24078 setLeft : function(left){
24079 this.storeLeftTop(left, this.getTop(true));
24080 supr.setLeft.apply(this, arguments);
24084 setTop : function(top){
24085 this.storeLeftTop(this.getLeft(true), top);
24086 supr.setTop.apply(this, arguments);
24090 setLeftTop : function(left, top){
24091 this.storeLeftTop(left, top);
24092 supr.setLeftTop.apply(this, arguments);
24096 setXY : function(xy, a, d, c, e){
24098 this.beforeAction();
24100 var cb = this.createCB(c);
24101 supr.setXY.call(this, xy, a, d, cb, e);
24108 createCB : function(c){
24119 // overridden Element method
24120 setX : function(x, a, d, c, e){
24121 this.setXY([x, this.getY()], a, d, c, e);
24124 // overridden Element method
24125 setY : function(y, a, d, c, e){
24126 this.setXY([this.getX(), y], a, d, c, e);
24129 // overridden Element method
24130 setSize : function(w, h, a, d, c, e){
24131 this.beforeAction();
24132 var cb = this.createCB(c);
24133 supr.setSize.call(this, w, h, a, d, cb, e);
24139 // overridden Element method
24140 setWidth : function(w, a, d, c, e){
24141 this.beforeAction();
24142 var cb = this.createCB(c);
24143 supr.setWidth.call(this, w, a, d, cb, e);
24149 // overridden Element method
24150 setHeight : function(h, a, d, c, e){
24151 this.beforeAction();
24152 var cb = this.createCB(c);
24153 supr.setHeight.call(this, h, a, d, cb, e);
24159 // overridden Element method
24160 setBounds : function(x, y, w, h, a, d, c, e){
24161 this.beforeAction();
24162 var cb = this.createCB(c);
24164 this.storeXY([x, y]);
24165 supr.setXY.call(this, [x, y]);
24166 supr.setSize.call(this, w, h, a, d, cb, e);
24169 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24175 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24176 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24177 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24178 * @param {Number} zindex The new z-index to set
24179 * @return {this} The Layer
24181 setZIndex : function(zindex){
24182 this.zindex = zindex;
24183 this.setStyle("z-index", zindex + 2);
24185 this.shadow.setZIndex(zindex + 1);
24188 this.shim.setStyle("z-index", zindex);
24194 * Ext JS Library 1.1.1
24195 * Copyright(c) 2006-2007, Ext JS, LLC.
24197 * Originally Released Under LGPL - original licence link has changed is not relivant.
24200 * <script type="text/javascript">
24205 * @class Roo.Shadow
24206 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24207 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24208 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24210 * Create a new Shadow
24211 * @param {Object} config The config object
24213 Roo.Shadow = function(config){
24214 Roo.apply(this, config);
24215 if(typeof this.mode != "string"){
24216 this.mode = this.defaultMode;
24218 var o = this.offset, a = {h: 0};
24219 var rad = Math.floor(this.offset/2);
24220 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24226 a.l -= this.offset + rad;
24227 a.t -= this.offset + rad;
24238 a.l -= (this.offset - rad);
24239 a.t -= this.offset + rad;
24241 a.w -= (this.offset - rad)*2;
24252 a.l -= (this.offset - rad);
24253 a.t -= (this.offset - rad);
24255 a.w -= (this.offset + rad + 1);
24256 a.h -= (this.offset + rad);
24265 Roo.Shadow.prototype = {
24267 * @cfg {String} mode
24268 * The shadow display mode. Supports the following options:<br />
24269 * sides: Shadow displays on both sides and bottom only<br />
24270 * frame: Shadow displays equally on all four sides<br />
24271 * drop: Traditional bottom-right drop shadow (default)
24274 * @cfg {String} offset
24275 * The number of pixels to offset the shadow from the element (defaults to 4)
24280 defaultMode: "drop",
24283 * Displays the shadow under the target element
24284 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24286 show : function(target){
24287 target = Roo.get(target);
24289 this.el = Roo.Shadow.Pool.pull();
24290 if(this.el.dom.nextSibling != target.dom){
24291 this.el.insertBefore(target);
24294 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24296 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24299 target.getLeft(true),
24300 target.getTop(true),
24304 this.el.dom.style.display = "block";
24308 * Returns true if the shadow is visible, else false
24310 isVisible : function(){
24311 return this.el ? true : false;
24315 * Direct alignment when values are already available. Show must be called at least once before
24316 * calling this method to ensure it is initialized.
24317 * @param {Number} left The target element left position
24318 * @param {Number} top The target element top position
24319 * @param {Number} width The target element width
24320 * @param {Number} height The target element height
24322 realign : function(l, t, w, h){
24326 var a = this.adjusts, d = this.el.dom, s = d.style;
24328 s.left = (l+a.l)+"px";
24329 s.top = (t+a.t)+"px";
24330 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24332 if(s.width != sws || s.height != shs){
24336 var cn = d.childNodes;
24337 var sww = Math.max(0, (sw-12))+"px";
24338 cn[0].childNodes[1].style.width = sww;
24339 cn[1].childNodes[1].style.width = sww;
24340 cn[2].childNodes[1].style.width = sww;
24341 cn[1].style.height = Math.max(0, (sh-12))+"px";
24347 * Hides this shadow
24351 this.el.dom.style.display = "none";
24352 Roo.Shadow.Pool.push(this.el);
24358 * Adjust the z-index of this shadow
24359 * @param {Number} zindex The new z-index
24361 setZIndex : function(z){
24364 this.el.setStyle("z-index", z);
24369 // Private utility class that manages the internal Shadow cache
24370 Roo.Shadow.Pool = function(){
24372 var markup = Roo.isIE ?
24373 '<div class="x-ie-shadow"></div>' :
24374 '<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>';
24377 var sh = p.shift();
24379 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24380 sh.autoBoxAdjust = false;
24385 push : function(sh){
24391 * Ext JS Library 1.1.1
24392 * Copyright(c) 2006-2007, Ext JS, LLC.
24394 * Originally Released Under LGPL - original licence link has changed is not relivant.
24397 * <script type="text/javascript">
24402 * @class Roo.SplitBar
24403 * @extends Roo.util.Observable
24404 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24408 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24409 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24410 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24411 split.minSize = 100;
24412 split.maxSize = 600;
24413 split.animate = true;
24414 split.on('moved', splitterMoved);
24417 * Create a new SplitBar
24418 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24419 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24420 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24421 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24422 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24423 position of the SplitBar).
24425 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24428 this.el = Roo.get(dragElement, true);
24429 this.el.dom.unselectable = "on";
24431 this.resizingEl = Roo.get(resizingElement, true);
24435 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24436 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24439 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24442 * The minimum size of the resizing element. (Defaults to 0)
24448 * The maximum size of the resizing element. (Defaults to 2000)
24451 this.maxSize = 2000;
24454 * Whether to animate the transition to the new size
24457 this.animate = false;
24460 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24463 this.useShim = false;
24468 if(!existingProxy){
24470 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24472 this.proxy = Roo.get(existingProxy).dom;
24475 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24478 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24481 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24484 this.dragSpecs = {};
24487 * @private The adapter to use to positon and resize elements
24489 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24490 this.adapter.init(this);
24492 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24494 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24495 this.el.addClass("x-splitbar-h");
24498 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24499 this.el.addClass("x-splitbar-v");
24505 * Fires when the splitter is moved (alias for {@link #event-moved})
24506 * @param {Roo.SplitBar} this
24507 * @param {Number} newSize the new width or height
24512 * Fires when the splitter is moved
24513 * @param {Roo.SplitBar} this
24514 * @param {Number} newSize the new width or height
24518 * @event beforeresize
24519 * Fires before the splitter is dragged
24520 * @param {Roo.SplitBar} this
24522 "beforeresize" : true,
24524 "beforeapply" : true
24527 Roo.util.Observable.call(this);
24530 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24531 onStartProxyDrag : function(x, y){
24532 this.fireEvent("beforeresize", this);
24534 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24536 o.enableDisplayMode("block");
24537 // all splitbars share the same overlay
24538 Roo.SplitBar.prototype.overlay = o;
24540 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24541 this.overlay.show();
24542 Roo.get(this.proxy).setDisplayed("block");
24543 var size = this.adapter.getElementSize(this);
24544 this.activeMinSize = this.getMinimumSize();;
24545 this.activeMaxSize = this.getMaximumSize();;
24546 var c1 = size - this.activeMinSize;
24547 var c2 = Math.max(this.activeMaxSize - size, 0);
24548 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24549 this.dd.resetConstraints();
24550 this.dd.setXConstraint(
24551 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24552 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24554 this.dd.setYConstraint(0, 0);
24556 this.dd.resetConstraints();
24557 this.dd.setXConstraint(0, 0);
24558 this.dd.setYConstraint(
24559 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24560 this.placement == Roo.SplitBar.TOP ? c2 : c1
24563 this.dragSpecs.startSize = size;
24564 this.dragSpecs.startPoint = [x, y];
24565 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24569 * @private Called after the drag operation by the DDProxy
24571 onEndProxyDrag : function(e){
24572 Roo.get(this.proxy).setDisplayed(false);
24573 var endPoint = Roo.lib.Event.getXY(e);
24575 this.overlay.hide();
24578 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24579 newSize = this.dragSpecs.startSize +
24580 (this.placement == Roo.SplitBar.LEFT ?
24581 endPoint[0] - this.dragSpecs.startPoint[0] :
24582 this.dragSpecs.startPoint[0] - endPoint[0]
24585 newSize = this.dragSpecs.startSize +
24586 (this.placement == Roo.SplitBar.TOP ?
24587 endPoint[1] - this.dragSpecs.startPoint[1] :
24588 this.dragSpecs.startPoint[1] - endPoint[1]
24591 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24592 if(newSize != this.dragSpecs.startSize){
24593 if(this.fireEvent('beforeapply', this, newSize) !== false){
24594 this.adapter.setElementSize(this, newSize);
24595 this.fireEvent("moved", this, newSize);
24596 this.fireEvent("resize", this, newSize);
24602 * Get the adapter this SplitBar uses
24603 * @return The adapter object
24605 getAdapter : function(){
24606 return this.adapter;
24610 * Set the adapter this SplitBar uses
24611 * @param {Object} adapter A SplitBar adapter object
24613 setAdapter : function(adapter){
24614 this.adapter = adapter;
24615 this.adapter.init(this);
24619 * Gets the minimum size for the resizing element
24620 * @return {Number} The minimum size
24622 getMinimumSize : function(){
24623 return this.minSize;
24627 * Sets the minimum size for the resizing element
24628 * @param {Number} minSize The minimum size
24630 setMinimumSize : function(minSize){
24631 this.minSize = minSize;
24635 * Gets the maximum size for the resizing element
24636 * @return {Number} The maximum size
24638 getMaximumSize : function(){
24639 return this.maxSize;
24643 * Sets the maximum size for the resizing element
24644 * @param {Number} maxSize The maximum size
24646 setMaximumSize : function(maxSize){
24647 this.maxSize = maxSize;
24651 * Sets the initialize size for the resizing element
24652 * @param {Number} size The initial size
24654 setCurrentSize : function(size){
24655 var oldAnimate = this.animate;
24656 this.animate = false;
24657 this.adapter.setElementSize(this, size);
24658 this.animate = oldAnimate;
24662 * Destroy this splitbar.
24663 * @param {Boolean} removeEl True to remove the element
24665 destroy : function(removeEl){
24667 this.shim.remove();
24670 this.proxy.parentNode.removeChild(this.proxy);
24678 * @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.
24680 Roo.SplitBar.createProxy = function(dir){
24681 var proxy = new Roo.Element(document.createElement("div"));
24682 proxy.unselectable();
24683 var cls = 'x-splitbar-proxy';
24684 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24685 document.body.appendChild(proxy.dom);
24690 * @class Roo.SplitBar.BasicLayoutAdapter
24691 * Default Adapter. It assumes the splitter and resizing element are not positioned
24692 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24694 Roo.SplitBar.BasicLayoutAdapter = function(){
24697 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24698 // do nothing for now
24699 init : function(s){
24703 * Called before drag operations to get the current size of the resizing element.
24704 * @param {Roo.SplitBar} s The SplitBar using this adapter
24706 getElementSize : function(s){
24707 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24708 return s.resizingEl.getWidth();
24710 return s.resizingEl.getHeight();
24715 * Called after drag operations to set the size of the resizing element.
24716 * @param {Roo.SplitBar} s The SplitBar using this adapter
24717 * @param {Number} newSize The new size to set
24718 * @param {Function} onComplete A function to be invoked when resizing is complete
24720 setElementSize : function(s, newSize, onComplete){
24721 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24723 s.resizingEl.setWidth(newSize);
24725 onComplete(s, newSize);
24728 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24733 s.resizingEl.setHeight(newSize);
24735 onComplete(s, newSize);
24738 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24745 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24746 * @extends Roo.SplitBar.BasicLayoutAdapter
24747 * Adapter that moves the splitter element to align with the resized sizing element.
24748 * Used with an absolute positioned SplitBar.
24749 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24750 * document.body, make sure you assign an id to the body element.
24752 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24753 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24754 this.container = Roo.get(container);
24757 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24758 init : function(s){
24759 this.basic.init(s);
24762 getElementSize : function(s){
24763 return this.basic.getElementSize(s);
24766 setElementSize : function(s, newSize, onComplete){
24767 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24770 moveSplitter : function(s){
24771 var yes = Roo.SplitBar;
24772 switch(s.placement){
24774 s.el.setX(s.resizingEl.getRight());
24777 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24780 s.el.setY(s.resizingEl.getBottom());
24783 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24790 * Orientation constant - Create a vertical SplitBar
24794 Roo.SplitBar.VERTICAL = 1;
24797 * Orientation constant - Create a horizontal SplitBar
24801 Roo.SplitBar.HORIZONTAL = 2;
24804 * Placement constant - The resizing element is to the left of the splitter element
24808 Roo.SplitBar.LEFT = 1;
24811 * Placement constant - The resizing element is to the right of the splitter element
24815 Roo.SplitBar.RIGHT = 2;
24818 * Placement constant - The resizing element is positioned above the splitter element
24822 Roo.SplitBar.TOP = 3;
24825 * Placement constant - The resizing element is positioned under splitter element
24829 Roo.SplitBar.BOTTOM = 4;
24832 * Ext JS Library 1.1.1
24833 * Copyright(c) 2006-2007, Ext JS, LLC.
24835 * Originally Released Under LGPL - original licence link has changed is not relivant.
24838 * <script type="text/javascript">
24843 * @extends Roo.util.Observable
24844 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24845 * This class also supports single and multi selection modes. <br>
24846 * Create a data model bound view:
24848 var store = new Roo.data.Store(...);
24850 var view = new Roo.View({
24852 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24854 singleSelect: true,
24855 selectedClass: "ydataview-selected",
24859 // listen for node click?
24860 view.on("click", function(vw, index, node, e){
24861 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24865 dataModel.load("foobar.xml");
24867 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24869 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24870 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24872 * Note: old style constructor is still suported (container, template, config)
24875 * Create a new View
24876 * @param {Object} config The config object
24879 Roo.View = function(config, depreciated_tpl, depreciated_config){
24881 this.parent = false;
24883 if (typeof(depreciated_tpl) == 'undefined') {
24884 // new way.. - universal constructor.
24885 Roo.apply(this, config);
24886 this.el = Roo.get(this.el);
24889 this.el = Roo.get(config);
24890 this.tpl = depreciated_tpl;
24891 Roo.apply(this, depreciated_config);
24893 this.wrapEl = this.el.wrap().wrap();
24894 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24897 if(typeof(this.tpl) == "string"){
24898 this.tpl = new Roo.Template(this.tpl);
24900 // support xtype ctors..
24901 this.tpl = new Roo.factory(this.tpl, Roo);
24905 this.tpl.compile();
24910 * @event beforeclick
24911 * Fires before a click is processed. Returns false to cancel the default action.
24912 * @param {Roo.View} this
24913 * @param {Number} index The index of the target node
24914 * @param {HTMLElement} node The target node
24915 * @param {Roo.EventObject} e The raw event object
24917 "beforeclick" : true,
24920 * Fires when a template node is clicked.
24921 * @param {Roo.View} this
24922 * @param {Number} index The index of the target node
24923 * @param {HTMLElement} node The target node
24924 * @param {Roo.EventObject} e The raw event object
24929 * Fires when a template node is double clicked.
24930 * @param {Roo.View} this
24931 * @param {Number} index The index of the target node
24932 * @param {HTMLElement} node The target node
24933 * @param {Roo.EventObject} e The raw event object
24937 * @event contextmenu
24938 * Fires when a template node is right clicked.
24939 * @param {Roo.View} this
24940 * @param {Number} index The index of the target node
24941 * @param {HTMLElement} node The target node
24942 * @param {Roo.EventObject} e The raw event object
24944 "contextmenu" : true,
24946 * @event selectionchange
24947 * Fires when the selected nodes change.
24948 * @param {Roo.View} this
24949 * @param {Array} selections Array of the selected nodes
24951 "selectionchange" : true,
24954 * @event beforeselect
24955 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24956 * @param {Roo.View} this
24957 * @param {HTMLElement} node The node to be selected
24958 * @param {Array} selections Array of currently selected nodes
24960 "beforeselect" : true,
24962 * @event preparedata
24963 * Fires on every row to render, to allow you to change the data.
24964 * @param {Roo.View} this
24965 * @param {Object} data to be rendered (change this)
24967 "preparedata" : true
24975 "click": this.onClick,
24976 "dblclick": this.onDblClick,
24977 "contextmenu": this.onContextMenu,
24981 this.selections = [];
24983 this.cmp = new Roo.CompositeElementLite([]);
24985 this.store = Roo.factory(this.store, Roo.data);
24986 this.setStore(this.store, true);
24989 if ( this.footer && this.footer.xtype) {
24991 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24993 this.footer.dataSource = this.store
24994 this.footer.container = fctr;
24995 this.footer = Roo.factory(this.footer, Roo);
24996 fctr.insertFirst(this.el);
24998 // this is a bit insane - as the paging toolbar seems to detach the el..
24999 // dom.parentNode.parentNode.parentNode
25000 // they get detached?
25004 Roo.View.superclass.constructor.call(this);
25009 Roo.extend(Roo.View, Roo.util.Observable, {
25012 * @cfg {Roo.data.Store} store Data store to load data from.
25017 * @cfg {String|Roo.Element} el The container element.
25022 * @cfg {String|Roo.Template} tpl The template used by this View
25026 * @cfg {String} dataName the named area of the template to use as the data area
25027 * Works with domtemplates roo-name="name"
25031 * @cfg {String} selectedClass The css class to add to selected nodes
25033 selectedClass : "x-view-selected",
25035 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25040 * @cfg {String} text to display on mask (default Loading)
25044 * @cfg {Boolean} multiSelect Allow multiple selection
25046 multiSelect : false,
25048 * @cfg {Boolean} singleSelect Allow single selection
25050 singleSelect: false,
25053 * @cfg {Boolean} toggleSelect - selecting
25055 toggleSelect : false,
25058 * @cfg {Boolean} tickable - selecting
25063 * Returns the element this view is bound to.
25064 * @return {Roo.Element}
25066 getEl : function(){
25067 return this.wrapEl;
25073 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25075 refresh : function(){
25076 //Roo.log('refresh');
25079 // if we are using something like 'domtemplate', then
25080 // the what gets used is:
25081 // t.applySubtemplate(NAME, data, wrapping data..)
25082 // the outer template then get' applied with
25083 // the store 'extra data'
25084 // and the body get's added to the
25085 // roo-name="data" node?
25086 // <span class='roo-tpl-{name}'></span> ?????
25090 this.clearSelections();
25091 this.el.update("");
25093 var records = this.store.getRange();
25094 if(records.length < 1) {
25096 // is this valid?? = should it render a template??
25098 this.el.update(this.emptyText);
25102 if (this.dataName) {
25103 this.el.update(t.apply(this.store.meta)); //????
25104 el = this.el.child('.roo-tpl-' + this.dataName);
25107 for(var i = 0, len = records.length; i < len; i++){
25108 var data = this.prepareData(records[i].data, i, records[i]);
25109 this.fireEvent("preparedata", this, data, i, records[i]);
25111 var d = Roo.apply({}, data);
25114 Roo.apply(d, {'roo-id' : Roo.id()});
25118 Roo.each(this.parent.item, function(item){
25119 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25122 Roo.apply(d, {'roo-data-checked' : 'checked'});
25126 html[html.length] = Roo.util.Format.trim(
25128 t.applySubtemplate(this.dataName, d, this.store.meta) :
25135 el.update(html.join(""));
25136 this.nodes = el.dom.childNodes;
25137 this.updateIndexes(0);
25142 * Function to override to reformat the data that is sent to
25143 * the template for each node.
25144 * DEPRICATED - use the preparedata event handler.
25145 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25146 * a JSON object for an UpdateManager bound view).
25148 prepareData : function(data, index, record)
25150 this.fireEvent("preparedata", this, data, index, record);
25154 onUpdate : function(ds, record){
25155 // Roo.log('on update');
25156 this.clearSelections();
25157 var index = this.store.indexOf(record);
25158 var n = this.nodes[index];
25159 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25160 n.parentNode.removeChild(n);
25161 this.updateIndexes(index, index);
25167 onAdd : function(ds, records, index)
25169 //Roo.log(['on Add', ds, records, index] );
25170 this.clearSelections();
25171 if(this.nodes.length == 0){
25175 var n = this.nodes[index];
25176 for(var i = 0, len = records.length; i < len; i++){
25177 var d = this.prepareData(records[i].data, i, records[i]);
25179 this.tpl.insertBefore(n, d);
25182 this.tpl.append(this.el, d);
25185 this.updateIndexes(index);
25188 onRemove : function(ds, record, index){
25189 // Roo.log('onRemove');
25190 this.clearSelections();
25191 var el = this.dataName ?
25192 this.el.child('.roo-tpl-' + this.dataName) :
25195 el.dom.removeChild(this.nodes[index]);
25196 this.updateIndexes(index);
25200 * Refresh an individual node.
25201 * @param {Number} index
25203 refreshNode : function(index){
25204 this.onUpdate(this.store, this.store.getAt(index));
25207 updateIndexes : function(startIndex, endIndex){
25208 var ns = this.nodes;
25209 startIndex = startIndex || 0;
25210 endIndex = endIndex || ns.length - 1;
25211 for(var i = startIndex; i <= endIndex; i++){
25212 ns[i].nodeIndex = i;
25217 * Changes the data store this view uses and refresh the view.
25218 * @param {Store} store
25220 setStore : function(store, initial){
25221 if(!initial && this.store){
25222 this.store.un("datachanged", this.refresh);
25223 this.store.un("add", this.onAdd);
25224 this.store.un("remove", this.onRemove);
25225 this.store.un("update", this.onUpdate);
25226 this.store.un("clear", this.refresh);
25227 this.store.un("beforeload", this.onBeforeLoad);
25228 this.store.un("load", this.onLoad);
25229 this.store.un("loadexception", this.onLoad);
25233 store.on("datachanged", this.refresh, this);
25234 store.on("add", this.onAdd, this);
25235 store.on("remove", this.onRemove, this);
25236 store.on("update", this.onUpdate, this);
25237 store.on("clear", this.refresh, this);
25238 store.on("beforeload", this.onBeforeLoad, this);
25239 store.on("load", this.onLoad, this);
25240 store.on("loadexception", this.onLoad, this);
25248 * onbeforeLoad - masks the loading area.
25251 onBeforeLoad : function(store,opts)
25253 //Roo.log('onBeforeLoad');
25255 this.el.update("");
25257 this.el.mask(this.mask ? this.mask : "Loading" );
25259 onLoad : function ()
25266 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25267 * @param {HTMLElement} node
25268 * @return {HTMLElement} The template node
25270 findItemFromChild : function(node){
25271 var el = this.dataName ?
25272 this.el.child('.roo-tpl-' + this.dataName,true) :
25275 if(!node || node.parentNode == el){
25278 var p = node.parentNode;
25279 while(p && p != el){
25280 if(p.parentNode == el){
25289 onClick : function(e){
25290 var item = this.findItemFromChild(e.getTarget());
25292 var index = this.indexOf(item);
25293 if(this.onItemClick(item, index, e) !== false){
25294 this.fireEvent("click", this, index, item, e);
25297 this.clearSelections();
25302 onContextMenu : function(e){
25303 var item = this.findItemFromChild(e.getTarget());
25305 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25310 onDblClick : function(e){
25311 var item = this.findItemFromChild(e.getTarget());
25313 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25317 onItemClick : function(item, index, e)
25319 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25322 if (this.toggleSelect) {
25323 var m = this.isSelected(item) ? 'unselect' : 'select';
25326 _t[m](item, true, false);
25329 if(this.multiSelect || this.singleSelect){
25330 if(this.multiSelect && e.shiftKey && this.lastSelection){
25331 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25333 this.select(item, this.multiSelect && e.ctrlKey);
25334 this.lastSelection = item;
25337 if(!this.tickable){
25338 e.preventDefault();
25346 * Get the number of selected nodes.
25349 getSelectionCount : function(){
25350 return this.selections.length;
25354 * Get the currently selected nodes.
25355 * @return {Array} An array of HTMLElements
25357 getSelectedNodes : function(){
25358 return this.selections;
25362 * Get the indexes of the selected nodes.
25365 getSelectedIndexes : function(){
25366 var indexes = [], s = this.selections;
25367 for(var i = 0, len = s.length; i < len; i++){
25368 indexes.push(s[i].nodeIndex);
25374 * Clear all selections
25375 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25377 clearSelections : function(suppressEvent){
25378 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25379 this.cmp.elements = this.selections;
25380 this.cmp.removeClass(this.selectedClass);
25381 this.selections = [];
25382 if(!suppressEvent){
25383 this.fireEvent("selectionchange", this, this.selections);
25389 * Returns true if the passed node is selected
25390 * @param {HTMLElement/Number} node The node or node index
25391 * @return {Boolean}
25393 isSelected : function(node){
25394 var s = this.selections;
25398 node = this.getNode(node);
25399 return s.indexOf(node) !== -1;
25404 * @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
25405 * @param {Boolean} keepExisting (optional) true to keep existing selections
25406 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25408 select : function(nodeInfo, keepExisting, suppressEvent){
25409 if(nodeInfo instanceof Array){
25411 this.clearSelections(true);
25413 for(var i = 0, len = nodeInfo.length; i < len; i++){
25414 this.select(nodeInfo[i], true, true);
25418 var node = this.getNode(nodeInfo);
25419 if(!node || this.isSelected(node)){
25420 return; // already selected.
25423 this.clearSelections(true);
25426 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25427 Roo.fly(node).addClass(this.selectedClass);
25428 this.selections.push(node);
25429 if(!suppressEvent){
25430 this.fireEvent("selectionchange", this, this.selections);
25438 * @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
25439 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25440 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25442 unselect : function(nodeInfo, keepExisting, suppressEvent)
25444 if(nodeInfo instanceof Array){
25445 Roo.each(this.selections, function(s) {
25446 this.unselect(s, nodeInfo);
25450 var node = this.getNode(nodeInfo);
25451 if(!node || !this.isSelected(node)){
25452 //Roo.log("not selected");
25453 return; // not selected.
25457 Roo.each(this.selections, function(s) {
25459 Roo.fly(node).removeClass(this.selectedClass);
25466 this.selections= ns;
25467 this.fireEvent("selectionchange", this, this.selections);
25471 * Gets a template node.
25472 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25473 * @return {HTMLElement} The node or null if it wasn't found
25475 getNode : function(nodeInfo){
25476 if(typeof nodeInfo == "string"){
25477 return document.getElementById(nodeInfo);
25478 }else if(typeof nodeInfo == "number"){
25479 return this.nodes[nodeInfo];
25485 * Gets a range template nodes.
25486 * @param {Number} startIndex
25487 * @param {Number} endIndex
25488 * @return {Array} An array of nodes
25490 getNodes : function(start, end){
25491 var ns = this.nodes;
25492 start = start || 0;
25493 end = typeof end == "undefined" ? ns.length - 1 : end;
25496 for(var i = start; i <= end; i++){
25500 for(var i = start; i >= end; i--){
25508 * Finds the index of the passed node
25509 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25510 * @return {Number} The index of the node or -1
25512 indexOf : function(node){
25513 node = this.getNode(node);
25514 if(typeof node.nodeIndex == "number"){
25515 return node.nodeIndex;
25517 var ns = this.nodes;
25518 for(var i = 0, len = ns.length; i < len; i++){
25528 * Ext JS Library 1.1.1
25529 * Copyright(c) 2006-2007, Ext JS, LLC.
25531 * Originally Released Under LGPL - original licence link has changed is not relivant.
25534 * <script type="text/javascript">
25538 * @class Roo.JsonView
25539 * @extends Roo.View
25540 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25542 var view = new Roo.JsonView({
25543 container: "my-element",
25544 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25549 // listen for node click?
25550 view.on("click", function(vw, index, node, e){
25551 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25554 // direct load of JSON data
25555 view.load("foobar.php");
25557 // Example from my blog list
25558 var tpl = new Roo.Template(
25559 '<div class="entry">' +
25560 '<a class="entry-title" href="{link}">{title}</a>' +
25561 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25562 "</div><hr />"
25565 var moreView = new Roo.JsonView({
25566 container : "entry-list",
25570 moreView.on("beforerender", this.sortEntries, this);
25572 url: "/blog/get-posts.php",
25573 params: "allposts=true",
25574 text: "Loading Blog Entries..."
25578 * Note: old code is supported with arguments : (container, template, config)
25582 * Create a new JsonView
25584 * @param {Object} config The config object
25587 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25590 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25592 var um = this.el.getUpdateManager();
25593 um.setRenderer(this);
25594 um.on("update", this.onLoad, this);
25595 um.on("failure", this.onLoadException, this);
25598 * @event beforerender
25599 * Fires before rendering of the downloaded JSON data.
25600 * @param {Roo.JsonView} this
25601 * @param {Object} data The JSON data loaded
25605 * Fires when data is loaded.
25606 * @param {Roo.JsonView} this
25607 * @param {Object} data The JSON data loaded
25608 * @param {Object} response The raw Connect response object
25611 * @event loadexception
25612 * Fires when loading fails.
25613 * @param {Roo.JsonView} this
25614 * @param {Object} response The raw Connect response object
25617 'beforerender' : true,
25619 'loadexception' : true
25622 Roo.extend(Roo.JsonView, Roo.View, {
25624 * @type {String} The root property in the loaded JSON object that contains the data
25629 * Refreshes the view.
25631 refresh : function(){
25632 this.clearSelections();
25633 this.el.update("");
25635 var o = this.jsonData;
25636 if(o && o.length > 0){
25637 for(var i = 0, len = o.length; i < len; i++){
25638 var data = this.prepareData(o[i], i, o);
25639 html[html.length] = this.tpl.apply(data);
25642 html.push(this.emptyText);
25644 this.el.update(html.join(""));
25645 this.nodes = this.el.dom.childNodes;
25646 this.updateIndexes(0);
25650 * 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.
25651 * @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:
25654 url: "your-url.php",
25655 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25656 callback: yourFunction,
25657 scope: yourObject, //(optional scope)
25660 text: "Loading...",
25665 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25666 * 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.
25667 * @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}
25668 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25669 * @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.
25672 var um = this.el.getUpdateManager();
25673 um.update.apply(um, arguments);
25676 render : function(el, response){
25677 this.clearSelections();
25678 this.el.update("");
25681 o = Roo.util.JSON.decode(response.responseText);
25684 o = o[this.jsonRoot];
25689 * The current JSON data or null
25692 this.beforeRender();
25697 * Get the number of records in the current JSON dataset
25700 getCount : function(){
25701 return this.jsonData ? this.jsonData.length : 0;
25705 * Returns the JSON object for the specified node(s)
25706 * @param {HTMLElement/Array} node The node or an array of nodes
25707 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25708 * you get the JSON object for the node
25710 getNodeData : function(node){
25711 if(node instanceof Array){
25713 for(var i = 0, len = node.length; i < len; i++){
25714 data.push(this.getNodeData(node[i]));
25718 return this.jsonData[this.indexOf(node)] || null;
25721 beforeRender : function(){
25722 this.snapshot = this.jsonData;
25724 this.sort.apply(this, this.sortInfo);
25726 this.fireEvent("beforerender", this, this.jsonData);
25729 onLoad : function(el, o){
25730 this.fireEvent("load", this, this.jsonData, o);
25733 onLoadException : function(el, o){
25734 this.fireEvent("loadexception", this, o);
25738 * Filter the data by a specific property.
25739 * @param {String} property A property on your JSON objects
25740 * @param {String/RegExp} value Either string that the property values
25741 * should start with, or a RegExp to test against the property
25743 filter : function(property, value){
25746 var ss = this.snapshot;
25747 if(typeof value == "string"){
25748 var vlen = value.length;
25750 this.clearFilter();
25753 value = value.toLowerCase();
25754 for(var i = 0, len = ss.length; i < len; i++){
25756 if(o[property].substr(0, vlen).toLowerCase() == value){
25760 } else if(value.exec){ // regex?
25761 for(var i = 0, len = ss.length; i < len; i++){
25763 if(value.test(o[property])){
25770 this.jsonData = data;
25776 * Filter by a function. The passed function will be called with each
25777 * object in the current dataset. If the function returns true the value is kept,
25778 * otherwise it is filtered.
25779 * @param {Function} fn
25780 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25782 filterBy : function(fn, scope){
25785 var ss = this.snapshot;
25786 for(var i = 0, len = ss.length; i < len; i++){
25788 if(fn.call(scope || this, o)){
25792 this.jsonData = data;
25798 * Clears the current filter.
25800 clearFilter : function(){
25801 if(this.snapshot && this.jsonData != this.snapshot){
25802 this.jsonData = this.snapshot;
25809 * Sorts the data for this view and refreshes it.
25810 * @param {String} property A property on your JSON objects to sort on
25811 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25812 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25814 sort : function(property, dir, sortType){
25815 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25818 var dsc = dir && dir.toLowerCase() == "desc";
25819 var f = function(o1, o2){
25820 var v1 = sortType ? sortType(o1[p]) : o1[p];
25821 var v2 = sortType ? sortType(o2[p]) : o2[p];
25824 return dsc ? +1 : -1;
25825 } else if(v1 > v2){
25826 return dsc ? -1 : +1;
25831 this.jsonData.sort(f);
25833 if(this.jsonData != this.snapshot){
25834 this.snapshot.sort(f);
25840 * Ext JS Library 1.1.1
25841 * Copyright(c) 2006-2007, Ext JS, LLC.
25843 * Originally Released Under LGPL - original licence link has changed is not relivant.
25846 * <script type="text/javascript">
25851 * @class Roo.ColorPalette
25852 * @extends Roo.Component
25853 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25854 * Here's an example of typical usage:
25856 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25857 cp.render('my-div');
25859 cp.on('select', function(palette, selColor){
25860 // do something with selColor
25864 * Create a new ColorPalette
25865 * @param {Object} config The config object
25867 Roo.ColorPalette = function(config){
25868 Roo.ColorPalette.superclass.constructor.call(this, config);
25872 * Fires when a color is selected
25873 * @param {ColorPalette} this
25874 * @param {String} color The 6-digit color hex code (without the # symbol)
25880 this.on("select", this.handler, this.scope, true);
25883 Roo.extend(Roo.ColorPalette, Roo.Component, {
25885 * @cfg {String} itemCls
25886 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25888 itemCls : "x-color-palette",
25890 * @cfg {String} value
25891 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25892 * the hex codes are case-sensitive.
25895 clickEvent:'click',
25897 ctype: "Roo.ColorPalette",
25900 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25902 allowReselect : false,
25905 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25906 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25907 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25908 * of colors with the width setting until the box is symmetrical.</p>
25909 * <p>You can override individual colors if needed:</p>
25911 var cp = new Roo.ColorPalette();
25912 cp.colors[0] = "FF0000"; // change the first box to red
25915 Or you can provide a custom array of your own for complete control:
25917 var cp = new Roo.ColorPalette();
25918 cp.colors = ["000000", "993300", "333300"];
25923 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25924 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25925 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25926 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25927 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25931 onRender : function(container, position){
25932 var t = new Roo.MasterTemplate(
25933 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25935 var c = this.colors;
25936 for(var i = 0, len = c.length; i < len; i++){
25939 var el = document.createElement("div");
25940 el.className = this.itemCls;
25942 container.dom.insertBefore(el, position);
25943 this.el = Roo.get(el);
25944 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25945 if(this.clickEvent != 'click'){
25946 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25951 afterRender : function(){
25952 Roo.ColorPalette.superclass.afterRender.call(this);
25954 var s = this.value;
25961 handleClick : function(e, t){
25962 e.preventDefault();
25963 if(!this.disabled){
25964 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25965 this.select(c.toUpperCase());
25970 * Selects the specified color in the palette (fires the select event)
25971 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25973 select : function(color){
25974 color = color.replace("#", "");
25975 if(color != this.value || this.allowReselect){
25978 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25980 el.child("a.color-"+color).addClass("x-color-palette-sel");
25981 this.value = color;
25982 this.fireEvent("select", this, color);
25987 * Ext JS Library 1.1.1
25988 * Copyright(c) 2006-2007, Ext JS, LLC.
25990 * Originally Released Under LGPL - original licence link has changed is not relivant.
25993 * <script type="text/javascript">
25997 * @class Roo.DatePicker
25998 * @extends Roo.Component
25999 * Simple date picker class.
26001 * Create a new DatePicker
26002 * @param {Object} config The config object
26004 Roo.DatePicker = function(config){
26005 Roo.DatePicker.superclass.constructor.call(this, config);
26007 this.value = config && config.value ?
26008 config.value.clearTime() : new Date().clearTime();
26013 * Fires when a date is selected
26014 * @param {DatePicker} this
26015 * @param {Date} date The selected date
26019 * @event monthchange
26020 * Fires when the displayed month changes
26021 * @param {DatePicker} this
26022 * @param {Date} date The selected month
26024 'monthchange': true
26028 this.on("select", this.handler, this.scope || this);
26030 // build the disabledDatesRE
26031 if(!this.disabledDatesRE && this.disabledDates){
26032 var dd = this.disabledDates;
26034 for(var i = 0; i < dd.length; i++){
26036 if(i != dd.length-1) re += "|";
26038 this.disabledDatesRE = new RegExp(re + ")");
26042 Roo.extend(Roo.DatePicker, Roo.Component, {
26044 * @cfg {String} todayText
26045 * The text to display on the button that selects the current date (defaults to "Today")
26047 todayText : "Today",
26049 * @cfg {String} okText
26050 * The text to display on the ok button
26052 okText : " OK ", //   to give the user extra clicking room
26054 * @cfg {String} cancelText
26055 * The text to display on the cancel button
26057 cancelText : "Cancel",
26059 * @cfg {String} todayTip
26060 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26062 todayTip : "{0} (Spacebar)",
26064 * @cfg {Date} minDate
26065 * Minimum allowable date (JavaScript date object, defaults to null)
26069 * @cfg {Date} maxDate
26070 * Maximum allowable date (JavaScript date object, defaults to null)
26074 * @cfg {String} minText
26075 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26077 minText : "This date is before the minimum date",
26079 * @cfg {String} maxText
26080 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26082 maxText : "This date is after the maximum date",
26084 * @cfg {String} format
26085 * The default date format string which can be overriden for localization support. The format must be
26086 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26090 * @cfg {Array} disabledDays
26091 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26093 disabledDays : null,
26095 * @cfg {String} disabledDaysText
26096 * The tooltip to display when the date falls on a disabled day (defaults to "")
26098 disabledDaysText : "",
26100 * @cfg {RegExp} disabledDatesRE
26101 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26103 disabledDatesRE : null,
26105 * @cfg {String} disabledDatesText
26106 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26108 disabledDatesText : "",
26110 * @cfg {Boolean} constrainToViewport
26111 * True to constrain the date picker to the viewport (defaults to true)
26113 constrainToViewport : true,
26115 * @cfg {Array} monthNames
26116 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26118 monthNames : Date.monthNames,
26120 * @cfg {Array} dayNames
26121 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26123 dayNames : Date.dayNames,
26125 * @cfg {String} nextText
26126 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26128 nextText: 'Next Month (Control+Right)',
26130 * @cfg {String} prevText
26131 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26133 prevText: 'Previous Month (Control+Left)',
26135 * @cfg {String} monthYearText
26136 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26138 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26140 * @cfg {Number} startDay
26141 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26145 * @cfg {Bool} showClear
26146 * Show a clear button (usefull for date form elements that can be blank.)
26152 * Sets the value of the date field
26153 * @param {Date} value The date to set
26155 setValue : function(value){
26156 var old = this.value;
26158 if (typeof(value) == 'string') {
26160 value = Date.parseDate(value, this.format);
26163 value = new Date();
26166 this.value = value.clearTime(true);
26168 this.update(this.value);
26173 * Gets the current selected value of the date field
26174 * @return {Date} The selected date
26176 getValue : function(){
26181 focus : function(){
26183 this.update(this.activeDate);
26188 onRender : function(container, position){
26191 '<table cellspacing="0">',
26192 '<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>',
26193 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26194 var dn = this.dayNames;
26195 for(var i = 0; i < 7; i++){
26196 var d = this.startDay+i;
26200 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26202 m[m.length] = "</tr></thead><tbody><tr>";
26203 for(var i = 0; i < 42; i++) {
26204 if(i % 7 == 0 && i != 0){
26205 m[m.length] = "</tr><tr>";
26207 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26209 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26210 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26212 var el = document.createElement("div");
26213 el.className = "x-date-picker";
26214 el.innerHTML = m.join("");
26216 container.dom.insertBefore(el, position);
26218 this.el = Roo.get(el);
26219 this.eventEl = Roo.get(el.firstChild);
26221 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26222 handler: this.showPrevMonth,
26224 preventDefault:true,
26228 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26229 handler: this.showNextMonth,
26231 preventDefault:true,
26235 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26237 this.monthPicker = this.el.down('div.x-date-mp');
26238 this.monthPicker.enableDisplayMode('block');
26240 var kn = new Roo.KeyNav(this.eventEl, {
26241 "left" : function(e){
26243 this.showPrevMonth() :
26244 this.update(this.activeDate.add("d", -1));
26247 "right" : function(e){
26249 this.showNextMonth() :
26250 this.update(this.activeDate.add("d", 1));
26253 "up" : function(e){
26255 this.showNextYear() :
26256 this.update(this.activeDate.add("d", -7));
26259 "down" : function(e){
26261 this.showPrevYear() :
26262 this.update(this.activeDate.add("d", 7));
26265 "pageUp" : function(e){
26266 this.showNextMonth();
26269 "pageDown" : function(e){
26270 this.showPrevMonth();
26273 "enter" : function(e){
26274 e.stopPropagation();
26281 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26283 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26285 this.el.unselectable();
26287 this.cells = this.el.select("table.x-date-inner tbody td");
26288 this.textNodes = this.el.query("table.x-date-inner tbody span");
26290 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26292 tooltip: this.monthYearText
26295 this.mbtn.on('click', this.showMonthPicker, this);
26296 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26299 var today = (new Date()).dateFormat(this.format);
26301 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26302 if (this.showClear) {
26303 baseTb.add( new Roo.Toolbar.Fill());
26306 text: String.format(this.todayText, today),
26307 tooltip: String.format(this.todayTip, today),
26308 handler: this.selectToday,
26312 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26315 if (this.showClear) {
26317 baseTb.add( new Roo.Toolbar.Fill());
26320 cls: 'x-btn-icon x-btn-clear',
26321 handler: function() {
26323 this.fireEvent("select", this, '');
26333 this.update(this.value);
26336 createMonthPicker : function(){
26337 if(!this.monthPicker.dom.firstChild){
26338 var buf = ['<table border="0" cellspacing="0">'];
26339 for(var i = 0; i < 6; i++){
26341 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26342 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26344 '<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>' :
26345 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26349 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26351 '</button><button type="button" class="x-date-mp-cancel">',
26353 '</button></td></tr>',
26356 this.monthPicker.update(buf.join(''));
26357 this.monthPicker.on('click', this.onMonthClick, this);
26358 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26360 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26361 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26363 this.mpMonths.each(function(m, a, i){
26366 m.dom.xmonth = 5 + Math.round(i * .5);
26368 m.dom.xmonth = Math.round((i-1) * .5);
26374 showMonthPicker : function(){
26375 this.createMonthPicker();
26376 var size = this.el.getSize();
26377 this.monthPicker.setSize(size);
26378 this.monthPicker.child('table').setSize(size);
26380 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26381 this.updateMPMonth(this.mpSelMonth);
26382 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26383 this.updateMPYear(this.mpSelYear);
26385 this.monthPicker.slideIn('t', {duration:.2});
26388 updateMPYear : function(y){
26390 var ys = this.mpYears.elements;
26391 for(var i = 1; i <= 10; i++){
26392 var td = ys[i-1], y2;
26394 y2 = y + Math.round(i * .5);
26395 td.firstChild.innerHTML = y2;
26398 y2 = y - (5-Math.round(i * .5));
26399 td.firstChild.innerHTML = y2;
26402 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26406 updateMPMonth : function(sm){
26407 this.mpMonths.each(function(m, a, i){
26408 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26412 selectMPMonth: function(m){
26416 onMonthClick : function(e, t){
26418 var el = new Roo.Element(t), pn;
26419 if(el.is('button.x-date-mp-cancel')){
26420 this.hideMonthPicker();
26422 else if(el.is('button.x-date-mp-ok')){
26423 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26424 this.hideMonthPicker();
26426 else if(pn = el.up('td.x-date-mp-month', 2)){
26427 this.mpMonths.removeClass('x-date-mp-sel');
26428 pn.addClass('x-date-mp-sel');
26429 this.mpSelMonth = pn.dom.xmonth;
26431 else if(pn = el.up('td.x-date-mp-year', 2)){
26432 this.mpYears.removeClass('x-date-mp-sel');
26433 pn.addClass('x-date-mp-sel');
26434 this.mpSelYear = pn.dom.xyear;
26436 else if(el.is('a.x-date-mp-prev')){
26437 this.updateMPYear(this.mpyear-10);
26439 else if(el.is('a.x-date-mp-next')){
26440 this.updateMPYear(this.mpyear+10);
26444 onMonthDblClick : function(e, t){
26446 var el = new Roo.Element(t), pn;
26447 if(pn = el.up('td.x-date-mp-month', 2)){
26448 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26449 this.hideMonthPicker();
26451 else if(pn = el.up('td.x-date-mp-year', 2)){
26452 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26453 this.hideMonthPicker();
26457 hideMonthPicker : function(disableAnim){
26458 if(this.monthPicker){
26459 if(disableAnim === true){
26460 this.monthPicker.hide();
26462 this.monthPicker.slideOut('t', {duration:.2});
26468 showPrevMonth : function(e){
26469 this.update(this.activeDate.add("mo", -1));
26473 showNextMonth : function(e){
26474 this.update(this.activeDate.add("mo", 1));
26478 showPrevYear : function(){
26479 this.update(this.activeDate.add("y", -1));
26483 showNextYear : function(){
26484 this.update(this.activeDate.add("y", 1));
26488 handleMouseWheel : function(e){
26489 var delta = e.getWheelDelta();
26491 this.showPrevMonth();
26493 } else if(delta < 0){
26494 this.showNextMonth();
26500 handleDateClick : function(e, t){
26502 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26503 this.setValue(new Date(t.dateValue));
26504 this.fireEvent("select", this, this.value);
26509 selectToday : function(){
26510 this.setValue(new Date().clearTime());
26511 this.fireEvent("select", this, this.value);
26515 update : function(date)
26517 var vd = this.activeDate;
26518 this.activeDate = date;
26520 var t = date.getTime();
26521 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26522 this.cells.removeClass("x-date-selected");
26523 this.cells.each(function(c){
26524 if(c.dom.firstChild.dateValue == t){
26525 c.addClass("x-date-selected");
26526 setTimeout(function(){
26527 try{c.dom.firstChild.focus();}catch(e){}
26536 var days = date.getDaysInMonth();
26537 var firstOfMonth = date.getFirstDateOfMonth();
26538 var startingPos = firstOfMonth.getDay()-this.startDay;
26540 if(startingPos <= this.startDay){
26544 var pm = date.add("mo", -1);
26545 var prevStart = pm.getDaysInMonth()-startingPos;
26547 var cells = this.cells.elements;
26548 var textEls = this.textNodes;
26549 days += startingPos;
26551 // convert everything to numbers so it's fast
26552 var day = 86400000;
26553 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26554 var today = new Date().clearTime().getTime();
26555 var sel = date.clearTime().getTime();
26556 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26557 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26558 var ddMatch = this.disabledDatesRE;
26559 var ddText = this.disabledDatesText;
26560 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26561 var ddaysText = this.disabledDaysText;
26562 var format = this.format;
26564 var setCellClass = function(cal, cell){
26566 var t = d.getTime();
26567 cell.firstChild.dateValue = t;
26569 cell.className += " x-date-today";
26570 cell.title = cal.todayText;
26573 cell.className += " x-date-selected";
26574 setTimeout(function(){
26575 try{cell.firstChild.focus();}catch(e){}
26580 cell.className = " x-date-disabled";
26581 cell.title = cal.minText;
26585 cell.className = " x-date-disabled";
26586 cell.title = cal.maxText;
26590 if(ddays.indexOf(d.getDay()) != -1){
26591 cell.title = ddaysText;
26592 cell.className = " x-date-disabled";
26595 if(ddMatch && format){
26596 var fvalue = d.dateFormat(format);
26597 if(ddMatch.test(fvalue)){
26598 cell.title = ddText.replace("%0", fvalue);
26599 cell.className = " x-date-disabled";
26605 for(; i < startingPos; i++) {
26606 textEls[i].innerHTML = (++prevStart);
26607 d.setDate(d.getDate()+1);
26608 cells[i].className = "x-date-prevday";
26609 setCellClass(this, cells[i]);
26611 for(; i < days; i++){
26612 intDay = i - startingPos + 1;
26613 textEls[i].innerHTML = (intDay);
26614 d.setDate(d.getDate()+1);
26615 cells[i].className = "x-date-active";
26616 setCellClass(this, cells[i]);
26619 for(; i < 42; i++) {
26620 textEls[i].innerHTML = (++extraDays);
26621 d.setDate(d.getDate()+1);
26622 cells[i].className = "x-date-nextday";
26623 setCellClass(this, cells[i]);
26626 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26627 this.fireEvent('monthchange', this, date);
26629 if(!this.internalRender){
26630 var main = this.el.dom.firstChild;
26631 var w = main.offsetWidth;
26632 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26633 Roo.fly(main).setWidth(w);
26634 this.internalRender = true;
26635 // opera does not respect the auto grow header center column
26636 // then, after it gets a width opera refuses to recalculate
26637 // without a second pass
26638 if(Roo.isOpera && !this.secondPass){
26639 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26640 this.secondPass = true;
26641 this.update.defer(10, this, [date]);
26649 * Ext JS Library 1.1.1
26650 * Copyright(c) 2006-2007, Ext JS, LLC.
26652 * Originally Released Under LGPL - original licence link has changed is not relivant.
26655 * <script type="text/javascript">
26658 * @class Roo.TabPanel
26659 * @extends Roo.util.Observable
26660 * A lightweight tab container.
26664 // basic tabs 1, built from existing content
26665 var tabs = new Roo.TabPanel("tabs1");
26666 tabs.addTab("script", "View Script");
26667 tabs.addTab("markup", "View Markup");
26668 tabs.activate("script");
26670 // more advanced tabs, built from javascript
26671 var jtabs = new Roo.TabPanel("jtabs");
26672 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26674 // set up the UpdateManager
26675 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26676 var updater = tab2.getUpdateManager();
26677 updater.setDefaultUrl("ajax1.htm");
26678 tab2.on('activate', updater.refresh, updater, true);
26680 // Use setUrl for Ajax loading
26681 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26682 tab3.setUrl("ajax2.htm", null, true);
26685 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26688 jtabs.activate("jtabs-1");
26691 * Create a new TabPanel.
26692 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26693 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26695 Roo.TabPanel = function(container, config){
26697 * The container element for this TabPanel.
26698 * @type Roo.Element
26700 this.el = Roo.get(container, true);
26702 if(typeof config == "boolean"){
26703 this.tabPosition = config ? "bottom" : "top";
26705 Roo.apply(this, config);
26708 if(this.tabPosition == "bottom"){
26709 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26710 this.el.addClass("x-tabs-bottom");
26712 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26713 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26714 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26716 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26718 if(this.tabPosition != "bottom"){
26719 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26720 * @type Roo.Element
26722 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26723 this.el.addClass("x-tabs-top");
26727 this.bodyEl.setStyle("position", "relative");
26729 this.active = null;
26730 this.activateDelegate = this.activate.createDelegate(this);
26735 * Fires when the active tab changes
26736 * @param {Roo.TabPanel} this
26737 * @param {Roo.TabPanelItem} activePanel The new active tab
26741 * @event beforetabchange
26742 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26743 * @param {Roo.TabPanel} this
26744 * @param {Object} e Set cancel to true on this object to cancel the tab change
26745 * @param {Roo.TabPanelItem} tab The tab being changed to
26747 "beforetabchange" : true
26750 Roo.EventManager.onWindowResize(this.onResize, this);
26751 this.cpad = this.el.getPadding("lr");
26752 this.hiddenCount = 0;
26755 // toolbar on the tabbar support...
26756 if (this.toolbar) {
26757 var tcfg = this.toolbar;
26758 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26759 this.toolbar = new Roo.Toolbar(tcfg);
26760 if (Roo.isSafari) {
26761 var tbl = tcfg.container.child('table', true);
26762 tbl.setAttribute('width', '100%');
26769 Roo.TabPanel.superclass.constructor.call(this);
26772 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26774 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26776 tabPosition : "top",
26778 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26780 currentTabWidth : 0,
26782 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26786 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26790 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26792 preferredTabWidth : 175,
26794 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26796 resizeTabs : false,
26798 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26800 monitorResize : true,
26802 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26807 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26808 * @param {String} id The id of the div to use <b>or create</b>
26809 * @param {String} text The text for the tab
26810 * @param {String} content (optional) Content to put in the TabPanelItem body
26811 * @param {Boolean} closable (optional) True to create a close icon on the tab
26812 * @return {Roo.TabPanelItem} The created TabPanelItem
26814 addTab : function(id, text, content, closable){
26815 var item = new Roo.TabPanelItem(this, id, text, closable);
26816 this.addTabItem(item);
26818 item.setContent(content);
26824 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26825 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26826 * @return {Roo.TabPanelItem}
26828 getTab : function(id){
26829 return this.items[id];
26833 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26834 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26836 hideTab : function(id){
26837 var t = this.items[id];
26840 this.hiddenCount++;
26841 this.autoSizeTabs();
26846 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26847 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26849 unhideTab : function(id){
26850 var t = this.items[id];
26852 t.setHidden(false);
26853 this.hiddenCount--;
26854 this.autoSizeTabs();
26859 * Adds an existing {@link Roo.TabPanelItem}.
26860 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26862 addTabItem : function(item){
26863 this.items[item.id] = item;
26864 this.items.push(item);
26865 if(this.resizeTabs){
26866 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26867 this.autoSizeTabs();
26874 * Removes a {@link Roo.TabPanelItem}.
26875 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26877 removeTab : function(id){
26878 var items = this.items;
26879 var tab = items[id];
26880 if(!tab) { return; }
26881 var index = items.indexOf(tab);
26882 if(this.active == tab && items.length > 1){
26883 var newTab = this.getNextAvailable(index);
26888 this.stripEl.dom.removeChild(tab.pnode.dom);
26889 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26890 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26892 items.splice(index, 1);
26893 delete this.items[tab.id];
26894 tab.fireEvent("close", tab);
26895 tab.purgeListeners();
26896 this.autoSizeTabs();
26899 getNextAvailable : function(start){
26900 var items = this.items;
26902 // look for a next tab that will slide over to
26903 // replace the one being removed
26904 while(index < items.length){
26905 var item = items[++index];
26906 if(item && !item.isHidden()){
26910 // if one isn't found select the previous tab (on the left)
26913 var item = items[--index];
26914 if(item && !item.isHidden()){
26922 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26923 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26925 disableTab : function(id){
26926 var tab = this.items[id];
26927 if(tab && this.active != tab){
26933 * Enables a {@link Roo.TabPanelItem} that is disabled.
26934 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26936 enableTab : function(id){
26937 var tab = this.items[id];
26942 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26943 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26944 * @return {Roo.TabPanelItem} The TabPanelItem.
26946 activate : function(id){
26947 var tab = this.items[id];
26951 if(tab == this.active || tab.disabled){
26955 this.fireEvent("beforetabchange", this, e, tab);
26956 if(e.cancel !== true && !tab.disabled){
26958 this.active.hide();
26960 this.active = this.items[id];
26961 this.active.show();
26962 this.fireEvent("tabchange", this, this.active);
26968 * Gets the active {@link Roo.TabPanelItem}.
26969 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26971 getActiveTab : function(){
26972 return this.active;
26976 * Updates the tab body element to fit the height of the container element
26977 * for overflow scrolling
26978 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26980 syncHeight : function(targetHeight){
26981 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26982 var bm = this.bodyEl.getMargins();
26983 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26984 this.bodyEl.setHeight(newHeight);
26988 onResize : function(){
26989 if(this.monitorResize){
26990 this.autoSizeTabs();
26995 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26997 beginUpdate : function(){
26998 this.updating = true;
27002 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27004 endUpdate : function(){
27005 this.updating = false;
27006 this.autoSizeTabs();
27010 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27012 autoSizeTabs : function(){
27013 var count = this.items.length;
27014 var vcount = count - this.hiddenCount;
27015 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
27016 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27017 var availWidth = Math.floor(w / vcount);
27018 var b = this.stripBody;
27019 if(b.getWidth() > w){
27020 var tabs = this.items;
27021 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27022 if(availWidth < this.minTabWidth){
27023 /*if(!this.sleft){ // incomplete scrolling code
27024 this.createScrollButtons();
27027 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27030 if(this.currentTabWidth < this.preferredTabWidth){
27031 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27037 * Returns the number of tabs in this TabPanel.
27040 getCount : function(){
27041 return this.items.length;
27045 * Resizes all the tabs to the passed width
27046 * @param {Number} The new width
27048 setTabWidth : function(width){
27049 this.currentTabWidth = width;
27050 for(var i = 0, len = this.items.length; i < len; i++) {
27051 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27056 * Destroys this TabPanel
27057 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27059 destroy : function(removeEl){
27060 Roo.EventManager.removeResizeListener(this.onResize, this);
27061 for(var i = 0, len = this.items.length; i < len; i++){
27062 this.items[i].purgeListeners();
27064 if(removeEl === true){
27065 this.el.update("");
27072 * @class Roo.TabPanelItem
27073 * @extends Roo.util.Observable
27074 * Represents an individual item (tab plus body) in a TabPanel.
27075 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27076 * @param {String} id The id of this TabPanelItem
27077 * @param {String} text The text for the tab of this TabPanelItem
27078 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27080 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27082 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27083 * @type Roo.TabPanel
27085 this.tabPanel = tabPanel;
27087 * The id for this TabPanelItem
27092 this.disabled = false;
27096 this.loaded = false;
27097 this.closable = closable;
27100 * The body element for this TabPanelItem.
27101 * @type Roo.Element
27103 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27104 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27105 this.bodyEl.setStyle("display", "block");
27106 this.bodyEl.setStyle("zoom", "1");
27109 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27111 this.el = Roo.get(els.el, true);
27112 this.inner = Roo.get(els.inner, true);
27113 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27114 this.pnode = Roo.get(els.el.parentNode, true);
27115 this.el.on("mousedown", this.onTabMouseDown, this);
27116 this.el.on("click", this.onTabClick, this);
27119 var c = Roo.get(els.close, true);
27120 c.dom.title = this.closeText;
27121 c.addClassOnOver("close-over");
27122 c.on("click", this.closeClick, this);
27128 * Fires when this tab becomes the active tab.
27129 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27130 * @param {Roo.TabPanelItem} this
27134 * @event beforeclose
27135 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27136 * @param {Roo.TabPanelItem} this
27137 * @param {Object} e Set cancel to true on this object to cancel the close.
27139 "beforeclose": true,
27142 * Fires when this tab is closed.
27143 * @param {Roo.TabPanelItem} this
27147 * @event deactivate
27148 * Fires when this tab is no longer the active tab.
27149 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27150 * @param {Roo.TabPanelItem} this
27152 "deactivate" : true
27154 this.hidden = false;
27156 Roo.TabPanelItem.superclass.constructor.call(this);
27159 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27160 purgeListeners : function(){
27161 Roo.util.Observable.prototype.purgeListeners.call(this);
27162 this.el.removeAllListeners();
27165 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27168 this.pnode.addClass("on");
27171 this.tabPanel.stripWrap.repaint();
27173 this.fireEvent("activate", this.tabPanel, this);
27177 * Returns true if this tab is the active tab.
27178 * @return {Boolean}
27180 isActive : function(){
27181 return this.tabPanel.getActiveTab() == this;
27185 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27188 this.pnode.removeClass("on");
27190 this.fireEvent("deactivate", this.tabPanel, this);
27193 hideAction : function(){
27194 this.bodyEl.hide();
27195 this.bodyEl.setStyle("position", "absolute");
27196 this.bodyEl.setLeft("-20000px");
27197 this.bodyEl.setTop("-20000px");
27200 showAction : function(){
27201 this.bodyEl.setStyle("position", "relative");
27202 this.bodyEl.setTop("");
27203 this.bodyEl.setLeft("");
27204 this.bodyEl.show();
27208 * Set the tooltip for the tab.
27209 * @param {String} tooltip The tab's tooltip
27211 setTooltip : function(text){
27212 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27213 this.textEl.dom.qtip = text;
27214 this.textEl.dom.removeAttribute('title');
27216 this.textEl.dom.title = text;
27220 onTabClick : function(e){
27221 e.preventDefault();
27222 this.tabPanel.activate(this.id);
27225 onTabMouseDown : function(e){
27226 e.preventDefault();
27227 this.tabPanel.activate(this.id);
27230 getWidth : function(){
27231 return this.inner.getWidth();
27234 setWidth : function(width){
27235 var iwidth = width - this.pnode.getPadding("lr");
27236 this.inner.setWidth(iwidth);
27237 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27238 this.pnode.setWidth(width);
27242 * Show or hide the tab
27243 * @param {Boolean} hidden True to hide or false to show.
27245 setHidden : function(hidden){
27246 this.hidden = hidden;
27247 this.pnode.setStyle("display", hidden ? "none" : "");
27251 * Returns true if this tab is "hidden"
27252 * @return {Boolean}
27254 isHidden : function(){
27255 return this.hidden;
27259 * Returns the text for this tab
27262 getText : function(){
27266 autoSize : function(){
27267 //this.el.beginMeasure();
27268 this.textEl.setWidth(1);
27270 * #2804 [new] Tabs in Roojs
27271 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27273 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27274 //this.el.endMeasure();
27278 * Sets the text for the tab (Note: this also sets the tooltip text)
27279 * @param {String} text The tab's text and tooltip
27281 setText : function(text){
27283 this.textEl.update(text);
27284 this.setTooltip(text);
27285 if(!this.tabPanel.resizeTabs){
27290 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27292 activate : function(){
27293 this.tabPanel.activate(this.id);
27297 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27299 disable : function(){
27300 if(this.tabPanel.active != this){
27301 this.disabled = true;
27302 this.pnode.addClass("disabled");
27307 * Enables this TabPanelItem if it was previously disabled.
27309 enable : function(){
27310 this.disabled = false;
27311 this.pnode.removeClass("disabled");
27315 * Sets the content for this TabPanelItem.
27316 * @param {String} content The content
27317 * @param {Boolean} loadScripts true to look for and load scripts
27319 setContent : function(content, loadScripts){
27320 this.bodyEl.update(content, loadScripts);
27324 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27325 * @return {Roo.UpdateManager} The UpdateManager
27327 getUpdateManager : function(){
27328 return this.bodyEl.getUpdateManager();
27332 * Set a URL to be used to load the content for this TabPanelItem.
27333 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27334 * @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)
27335 * @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)
27336 * @return {Roo.UpdateManager} The UpdateManager
27338 setUrl : function(url, params, loadOnce){
27339 if(this.refreshDelegate){
27340 this.un('activate', this.refreshDelegate);
27342 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27343 this.on("activate", this.refreshDelegate);
27344 return this.bodyEl.getUpdateManager();
27348 _handleRefresh : function(url, params, loadOnce){
27349 if(!loadOnce || !this.loaded){
27350 var updater = this.bodyEl.getUpdateManager();
27351 updater.update(url, params, this._setLoaded.createDelegate(this));
27356 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27357 * Will fail silently if the setUrl method has not been called.
27358 * This does not activate the panel, just updates its content.
27360 refresh : function(){
27361 if(this.refreshDelegate){
27362 this.loaded = false;
27363 this.refreshDelegate();
27368 _setLoaded : function(){
27369 this.loaded = true;
27373 closeClick : function(e){
27376 this.fireEvent("beforeclose", this, o);
27377 if(o.cancel !== true){
27378 this.tabPanel.removeTab(this.id);
27382 * The text displayed in the tooltip for the close icon.
27385 closeText : "Close this tab"
27389 Roo.TabPanel.prototype.createStrip = function(container){
27390 var strip = document.createElement("div");
27391 strip.className = "x-tabs-wrap";
27392 container.appendChild(strip);
27396 Roo.TabPanel.prototype.createStripList = function(strip){
27397 // div wrapper for retard IE
27398 // returns the "tr" element.
27399 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27400 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27401 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27402 return strip.firstChild.firstChild.firstChild.firstChild;
27405 Roo.TabPanel.prototype.createBody = function(container){
27406 var body = document.createElement("div");
27407 Roo.id(body, "tab-body");
27408 Roo.fly(body).addClass("x-tabs-body");
27409 container.appendChild(body);
27413 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27414 var body = Roo.getDom(id);
27416 body = document.createElement("div");
27419 Roo.fly(body).addClass("x-tabs-item-body");
27420 bodyEl.insertBefore(body, bodyEl.firstChild);
27424 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27425 var td = document.createElement("td");
27426 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27427 //stripEl.appendChild(td);
27429 td.className = "x-tabs-closable";
27430 if(!this.closeTpl){
27431 this.closeTpl = new Roo.Template(
27432 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27433 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27434 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27437 var el = this.closeTpl.overwrite(td, {"text": text});
27438 var close = el.getElementsByTagName("div")[0];
27439 var inner = el.getElementsByTagName("em")[0];
27440 return {"el": el, "close": close, "inner": inner};
27443 this.tabTpl = new Roo.Template(
27444 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27445 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27448 var el = this.tabTpl.overwrite(td, {"text": text});
27449 var inner = el.getElementsByTagName("em")[0];
27450 return {"el": el, "inner": inner};
27454 * Ext JS Library 1.1.1
27455 * Copyright(c) 2006-2007, Ext JS, LLC.
27457 * Originally Released Under LGPL - original licence link has changed is not relivant.
27460 * <script type="text/javascript">
27464 * @class Roo.Button
27465 * @extends Roo.util.Observable
27466 * Simple Button class
27467 * @cfg {String} text The button text
27468 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27469 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27470 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27471 * @cfg {Object} scope The scope of the handler
27472 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27473 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27474 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27475 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27476 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27477 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27478 applies if enableToggle = true)
27479 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27480 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27481 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27483 * Create a new button
27484 * @param {Object} config The config object
27486 Roo.Button = function(renderTo, config)
27490 renderTo = config.renderTo || false;
27493 Roo.apply(this, config);
27497 * Fires when this button is clicked
27498 * @param {Button} this
27499 * @param {EventObject} e The click event
27504 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27505 * @param {Button} this
27506 * @param {Boolean} pressed
27511 * Fires when the mouse hovers over the button
27512 * @param {Button} this
27513 * @param {Event} e The event object
27515 'mouseover' : true,
27518 * Fires when the mouse exits the button
27519 * @param {Button} this
27520 * @param {Event} e The event object
27525 * Fires when the button is rendered
27526 * @param {Button} this
27531 this.menu = Roo.menu.MenuMgr.get(this.menu);
27533 // register listeners first!! - so render can be captured..
27534 Roo.util.Observable.call(this);
27536 this.render(renderTo);
27542 Roo.extend(Roo.Button, Roo.util.Observable, {
27548 * Read-only. True if this button is hidden
27553 * Read-only. True if this button is disabled
27558 * Read-only. True if this button is pressed (only if enableToggle = true)
27564 * @cfg {Number} tabIndex
27565 * The DOM tabIndex for this button (defaults to undefined)
27567 tabIndex : undefined,
27570 * @cfg {Boolean} enableToggle
27571 * True to enable pressed/not pressed toggling (defaults to false)
27573 enableToggle: false,
27575 * @cfg {Mixed} menu
27576 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27580 * @cfg {String} menuAlign
27581 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27583 menuAlign : "tl-bl?",
27586 * @cfg {String} iconCls
27587 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27589 iconCls : undefined,
27591 * @cfg {String} type
27592 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27597 menuClassTarget: 'tr',
27600 * @cfg {String} clickEvent
27601 * The type of event to map to the button's event handler (defaults to 'click')
27603 clickEvent : 'click',
27606 * @cfg {Boolean} handleMouseEvents
27607 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27609 handleMouseEvents : true,
27612 * @cfg {String} tooltipType
27613 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27615 tooltipType : 'qtip',
27618 * @cfg {String} cls
27619 * A CSS class to apply to the button's main element.
27623 * @cfg {Roo.Template} template (Optional)
27624 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27625 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27626 * require code modifications if required elements (e.g. a button) aren't present.
27630 render : function(renderTo){
27632 if(this.hideParent){
27633 this.parentEl = Roo.get(renderTo);
27635 if(!this.dhconfig){
27636 if(!this.template){
27637 if(!Roo.Button.buttonTemplate){
27638 // hideous table template
27639 Roo.Button.buttonTemplate = new Roo.Template(
27640 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27641 '<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>',
27642 "</tr></tbody></table>");
27644 this.template = Roo.Button.buttonTemplate;
27646 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27647 var btnEl = btn.child("button:first");
27648 btnEl.on('focus', this.onFocus, this);
27649 btnEl.on('blur', this.onBlur, this);
27651 btn.addClass(this.cls);
27654 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27657 btnEl.addClass(this.iconCls);
27659 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27662 if(this.tabIndex !== undefined){
27663 btnEl.dom.tabIndex = this.tabIndex;
27666 if(typeof this.tooltip == 'object'){
27667 Roo.QuickTips.tips(Roo.apply({
27671 btnEl.dom[this.tooltipType] = this.tooltip;
27675 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27679 this.el.dom.id = this.el.id = this.id;
27682 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27683 this.menu.on("show", this.onMenuShow, this);
27684 this.menu.on("hide", this.onMenuHide, this);
27686 btn.addClass("x-btn");
27687 if(Roo.isIE && !Roo.isIE7){
27688 this.autoWidth.defer(1, this);
27692 if(this.handleMouseEvents){
27693 btn.on("mouseover", this.onMouseOver, this);
27694 btn.on("mouseout", this.onMouseOut, this);
27695 btn.on("mousedown", this.onMouseDown, this);
27697 btn.on(this.clickEvent, this.onClick, this);
27698 //btn.on("mouseup", this.onMouseUp, this);
27705 Roo.ButtonToggleMgr.register(this);
27707 this.el.addClass("x-btn-pressed");
27710 var repeater = new Roo.util.ClickRepeater(btn,
27711 typeof this.repeat == "object" ? this.repeat : {}
27713 repeater.on("click", this.onClick, this);
27716 this.fireEvent('render', this);
27720 * Returns the button's underlying element
27721 * @return {Roo.Element} The element
27723 getEl : function(){
27728 * Destroys this Button and removes any listeners.
27730 destroy : function(){
27731 Roo.ButtonToggleMgr.unregister(this);
27732 this.el.removeAllListeners();
27733 this.purgeListeners();
27738 autoWidth : function(){
27740 this.el.setWidth("auto");
27741 if(Roo.isIE7 && Roo.isStrict){
27742 var ib = this.el.child('button');
27743 if(ib && ib.getWidth() > 20){
27745 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27750 this.el.beginMeasure();
27752 if(this.el.getWidth() < this.minWidth){
27753 this.el.setWidth(this.minWidth);
27756 this.el.endMeasure();
27763 * Assigns this button's click handler
27764 * @param {Function} handler The function to call when the button is clicked
27765 * @param {Object} scope (optional) Scope for the function passed in
27767 setHandler : function(handler, scope){
27768 this.handler = handler;
27769 this.scope = scope;
27773 * Sets this button's text
27774 * @param {String} text The button text
27776 setText : function(text){
27779 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27785 * Gets the text for this button
27786 * @return {String} The button text
27788 getText : function(){
27796 this.hidden = false;
27798 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27806 this.hidden = true;
27808 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27813 * Convenience function for boolean show/hide
27814 * @param {Boolean} visible True to show, false to hide
27816 setVisible: function(visible){
27825 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27826 * @param {Boolean} state (optional) Force a particular state
27828 toggle : function(state){
27829 state = state === undefined ? !this.pressed : state;
27830 if(state != this.pressed){
27832 this.el.addClass("x-btn-pressed");
27833 this.pressed = true;
27834 this.fireEvent("toggle", this, true);
27836 this.el.removeClass("x-btn-pressed");
27837 this.pressed = false;
27838 this.fireEvent("toggle", this, false);
27840 if(this.toggleHandler){
27841 this.toggleHandler.call(this.scope || this, this, state);
27849 focus : function(){
27850 this.el.child('button:first').focus();
27854 * Disable this button
27856 disable : function(){
27858 this.el.addClass("x-btn-disabled");
27860 this.disabled = true;
27864 * Enable this button
27866 enable : function(){
27868 this.el.removeClass("x-btn-disabled");
27870 this.disabled = false;
27874 * Convenience function for boolean enable/disable
27875 * @param {Boolean} enabled True to enable, false to disable
27877 setDisabled : function(v){
27878 this[v !== true ? "enable" : "disable"]();
27882 onClick : function(e)
27885 e.preventDefault();
27890 if(!this.disabled){
27891 if(this.enableToggle){
27894 if(this.menu && !this.menu.isVisible()){
27895 this.menu.show(this.el, this.menuAlign);
27897 this.fireEvent("click", this, e);
27899 this.el.removeClass("x-btn-over");
27900 this.handler.call(this.scope || this, this, e);
27905 onMouseOver : function(e){
27906 if(!this.disabled){
27907 this.el.addClass("x-btn-over");
27908 this.fireEvent('mouseover', this, e);
27912 onMouseOut : function(e){
27913 if(!e.within(this.el, true)){
27914 this.el.removeClass("x-btn-over");
27915 this.fireEvent('mouseout', this, e);
27919 onFocus : function(e){
27920 if(!this.disabled){
27921 this.el.addClass("x-btn-focus");
27925 onBlur : function(e){
27926 this.el.removeClass("x-btn-focus");
27929 onMouseDown : function(e){
27930 if(!this.disabled && e.button == 0){
27931 this.el.addClass("x-btn-click");
27932 Roo.get(document).on('mouseup', this.onMouseUp, this);
27936 onMouseUp : function(e){
27938 this.el.removeClass("x-btn-click");
27939 Roo.get(document).un('mouseup', this.onMouseUp, this);
27943 onMenuShow : function(e){
27944 this.el.addClass("x-btn-menu-active");
27947 onMenuHide : function(e){
27948 this.el.removeClass("x-btn-menu-active");
27952 // Private utility class used by Button
27953 Roo.ButtonToggleMgr = function(){
27956 function toggleGroup(btn, state){
27958 var g = groups[btn.toggleGroup];
27959 for(var i = 0, l = g.length; i < l; i++){
27961 g[i].toggle(false);
27968 register : function(btn){
27969 if(!btn.toggleGroup){
27972 var g = groups[btn.toggleGroup];
27974 g = groups[btn.toggleGroup] = [];
27977 btn.on("toggle", toggleGroup);
27980 unregister : function(btn){
27981 if(!btn.toggleGroup){
27984 var g = groups[btn.toggleGroup];
27987 btn.un("toggle", toggleGroup);
27993 * Ext JS Library 1.1.1
27994 * Copyright(c) 2006-2007, Ext JS, LLC.
27996 * Originally Released Under LGPL - original licence link has changed is not relivant.
27999 * <script type="text/javascript">
28003 * @class Roo.SplitButton
28004 * @extends Roo.Button
28005 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28006 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28007 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28008 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28009 * @cfg {String} arrowTooltip The title attribute of the arrow
28011 * Create a new menu button
28012 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28013 * @param {Object} config The config object
28015 Roo.SplitButton = function(renderTo, config){
28016 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28018 * @event arrowclick
28019 * Fires when this button's arrow is clicked
28020 * @param {SplitButton} this
28021 * @param {EventObject} e The click event
28023 this.addEvents({"arrowclick":true});
28026 Roo.extend(Roo.SplitButton, Roo.Button, {
28027 render : function(renderTo){
28028 // this is one sweet looking template!
28029 var tpl = new Roo.Template(
28030 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28031 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28032 '<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>',
28033 "</tbody></table></td><td>",
28034 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28035 '<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>',
28036 "</tbody></table></td></tr></table>"
28038 var btn = tpl.append(renderTo, [this.text, this.type], true);
28039 var btnEl = btn.child("button");
28041 btn.addClass(this.cls);
28044 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28047 btnEl.addClass(this.iconCls);
28049 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28053 if(this.handleMouseEvents){
28054 btn.on("mouseover", this.onMouseOver, this);
28055 btn.on("mouseout", this.onMouseOut, this);
28056 btn.on("mousedown", this.onMouseDown, this);
28057 btn.on("mouseup", this.onMouseUp, this);
28059 btn.on(this.clickEvent, this.onClick, this);
28061 if(typeof this.tooltip == 'object'){
28062 Roo.QuickTips.tips(Roo.apply({
28066 btnEl.dom[this.tooltipType] = this.tooltip;
28069 if(this.arrowTooltip){
28070 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28079 this.el.addClass("x-btn-pressed");
28081 if(Roo.isIE && !Roo.isIE7){
28082 this.autoWidth.defer(1, this);
28087 this.menu.on("show", this.onMenuShow, this);
28088 this.menu.on("hide", this.onMenuHide, this);
28090 this.fireEvent('render', this);
28094 autoWidth : function(){
28096 var tbl = this.el.child("table:first");
28097 var tbl2 = this.el.child("table:last");
28098 this.el.setWidth("auto");
28099 tbl.setWidth("auto");
28100 if(Roo.isIE7 && Roo.isStrict){
28101 var ib = this.el.child('button:first');
28102 if(ib && ib.getWidth() > 20){
28104 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28109 this.el.beginMeasure();
28111 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28112 tbl.setWidth(this.minWidth-tbl2.getWidth());
28115 this.el.endMeasure();
28118 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28122 * Sets this button's click handler
28123 * @param {Function} handler The function to call when the button is clicked
28124 * @param {Object} scope (optional) Scope for the function passed above
28126 setHandler : function(handler, scope){
28127 this.handler = handler;
28128 this.scope = scope;
28132 * Sets this button's arrow click handler
28133 * @param {Function} handler The function to call when the arrow is clicked
28134 * @param {Object} scope (optional) Scope for the function passed above
28136 setArrowHandler : function(handler, scope){
28137 this.arrowHandler = handler;
28138 this.scope = scope;
28144 focus : function(){
28146 this.el.child("button:first").focus();
28151 onClick : function(e){
28152 e.preventDefault();
28153 if(!this.disabled){
28154 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28155 if(this.menu && !this.menu.isVisible()){
28156 this.menu.show(this.el, this.menuAlign);
28158 this.fireEvent("arrowclick", this, e);
28159 if(this.arrowHandler){
28160 this.arrowHandler.call(this.scope || this, this, e);
28163 this.fireEvent("click", this, e);
28165 this.handler.call(this.scope || this, this, e);
28171 onMouseDown : function(e){
28172 if(!this.disabled){
28173 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28177 onMouseUp : function(e){
28178 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28183 // backwards compat
28184 Roo.MenuButton = Roo.SplitButton;/*
28186 * Ext JS Library 1.1.1
28187 * Copyright(c) 2006-2007, Ext JS, LLC.
28189 * Originally Released Under LGPL - original licence link has changed is not relivant.
28192 * <script type="text/javascript">
28196 * @class Roo.Toolbar
28197 * Basic Toolbar class.
28199 * Creates a new Toolbar
28200 * @param {Object} container The config object
28202 Roo.Toolbar = function(container, buttons, config)
28204 /// old consturctor format still supported..
28205 if(container instanceof Array){ // omit the container for later rendering
28206 buttons = container;
28210 if (typeof(container) == 'object' && container.xtype) {
28211 config = container;
28212 container = config.container;
28213 buttons = config.buttons || []; // not really - use items!!
28216 if (config && config.items) {
28217 xitems = config.items;
28218 delete config.items;
28220 Roo.apply(this, config);
28221 this.buttons = buttons;
28224 this.render(container);
28226 this.xitems = xitems;
28227 Roo.each(xitems, function(b) {
28233 Roo.Toolbar.prototype = {
28235 * @cfg {Array} items
28236 * array of button configs or elements to add (will be converted to a MixedCollection)
28240 * @cfg {String/HTMLElement/Element} container
28241 * The id or element that will contain the toolbar
28244 render : function(ct){
28245 this.el = Roo.get(ct);
28247 this.el.addClass(this.cls);
28249 // using a table allows for vertical alignment
28250 // 100% width is needed by Safari...
28251 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28252 this.tr = this.el.child("tr", true);
28254 this.items = new Roo.util.MixedCollection(false, function(o){
28255 return o.id || ("item" + (++autoId));
28258 this.add.apply(this, this.buttons);
28259 delete this.buttons;
28264 * Adds element(s) to the toolbar -- this function takes a variable number of
28265 * arguments of mixed type and adds them to the toolbar.
28266 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28268 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28269 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28270 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28271 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28272 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28273 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28274 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28275 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28276 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28278 * @param {Mixed} arg2
28279 * @param {Mixed} etc.
28282 var a = arguments, l = a.length;
28283 for(var i = 0; i < l; i++){
28288 _add : function(el) {
28291 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28294 if (el.applyTo){ // some kind of form field
28295 return this.addField(el);
28297 if (el.render){ // some kind of Toolbar.Item
28298 return this.addItem(el);
28300 if (typeof el == "string"){ // string
28301 if(el == "separator" || el == "-"){
28302 return this.addSeparator();
28305 return this.addSpacer();
28308 return this.addFill();
28310 return this.addText(el);
28313 if(el.tagName){ // element
28314 return this.addElement(el);
28316 if(typeof el == "object"){ // must be button config?
28317 return this.addButton(el);
28319 // and now what?!?!
28325 * Add an Xtype element
28326 * @param {Object} xtype Xtype Object
28327 * @return {Object} created Object
28329 addxtype : function(e){
28330 return this.add(e);
28334 * Returns the Element for this toolbar.
28335 * @return {Roo.Element}
28337 getEl : function(){
28343 * @return {Roo.Toolbar.Item} The separator item
28345 addSeparator : function(){
28346 return this.addItem(new Roo.Toolbar.Separator());
28350 * Adds a spacer element
28351 * @return {Roo.Toolbar.Spacer} The spacer item
28353 addSpacer : function(){
28354 return this.addItem(new Roo.Toolbar.Spacer());
28358 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28359 * @return {Roo.Toolbar.Fill} The fill item
28361 addFill : function(){
28362 return this.addItem(new Roo.Toolbar.Fill());
28366 * Adds any standard HTML element to the toolbar
28367 * @param {String/HTMLElement/Element} el The element or id of the element to add
28368 * @return {Roo.Toolbar.Item} The element's item
28370 addElement : function(el){
28371 return this.addItem(new Roo.Toolbar.Item(el));
28374 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28375 * @type Roo.util.MixedCollection
28380 * Adds any Toolbar.Item or subclass
28381 * @param {Roo.Toolbar.Item} item
28382 * @return {Roo.Toolbar.Item} The item
28384 addItem : function(item){
28385 var td = this.nextBlock();
28387 this.items.add(item);
28392 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28393 * @param {Object/Array} config A button config or array of configs
28394 * @return {Roo.Toolbar.Button/Array}
28396 addButton : function(config){
28397 if(config instanceof Array){
28399 for(var i = 0, len = config.length; i < len; i++) {
28400 buttons.push(this.addButton(config[i]));
28405 if(!(config instanceof Roo.Toolbar.Button)){
28407 new Roo.Toolbar.SplitButton(config) :
28408 new Roo.Toolbar.Button(config);
28410 var td = this.nextBlock();
28417 * Adds text to the toolbar
28418 * @param {String} text The text to add
28419 * @return {Roo.Toolbar.Item} The element's item
28421 addText : function(text){
28422 return this.addItem(new Roo.Toolbar.TextItem(text));
28426 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28427 * @param {Number} index The index where the item is to be inserted
28428 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28429 * @return {Roo.Toolbar.Button/Item}
28431 insertButton : function(index, item){
28432 if(item instanceof Array){
28434 for(var i = 0, len = item.length; i < len; i++) {
28435 buttons.push(this.insertButton(index + i, item[i]));
28439 if (!(item instanceof Roo.Toolbar.Button)){
28440 item = new Roo.Toolbar.Button(item);
28442 var td = document.createElement("td");
28443 this.tr.insertBefore(td, this.tr.childNodes[index]);
28445 this.items.insert(index, item);
28450 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28451 * @param {Object} config
28452 * @return {Roo.Toolbar.Item} The element's item
28454 addDom : function(config, returnEl){
28455 var td = this.nextBlock();
28456 Roo.DomHelper.overwrite(td, config);
28457 var ti = new Roo.Toolbar.Item(td.firstChild);
28459 this.items.add(ti);
28464 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28465 * @type Roo.util.MixedCollection
28470 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28471 * Note: the field should not have been rendered yet. For a field that has already been
28472 * rendered, use {@link #addElement}.
28473 * @param {Roo.form.Field} field
28474 * @return {Roo.ToolbarItem}
28478 addField : function(field) {
28479 if (!this.fields) {
28481 this.fields = new Roo.util.MixedCollection(false, function(o){
28482 return o.id || ("item" + (++autoId));
28487 var td = this.nextBlock();
28489 var ti = new Roo.Toolbar.Item(td.firstChild);
28491 this.items.add(ti);
28492 this.fields.add(field);
28503 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28504 this.el.child('div').hide();
28512 this.el.child('div').show();
28516 nextBlock : function(){
28517 var td = document.createElement("td");
28518 this.tr.appendChild(td);
28523 destroy : function(){
28524 if(this.items){ // rendered?
28525 Roo.destroy.apply(Roo, this.items.items);
28527 if(this.fields){ // rendered?
28528 Roo.destroy.apply(Roo, this.fields.items);
28530 Roo.Element.uncache(this.el, this.tr);
28535 * @class Roo.Toolbar.Item
28536 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28538 * Creates a new Item
28539 * @param {HTMLElement} el
28541 Roo.Toolbar.Item = function(el){
28543 if (typeof (el.xtype) != 'undefined') {
28548 this.el = Roo.getDom(el);
28549 this.id = Roo.id(this.el);
28550 this.hidden = false;
28555 * Fires when the button is rendered
28556 * @param {Button} this
28560 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28562 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28563 //Roo.Toolbar.Item.prototype = {
28566 * Get this item's HTML Element
28567 * @return {HTMLElement}
28569 getEl : function(){
28574 render : function(td){
28577 td.appendChild(this.el);
28579 this.fireEvent('render', this);
28583 * Removes and destroys this item.
28585 destroy : function(){
28586 this.td.parentNode.removeChild(this.td);
28593 this.hidden = false;
28594 this.td.style.display = "";
28601 this.hidden = true;
28602 this.td.style.display = "none";
28606 * Convenience function for boolean show/hide.
28607 * @param {Boolean} visible true to show/false to hide
28609 setVisible: function(visible){
28618 * Try to focus this item.
28620 focus : function(){
28621 Roo.fly(this.el).focus();
28625 * Disables this item.
28627 disable : function(){
28628 Roo.fly(this.td).addClass("x-item-disabled");
28629 this.disabled = true;
28630 this.el.disabled = true;
28634 * Enables this item.
28636 enable : function(){
28637 Roo.fly(this.td).removeClass("x-item-disabled");
28638 this.disabled = false;
28639 this.el.disabled = false;
28645 * @class Roo.Toolbar.Separator
28646 * @extends Roo.Toolbar.Item
28647 * A simple toolbar separator class
28649 * Creates a new Separator
28651 Roo.Toolbar.Separator = function(cfg){
28653 var s = document.createElement("span");
28654 s.className = "ytb-sep";
28659 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28661 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28662 enable:Roo.emptyFn,
28663 disable:Roo.emptyFn,
28668 * @class Roo.Toolbar.Spacer
28669 * @extends Roo.Toolbar.Item
28670 * A simple element that adds extra horizontal space to a toolbar.
28672 * Creates a new Spacer
28674 Roo.Toolbar.Spacer = function(cfg){
28675 var s = document.createElement("div");
28676 s.className = "ytb-spacer";
28680 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28682 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28683 enable:Roo.emptyFn,
28684 disable:Roo.emptyFn,
28689 * @class Roo.Toolbar.Fill
28690 * @extends Roo.Toolbar.Spacer
28691 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28693 * Creates a new Spacer
28695 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28697 render : function(td){
28698 td.style.width = '100%';
28699 Roo.Toolbar.Fill.superclass.render.call(this, td);
28704 * @class Roo.Toolbar.TextItem
28705 * @extends Roo.Toolbar.Item
28706 * A simple class that renders text directly into a toolbar.
28708 * Creates a new TextItem
28709 * @param {String} text
28711 Roo.Toolbar.TextItem = function(cfg){
28712 var text = cfg || "";
28713 if (typeof(cfg) == 'object') {
28714 text = cfg.text || "";
28718 var s = document.createElement("span");
28719 s.className = "ytb-text";
28720 s.innerHTML = text;
28725 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28727 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28730 enable:Roo.emptyFn,
28731 disable:Roo.emptyFn,
28736 * @class Roo.Toolbar.Button
28737 * @extends Roo.Button
28738 * A button that renders into a toolbar.
28740 * Creates a new Button
28741 * @param {Object} config A standard {@link Roo.Button} config object
28743 Roo.Toolbar.Button = function(config){
28744 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28746 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28747 render : function(td){
28749 Roo.Toolbar.Button.superclass.render.call(this, td);
28753 * Removes and destroys this button
28755 destroy : function(){
28756 Roo.Toolbar.Button.superclass.destroy.call(this);
28757 this.td.parentNode.removeChild(this.td);
28761 * Shows this button
28764 this.hidden = false;
28765 this.td.style.display = "";
28769 * Hides this button
28772 this.hidden = true;
28773 this.td.style.display = "none";
28777 * Disables this item
28779 disable : function(){
28780 Roo.fly(this.td).addClass("x-item-disabled");
28781 this.disabled = true;
28785 * Enables this item
28787 enable : function(){
28788 Roo.fly(this.td).removeClass("x-item-disabled");
28789 this.disabled = false;
28792 // backwards compat
28793 Roo.ToolbarButton = Roo.Toolbar.Button;
28796 * @class Roo.Toolbar.SplitButton
28797 * @extends Roo.SplitButton
28798 * A menu button that renders into a toolbar.
28800 * Creates a new SplitButton
28801 * @param {Object} config A standard {@link Roo.SplitButton} config object
28803 Roo.Toolbar.SplitButton = function(config){
28804 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28806 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28807 render : function(td){
28809 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28813 * Removes and destroys this button
28815 destroy : function(){
28816 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28817 this.td.parentNode.removeChild(this.td);
28821 * Shows this button
28824 this.hidden = false;
28825 this.td.style.display = "";
28829 * Hides this button
28832 this.hidden = true;
28833 this.td.style.display = "none";
28837 // backwards compat
28838 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28840 * Ext JS Library 1.1.1
28841 * Copyright(c) 2006-2007, Ext JS, LLC.
28843 * Originally Released Under LGPL - original licence link has changed is not relivant.
28846 * <script type="text/javascript">
28850 * @class Roo.PagingToolbar
28851 * @extends Roo.Toolbar
28852 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28854 * Create a new PagingToolbar
28855 * @param {Object} config The config object
28857 Roo.PagingToolbar = function(el, ds, config)
28859 // old args format still supported... - xtype is prefered..
28860 if (typeof(el) == 'object' && el.xtype) {
28861 // created from xtype...
28863 ds = el.dataSource;
28864 el = config.container;
28867 if (config.items) {
28868 items = config.items;
28872 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28875 this.renderButtons(this.el);
28878 // supprot items array.
28880 Roo.each(items, function(e) {
28881 this.add(Roo.factory(e));
28886 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28888 * @cfg {Roo.data.Store} dataSource
28889 * The underlying data store providing the paged data
28892 * @cfg {String/HTMLElement/Element} container
28893 * container The id or element that will contain the toolbar
28896 * @cfg {Boolean} displayInfo
28897 * True to display the displayMsg (defaults to false)
28900 * @cfg {Number} pageSize
28901 * The number of records to display per page (defaults to 20)
28905 * @cfg {String} displayMsg
28906 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28908 displayMsg : 'Displaying {0} - {1} of {2}',
28910 * @cfg {String} emptyMsg
28911 * The message to display when no records are found (defaults to "No data to display")
28913 emptyMsg : 'No data to display',
28915 * Customizable piece of the default paging text (defaults to "Page")
28918 beforePageText : "Page",
28920 * Customizable piece of the default paging text (defaults to "of %0")
28923 afterPageText : "of {0}",
28925 * Customizable piece of the default paging text (defaults to "First Page")
28928 firstText : "First Page",
28930 * Customizable piece of the default paging text (defaults to "Previous Page")
28933 prevText : "Previous Page",
28935 * Customizable piece of the default paging text (defaults to "Next Page")
28938 nextText : "Next Page",
28940 * Customizable piece of the default paging text (defaults to "Last Page")
28943 lastText : "Last Page",
28945 * Customizable piece of the default paging text (defaults to "Refresh")
28948 refreshText : "Refresh",
28951 renderButtons : function(el){
28952 Roo.PagingToolbar.superclass.render.call(this, el);
28953 this.first = this.addButton({
28954 tooltip: this.firstText,
28955 cls: "x-btn-icon x-grid-page-first",
28957 handler: this.onClick.createDelegate(this, ["first"])
28959 this.prev = this.addButton({
28960 tooltip: this.prevText,
28961 cls: "x-btn-icon x-grid-page-prev",
28963 handler: this.onClick.createDelegate(this, ["prev"])
28965 //this.addSeparator();
28966 this.add(this.beforePageText);
28967 this.field = Roo.get(this.addDom({
28972 cls: "x-grid-page-number"
28974 this.field.on("keydown", this.onPagingKeydown, this);
28975 this.field.on("focus", function(){this.dom.select();});
28976 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28977 this.field.setHeight(18);
28978 //this.addSeparator();
28979 this.next = this.addButton({
28980 tooltip: this.nextText,
28981 cls: "x-btn-icon x-grid-page-next",
28983 handler: this.onClick.createDelegate(this, ["next"])
28985 this.last = this.addButton({
28986 tooltip: this.lastText,
28987 cls: "x-btn-icon x-grid-page-last",
28989 handler: this.onClick.createDelegate(this, ["last"])
28991 //this.addSeparator();
28992 this.loading = this.addButton({
28993 tooltip: this.refreshText,
28994 cls: "x-btn-icon x-grid-loading",
28995 handler: this.onClick.createDelegate(this, ["refresh"])
28998 if(this.displayInfo){
28999 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29004 updateInfo : function(){
29005 if(this.displayEl){
29006 var count = this.ds.getCount();
29007 var msg = count == 0 ?
29011 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29013 this.displayEl.update(msg);
29018 onLoad : function(ds, r, o){
29019 this.cursor = o.params ? o.params.start : 0;
29020 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29022 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29023 this.field.dom.value = ap;
29024 this.first.setDisabled(ap == 1);
29025 this.prev.setDisabled(ap == 1);
29026 this.next.setDisabled(ap == ps);
29027 this.last.setDisabled(ap == ps);
29028 this.loading.enable();
29033 getPageData : function(){
29034 var total = this.ds.getTotalCount();
29037 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29038 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29043 onLoadError : function(){
29044 this.loading.enable();
29048 onPagingKeydown : function(e){
29049 var k = e.getKey();
29050 var d = this.getPageData();
29052 var v = this.field.dom.value, pageNum;
29053 if(!v || isNaN(pageNum = parseInt(v, 10))){
29054 this.field.dom.value = d.activePage;
29057 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29058 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29061 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))
29063 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29064 this.field.dom.value = pageNum;
29065 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29068 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29070 var v = this.field.dom.value, pageNum;
29071 var increment = (e.shiftKey) ? 10 : 1;
29072 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29074 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29075 this.field.dom.value = d.activePage;
29078 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29080 this.field.dom.value = parseInt(v, 10) + increment;
29081 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29082 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29089 beforeLoad : function(){
29091 this.loading.disable();
29096 onClick : function(which){
29100 ds.load({params:{start: 0, limit: this.pageSize}});
29103 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29106 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29109 var total = ds.getTotalCount();
29110 var extra = total % this.pageSize;
29111 var lastStart = extra ? (total - extra) : total-this.pageSize;
29112 ds.load({params:{start: lastStart, limit: this.pageSize}});
29115 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29121 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29122 * @param {Roo.data.Store} store The data store to unbind
29124 unbind : function(ds){
29125 ds.un("beforeload", this.beforeLoad, this);
29126 ds.un("load", this.onLoad, this);
29127 ds.un("loadexception", this.onLoadError, this);
29128 ds.un("remove", this.updateInfo, this);
29129 ds.un("add", this.updateInfo, this);
29130 this.ds = undefined;
29134 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29135 * @param {Roo.data.Store} store The data store to bind
29137 bind : function(ds){
29138 ds.on("beforeload", this.beforeLoad, this);
29139 ds.on("load", this.onLoad, this);
29140 ds.on("loadexception", this.onLoadError, this);
29141 ds.on("remove", this.updateInfo, this);
29142 ds.on("add", this.updateInfo, this);
29147 * Ext JS Library 1.1.1
29148 * Copyright(c) 2006-2007, Ext JS, LLC.
29150 * Originally Released Under LGPL - original licence link has changed is not relivant.
29153 * <script type="text/javascript">
29157 * @class Roo.Resizable
29158 * @extends Roo.util.Observable
29159 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29160 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29161 * 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
29162 * the element will be wrapped for you automatically.</p>
29163 * <p>Here is the list of valid resize handles:</p>
29166 ------ -------------------
29175 'hd' horizontal drag
29178 * <p>Here's an example showing the creation of a typical Resizable:</p>
29180 var resizer = new Roo.Resizable("element-id", {
29188 resizer.on("resize", myHandler);
29190 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29191 * resizer.east.setDisplayed(false);</p>
29192 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29193 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29194 * resize operation's new size (defaults to [0, 0])
29195 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29196 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29197 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29198 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29199 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29200 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29201 * @cfg {Number} width The width of the element in pixels (defaults to null)
29202 * @cfg {Number} height The height of the element in pixels (defaults to null)
29203 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29204 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29205 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29206 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29207 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29208 * in favor of the handles config option (defaults to false)
29209 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29210 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29211 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29212 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29213 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29214 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29215 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29216 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29217 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29218 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29219 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29221 * Create a new resizable component
29222 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29223 * @param {Object} config configuration options
29225 Roo.Resizable = function(el, config)
29227 this.el = Roo.get(el);
29229 if(config && config.wrap){
29230 config.resizeChild = this.el;
29231 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29232 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29233 this.el.setStyle("overflow", "hidden");
29234 this.el.setPositioning(config.resizeChild.getPositioning());
29235 config.resizeChild.clearPositioning();
29236 if(!config.width || !config.height){
29237 var csize = config.resizeChild.getSize();
29238 this.el.setSize(csize.width, csize.height);
29240 if(config.pinned && !config.adjustments){
29241 config.adjustments = "auto";
29245 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29246 this.proxy.unselectable();
29247 this.proxy.enableDisplayMode('block');
29249 Roo.apply(this, config);
29252 this.disableTrackOver = true;
29253 this.el.addClass("x-resizable-pinned");
29255 // if the element isn't positioned, make it relative
29256 var position = this.el.getStyle("position");
29257 if(position != "absolute" && position != "fixed"){
29258 this.el.setStyle("position", "relative");
29260 if(!this.handles){ // no handles passed, must be legacy style
29261 this.handles = 's,e,se';
29262 if(this.multiDirectional){
29263 this.handles += ',n,w';
29266 if(this.handles == "all"){
29267 this.handles = "n s e w ne nw se sw";
29269 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29270 var ps = Roo.Resizable.positions;
29271 for(var i = 0, len = hs.length; i < len; i++){
29272 if(hs[i] && ps[hs[i]]){
29273 var pos = ps[hs[i]];
29274 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29278 this.corner = this.southeast;
29280 // updateBox = the box can move..
29281 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29282 this.updateBox = true;
29285 this.activeHandle = null;
29287 if(this.resizeChild){
29288 if(typeof this.resizeChild == "boolean"){
29289 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29291 this.resizeChild = Roo.get(this.resizeChild, true);
29295 if(this.adjustments == "auto"){
29296 var rc = this.resizeChild;
29297 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29298 if(rc && (hw || hn)){
29299 rc.position("relative");
29300 rc.setLeft(hw ? hw.el.getWidth() : 0);
29301 rc.setTop(hn ? hn.el.getHeight() : 0);
29303 this.adjustments = [
29304 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29305 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29309 if(this.draggable){
29310 this.dd = this.dynamic ?
29311 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29312 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29318 * @event beforeresize
29319 * Fired before resize is allowed. Set enabled to false to cancel resize.
29320 * @param {Roo.Resizable} this
29321 * @param {Roo.EventObject} e The mousedown event
29323 "beforeresize" : true,
29326 * Fired a resizing.
29327 * @param {Roo.Resizable} this
29328 * @param {Number} x The new x position
29329 * @param {Number} y The new y position
29330 * @param {Number} w The new w width
29331 * @param {Number} h The new h hight
29332 * @param {Roo.EventObject} e The mouseup event
29337 * Fired after a resize.
29338 * @param {Roo.Resizable} this
29339 * @param {Number} width The new width
29340 * @param {Number} height The new height
29341 * @param {Roo.EventObject} e The mouseup event
29346 if(this.width !== null && this.height !== null){
29347 this.resizeTo(this.width, this.height);
29349 this.updateChildSize();
29352 this.el.dom.style.zoom = 1;
29354 Roo.Resizable.superclass.constructor.call(this);
29357 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29358 resizeChild : false,
29359 adjustments : [0, 0],
29369 multiDirectional : false,
29370 disableTrackOver : false,
29371 easing : 'easeOutStrong',
29372 widthIncrement : 0,
29373 heightIncrement : 0,
29377 preserveRatio : false,
29378 transparent: false,
29384 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29386 constrainTo: undefined,
29388 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29390 resizeRegion: undefined,
29394 * Perform a manual resize
29395 * @param {Number} width
29396 * @param {Number} height
29398 resizeTo : function(width, height){
29399 this.el.setSize(width, height);
29400 this.updateChildSize();
29401 this.fireEvent("resize", this, width, height, null);
29405 startSizing : function(e, handle){
29406 this.fireEvent("beforeresize", this, e);
29407 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29410 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29411 this.overlay.unselectable();
29412 this.overlay.enableDisplayMode("block");
29413 this.overlay.on("mousemove", this.onMouseMove, this);
29414 this.overlay.on("mouseup", this.onMouseUp, this);
29416 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29418 this.resizing = true;
29419 this.startBox = this.el.getBox();
29420 this.startPoint = e.getXY();
29421 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29422 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29424 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29425 this.overlay.show();
29427 if(this.constrainTo) {
29428 var ct = Roo.get(this.constrainTo);
29429 this.resizeRegion = ct.getRegion().adjust(
29430 ct.getFrameWidth('t'),
29431 ct.getFrameWidth('l'),
29432 -ct.getFrameWidth('b'),
29433 -ct.getFrameWidth('r')
29437 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29439 this.proxy.setBox(this.startBox);
29441 this.proxy.setStyle('visibility', 'visible');
29447 onMouseDown : function(handle, e){
29450 this.activeHandle = handle;
29451 this.startSizing(e, handle);
29456 onMouseUp : function(e){
29457 var size = this.resizeElement();
29458 this.resizing = false;
29460 this.overlay.hide();
29462 this.fireEvent("resize", this, size.width, size.height, e);
29466 updateChildSize : function(){
29468 if(this.resizeChild){
29470 var child = this.resizeChild;
29471 var adj = this.adjustments;
29472 if(el.dom.offsetWidth){
29473 var b = el.getSize(true);
29474 child.setSize(b.width+adj[0], b.height+adj[1]);
29476 // Second call here for IE
29477 // The first call enables instant resizing and
29478 // the second call corrects scroll bars if they
29481 setTimeout(function(){
29482 if(el.dom.offsetWidth){
29483 var b = el.getSize(true);
29484 child.setSize(b.width+adj[0], b.height+adj[1]);
29492 snap : function(value, inc, min){
29493 if(!inc || !value) return value;
29494 var newValue = value;
29495 var m = value % inc;
29498 newValue = value + (inc-m);
29500 newValue = value - m;
29503 return Math.max(min, newValue);
29507 resizeElement : function(){
29508 var box = this.proxy.getBox();
29509 if(this.updateBox){
29510 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29512 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29514 this.updateChildSize();
29522 constrain : function(v, diff, m, mx){
29525 }else if(v - diff > mx){
29532 onMouseMove : function(e){
29535 try{// try catch so if something goes wrong the user doesn't get hung
29537 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29541 //var curXY = this.startPoint;
29542 var curSize = this.curSize || this.startBox;
29543 var x = this.startBox.x, y = this.startBox.y;
29544 var ox = x, oy = y;
29545 var w = curSize.width, h = curSize.height;
29546 var ow = w, oh = h;
29547 var mw = this.minWidth, mh = this.minHeight;
29548 var mxw = this.maxWidth, mxh = this.maxHeight;
29549 var wi = this.widthIncrement;
29550 var hi = this.heightIncrement;
29552 var eventXY = e.getXY();
29553 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29554 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29556 var pos = this.activeHandle.position;
29561 w = Math.min(Math.max(mw, w), mxw);
29566 h = Math.min(Math.max(mh, h), mxh);
29571 w = Math.min(Math.max(mw, w), mxw);
29572 h = Math.min(Math.max(mh, h), mxh);
29575 diffY = this.constrain(h, diffY, mh, mxh);
29582 var adiffX = Math.abs(diffX);
29583 var sub = (adiffX % wi); // how much
29584 if (sub > (wi/2)) { // far enough to snap
29585 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29587 // remove difference..
29588 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29592 x = Math.max(this.minX, x);
29595 diffX = this.constrain(w, diffX, mw, mxw);
29601 w = Math.min(Math.max(mw, w), mxw);
29602 diffY = this.constrain(h, diffY, mh, mxh);
29607 diffX = this.constrain(w, diffX, mw, mxw);
29608 diffY = this.constrain(h, diffY, mh, mxh);
29615 diffX = this.constrain(w, diffX, mw, mxw);
29617 h = Math.min(Math.max(mh, h), mxh);
29623 var sw = this.snap(w, wi, mw);
29624 var sh = this.snap(h, hi, mh);
29625 if(sw != w || sh != h){
29648 if(this.preserveRatio){
29653 h = Math.min(Math.max(mh, h), mxh);
29658 w = Math.min(Math.max(mw, w), mxw);
29663 w = Math.min(Math.max(mw, w), mxw);
29669 w = Math.min(Math.max(mw, w), mxw);
29675 h = Math.min(Math.max(mh, h), mxh);
29683 h = Math.min(Math.max(mh, h), mxh);
29693 h = Math.min(Math.max(mh, h), mxh);
29701 if (pos == 'hdrag') {
29704 this.proxy.setBounds(x, y, w, h);
29706 this.resizeElement();
29710 this.fireEvent("resizing", this, x, y, w, h, e);
29714 handleOver : function(){
29716 this.el.addClass("x-resizable-over");
29721 handleOut : function(){
29722 if(!this.resizing){
29723 this.el.removeClass("x-resizable-over");
29728 * Returns the element this component is bound to.
29729 * @return {Roo.Element}
29731 getEl : function(){
29736 * Returns the resizeChild element (or null).
29737 * @return {Roo.Element}
29739 getResizeChild : function(){
29740 return this.resizeChild;
29742 groupHandler : function()
29747 * Destroys this resizable. If the element was wrapped and
29748 * removeEl is not true then the element remains.
29749 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29751 destroy : function(removeEl){
29752 this.proxy.remove();
29754 this.overlay.removeAllListeners();
29755 this.overlay.remove();
29757 var ps = Roo.Resizable.positions;
29759 if(typeof ps[k] != "function" && this[ps[k]]){
29760 var h = this[ps[k]];
29761 h.el.removeAllListeners();
29766 this.el.update("");
29773 // hash to map config positions to true positions
29774 Roo.Resizable.positions = {
29775 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29780 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29782 // only initialize the template if resizable is used
29783 var tpl = Roo.DomHelper.createTemplate(
29784 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29787 Roo.Resizable.Handle.prototype.tpl = tpl;
29789 this.position = pos;
29791 // show north drag fro topdra
29792 var handlepos = pos == 'hdrag' ? 'north' : pos;
29794 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29795 if (pos == 'hdrag') {
29796 this.el.setStyle('cursor', 'pointer');
29798 this.el.unselectable();
29800 this.el.setOpacity(0);
29802 this.el.on("mousedown", this.onMouseDown, this);
29803 if(!disableTrackOver){
29804 this.el.on("mouseover", this.onMouseOver, this);
29805 this.el.on("mouseout", this.onMouseOut, this);
29810 Roo.Resizable.Handle.prototype = {
29811 afterResize : function(rz){
29816 onMouseDown : function(e){
29817 this.rz.onMouseDown(this, e);
29820 onMouseOver : function(e){
29821 this.rz.handleOver(this, e);
29824 onMouseOut : function(e){
29825 this.rz.handleOut(this, e);
29829 * Ext JS Library 1.1.1
29830 * Copyright(c) 2006-2007, Ext JS, LLC.
29832 * Originally Released Under LGPL - original licence link has changed is not relivant.
29835 * <script type="text/javascript">
29839 * @class Roo.Editor
29840 * @extends Roo.Component
29841 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29843 * Create a new Editor
29844 * @param {Roo.form.Field} field The Field object (or descendant)
29845 * @param {Object} config The config object
29847 Roo.Editor = function(field, config){
29848 Roo.Editor.superclass.constructor.call(this, config);
29849 this.field = field;
29852 * @event beforestartedit
29853 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29854 * false from the handler of this event.
29855 * @param {Editor} this
29856 * @param {Roo.Element} boundEl The underlying element bound to this editor
29857 * @param {Mixed} value The field value being set
29859 "beforestartedit" : true,
29862 * Fires when this editor is displayed
29863 * @param {Roo.Element} boundEl The underlying element bound to this editor
29864 * @param {Mixed} value The starting field value
29866 "startedit" : true,
29868 * @event beforecomplete
29869 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29870 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29871 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29872 * event will not fire since no edit actually occurred.
29873 * @param {Editor} this
29874 * @param {Mixed} value The current field value
29875 * @param {Mixed} startValue The original field value
29877 "beforecomplete" : true,
29880 * Fires after editing is complete and any changed value has been written to the underlying field.
29881 * @param {Editor} this
29882 * @param {Mixed} value The current field value
29883 * @param {Mixed} startValue The original field value
29887 * @event specialkey
29888 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29889 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29890 * @param {Roo.form.Field} this
29891 * @param {Roo.EventObject} e The event object
29893 "specialkey" : true
29897 Roo.extend(Roo.Editor, Roo.Component, {
29899 * @cfg {Boolean/String} autosize
29900 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29901 * or "height" to adopt the height only (defaults to false)
29904 * @cfg {Boolean} revertInvalid
29905 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29906 * validation fails (defaults to true)
29909 * @cfg {Boolean} ignoreNoChange
29910 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29911 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29912 * will never be ignored.
29915 * @cfg {Boolean} hideEl
29916 * False to keep the bound element visible while the editor is displayed (defaults to true)
29919 * @cfg {Mixed} value
29920 * The data value of the underlying field (defaults to "")
29924 * @cfg {String} alignment
29925 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29929 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29930 * for bottom-right shadow (defaults to "frame")
29934 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29938 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29940 completeOnEnter : false,
29942 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29944 cancelOnEsc : false,
29946 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29951 onRender : function(ct, position){
29952 this.el = new Roo.Layer({
29953 shadow: this.shadow,
29959 constrain: this.constrain
29961 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29962 if(this.field.msgTarget != 'title'){
29963 this.field.msgTarget = 'qtip';
29965 this.field.render(this.el);
29967 this.field.el.dom.setAttribute('autocomplete', 'off');
29969 this.field.on("specialkey", this.onSpecialKey, this);
29970 if(this.swallowKeys){
29971 this.field.el.swallowEvent(['keydown','keypress']);
29974 this.field.on("blur", this.onBlur, this);
29975 if(this.field.grow){
29976 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29980 onSpecialKey : function(field, e)
29982 //Roo.log('editor onSpecialKey');
29983 if(this.completeOnEnter && e.getKey() == e.ENTER){
29985 this.completeEdit();
29988 // do not fire special key otherwise it might hide close the editor...
29989 if(e.getKey() == e.ENTER){
29992 if(this.cancelOnEsc && e.getKey() == e.ESC){
29996 this.fireEvent('specialkey', field, e);
30001 * Starts the editing process and shows the editor.
30002 * @param {String/HTMLElement/Element} el The element to edit
30003 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30004 * to the innerHTML of el.
30006 startEdit : function(el, value){
30008 this.completeEdit();
30010 this.boundEl = Roo.get(el);
30011 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30012 if(!this.rendered){
30013 this.render(this.parentEl || document.body);
30015 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30018 this.startValue = v;
30019 this.field.setValue(v);
30021 var sz = this.boundEl.getSize();
30022 switch(this.autoSize){
30024 this.setSize(sz.width, "");
30027 this.setSize("", sz.height);
30030 this.setSize(sz.width, sz.height);
30033 this.el.alignTo(this.boundEl, this.alignment);
30034 this.editing = true;
30036 Roo.QuickTips.disable();
30042 * Sets the height and width of this editor.
30043 * @param {Number} width The new width
30044 * @param {Number} height The new height
30046 setSize : function(w, h){
30047 this.field.setSize(w, h);
30054 * Realigns the editor to the bound field based on the current alignment config value.
30056 realign : function(){
30057 this.el.alignTo(this.boundEl, this.alignment);
30061 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30062 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30064 completeEdit : function(remainVisible){
30068 var v = this.getValue();
30069 if(this.revertInvalid !== false && !this.field.isValid()){
30070 v = this.startValue;
30071 this.cancelEdit(true);
30073 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30074 this.editing = false;
30078 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30079 this.editing = false;
30080 if(this.updateEl && this.boundEl){
30081 this.boundEl.update(v);
30083 if(remainVisible !== true){
30086 this.fireEvent("complete", this, v, this.startValue);
30091 onShow : function(){
30093 if(this.hideEl !== false){
30094 this.boundEl.hide();
30097 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30098 this.fixIEFocus = true;
30099 this.deferredFocus.defer(50, this);
30101 this.field.focus();
30103 this.fireEvent("startedit", this.boundEl, this.startValue);
30106 deferredFocus : function(){
30108 this.field.focus();
30113 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30114 * reverted to the original starting value.
30115 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30116 * cancel (defaults to false)
30118 cancelEdit : function(remainVisible){
30120 this.setValue(this.startValue);
30121 if(remainVisible !== true){
30128 onBlur : function(){
30129 if(this.allowBlur !== true && this.editing){
30130 this.completeEdit();
30135 onHide : function(){
30137 this.completeEdit();
30141 if(this.field.collapse){
30142 this.field.collapse();
30145 if(this.hideEl !== false){
30146 this.boundEl.show();
30149 Roo.QuickTips.enable();
30154 * Sets the data value of the editor
30155 * @param {Mixed} value Any valid value supported by the underlying field
30157 setValue : function(v){
30158 this.field.setValue(v);
30162 * Gets the data value of the editor
30163 * @return {Mixed} The data value
30165 getValue : function(){
30166 return this.field.getValue();
30170 * Ext JS Library 1.1.1
30171 * Copyright(c) 2006-2007, Ext JS, LLC.
30173 * Originally Released Under LGPL - original licence link has changed is not relivant.
30176 * <script type="text/javascript">
30180 * @class Roo.BasicDialog
30181 * @extends Roo.util.Observable
30182 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30184 var dlg = new Roo.BasicDialog("my-dlg", {
30193 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30194 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30195 dlg.addButton('Cancel', dlg.hide, dlg);
30198 <b>A Dialog should always be a direct child of the body element.</b>
30199 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30200 * @cfg {String} title Default text to display in the title bar (defaults to null)
30201 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30202 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30203 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30204 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30205 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30206 * (defaults to null with no animation)
30207 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30208 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30209 * property for valid values (defaults to 'all')
30210 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30211 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30212 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30213 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30214 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30215 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30216 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30217 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30218 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30219 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30220 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30221 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30222 * draggable = true (defaults to false)
30223 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30224 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30225 * shadow (defaults to false)
30226 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30227 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30228 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30229 * @cfg {Array} buttons Array of buttons
30230 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30232 * Create a new BasicDialog.
30233 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30234 * @param {Object} config Configuration options
30236 Roo.BasicDialog = function(el, config){
30237 this.el = Roo.get(el);
30238 var dh = Roo.DomHelper;
30239 if(!this.el && config && config.autoCreate){
30240 if(typeof config.autoCreate == "object"){
30241 if(!config.autoCreate.id){
30242 config.autoCreate.id = el;
30244 this.el = dh.append(document.body,
30245 config.autoCreate, true);
30247 this.el = dh.append(document.body,
30248 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30252 el.setDisplayed(true);
30253 el.hide = this.hideAction;
30255 el.addClass("x-dlg");
30257 Roo.apply(this, config);
30259 this.proxy = el.createProxy("x-dlg-proxy");
30260 this.proxy.hide = this.hideAction;
30261 this.proxy.setOpacity(.5);
30265 el.setWidth(config.width);
30268 el.setHeight(config.height);
30270 this.size = el.getSize();
30271 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30272 this.xy = [config.x,config.y];
30274 this.xy = el.getCenterXY(true);
30276 /** The header element @type Roo.Element */
30277 this.header = el.child("> .x-dlg-hd");
30278 /** The body element @type Roo.Element */
30279 this.body = el.child("> .x-dlg-bd");
30280 /** The footer element @type Roo.Element */
30281 this.footer = el.child("> .x-dlg-ft");
30284 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30287 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30290 this.header.unselectable();
30292 this.header.update(this.title);
30294 // this element allows the dialog to be focused for keyboard event
30295 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30296 this.focusEl.swallowEvent("click", true);
30298 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30300 // wrap the body and footer for special rendering
30301 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30303 this.bwrap.dom.appendChild(this.footer.dom);
30306 this.bg = this.el.createChild({
30307 tag: "div", cls:"x-dlg-bg",
30308 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30310 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30313 if(this.autoScroll !== false && !this.autoTabs){
30314 this.body.setStyle("overflow", "auto");
30317 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30319 if(this.closable !== false){
30320 this.el.addClass("x-dlg-closable");
30321 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30322 this.close.on("click", this.closeClick, this);
30323 this.close.addClassOnOver("x-dlg-close-over");
30325 if(this.collapsible !== false){
30326 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30327 this.collapseBtn.on("click", this.collapseClick, this);
30328 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30329 this.header.on("dblclick", this.collapseClick, this);
30331 if(this.resizable !== false){
30332 this.el.addClass("x-dlg-resizable");
30333 this.resizer = new Roo.Resizable(el, {
30334 minWidth: this.minWidth || 80,
30335 minHeight:this.minHeight || 80,
30336 handles: this.resizeHandles || "all",
30339 this.resizer.on("beforeresize", this.beforeResize, this);
30340 this.resizer.on("resize", this.onResize, this);
30342 if(this.draggable !== false){
30343 el.addClass("x-dlg-draggable");
30344 if (!this.proxyDrag) {
30345 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30348 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30350 dd.setHandleElId(this.header.id);
30351 dd.endDrag = this.endMove.createDelegate(this);
30352 dd.startDrag = this.startMove.createDelegate(this);
30353 dd.onDrag = this.onDrag.createDelegate(this);
30358 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30359 this.mask.enableDisplayMode("block");
30361 this.el.addClass("x-dlg-modal");
30364 this.shadow = new Roo.Shadow({
30365 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30366 offset : this.shadowOffset
30369 this.shadowOffset = 0;
30371 if(Roo.useShims && this.shim !== false){
30372 this.shim = this.el.createShim();
30373 this.shim.hide = this.hideAction;
30381 if (this.buttons) {
30382 var bts= this.buttons;
30384 Roo.each(bts, function(b) {
30393 * Fires when a key is pressed
30394 * @param {Roo.BasicDialog} this
30395 * @param {Roo.EventObject} e
30400 * Fires when this dialog is moved by the user.
30401 * @param {Roo.BasicDialog} this
30402 * @param {Number} x The new page X
30403 * @param {Number} y The new page Y
30408 * Fires when this dialog is resized by the user.
30409 * @param {Roo.BasicDialog} this
30410 * @param {Number} width The new width
30411 * @param {Number} height The new height
30415 * @event beforehide
30416 * Fires before this dialog is hidden.
30417 * @param {Roo.BasicDialog} this
30419 "beforehide" : true,
30422 * Fires when this dialog is hidden.
30423 * @param {Roo.BasicDialog} this
30427 * @event beforeshow
30428 * Fires before this dialog is shown.
30429 * @param {Roo.BasicDialog} this
30431 "beforeshow" : true,
30434 * Fires when this dialog is shown.
30435 * @param {Roo.BasicDialog} this
30439 el.on("keydown", this.onKeyDown, this);
30440 el.on("mousedown", this.toFront, this);
30441 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30443 Roo.DialogManager.register(this);
30444 Roo.BasicDialog.superclass.constructor.call(this);
30447 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30448 shadowOffset: Roo.isIE ? 6 : 5,
30451 minButtonWidth: 75,
30452 defaultButton: null,
30453 buttonAlign: "right",
30458 * Sets the dialog title text
30459 * @param {String} text The title text to display
30460 * @return {Roo.BasicDialog} this
30462 setTitle : function(text){
30463 this.header.update(text);
30468 closeClick : function(){
30473 collapseClick : function(){
30474 this[this.collapsed ? "expand" : "collapse"]();
30478 * Collapses the dialog to its minimized state (only the title bar is visible).
30479 * Equivalent to the user clicking the collapse dialog button.
30481 collapse : function(){
30482 if(!this.collapsed){
30483 this.collapsed = true;
30484 this.el.addClass("x-dlg-collapsed");
30485 this.restoreHeight = this.el.getHeight();
30486 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30491 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30492 * clicking the expand dialog button.
30494 expand : function(){
30495 if(this.collapsed){
30496 this.collapsed = false;
30497 this.el.removeClass("x-dlg-collapsed");
30498 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30503 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30504 * @return {Roo.TabPanel} The tabs component
30506 initTabs : function(){
30507 var tabs = this.getTabs();
30508 while(tabs.getTab(0)){
30511 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30513 tabs.addTab(Roo.id(dom), dom.title);
30521 beforeResize : function(){
30522 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30526 onResize : function(){
30527 this.refreshSize();
30528 this.syncBodyHeight();
30529 this.adjustAssets();
30531 this.fireEvent("resize", this, this.size.width, this.size.height);
30535 onKeyDown : function(e){
30536 if(this.isVisible()){
30537 this.fireEvent("keydown", this, e);
30542 * Resizes the dialog.
30543 * @param {Number} width
30544 * @param {Number} height
30545 * @return {Roo.BasicDialog} this
30547 resizeTo : function(width, height){
30548 this.el.setSize(width, height);
30549 this.size = {width: width, height: height};
30550 this.syncBodyHeight();
30551 if(this.fixedcenter){
30554 if(this.isVisible()){
30555 this.constrainXY();
30556 this.adjustAssets();
30558 this.fireEvent("resize", this, width, height);
30564 * Resizes the dialog to fit the specified content size.
30565 * @param {Number} width
30566 * @param {Number} height
30567 * @return {Roo.BasicDialog} this
30569 setContentSize : function(w, h){
30570 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30571 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30572 //if(!this.el.isBorderBox()){
30573 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30574 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30577 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30578 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30580 this.resizeTo(w, h);
30585 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30586 * executed in response to a particular key being pressed while the dialog is active.
30587 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30588 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30589 * @param {Function} fn The function to call
30590 * @param {Object} scope (optional) The scope of the function
30591 * @return {Roo.BasicDialog} this
30593 addKeyListener : function(key, fn, scope){
30594 var keyCode, shift, ctrl, alt;
30595 if(typeof key == "object" && !(key instanceof Array)){
30596 keyCode = key["key"];
30597 shift = key["shift"];
30598 ctrl = key["ctrl"];
30603 var handler = function(dlg, e){
30604 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30605 var k = e.getKey();
30606 if(keyCode instanceof Array){
30607 for(var i = 0, len = keyCode.length; i < len; i++){
30608 if(keyCode[i] == k){
30609 fn.call(scope || window, dlg, k, e);
30615 fn.call(scope || window, dlg, k, e);
30620 this.on("keydown", handler);
30625 * Returns the TabPanel component (creates it if it doesn't exist).
30626 * Note: If you wish to simply check for the existence of tabs without creating them,
30627 * check for a null 'tabs' property.
30628 * @return {Roo.TabPanel} The tabs component
30630 getTabs : function(){
30632 this.el.addClass("x-dlg-auto-tabs");
30633 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30634 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30640 * Adds a button to the footer section of the dialog.
30641 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30642 * object or a valid Roo.DomHelper element config
30643 * @param {Function} handler The function called when the button is clicked
30644 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30645 * @return {Roo.Button} The new button
30647 addButton : function(config, handler, scope){
30648 var dh = Roo.DomHelper;
30650 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30652 if(!this.btnContainer){
30653 var tb = this.footer.createChild({
30655 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30656 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30658 this.btnContainer = tb.firstChild.firstChild.firstChild;
30663 minWidth: this.minButtonWidth,
30666 if(typeof config == "string"){
30667 bconfig.text = config;
30670 bconfig.dhconfig = config;
30672 Roo.apply(bconfig, config);
30676 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30677 bconfig.position = Math.max(0, bconfig.position);
30678 fc = this.btnContainer.childNodes[bconfig.position];
30681 var btn = new Roo.Button(
30683 this.btnContainer.insertBefore(document.createElement("td"),fc)
30684 : this.btnContainer.appendChild(document.createElement("td")),
30685 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30688 this.syncBodyHeight();
30691 * Array of all the buttons that have been added to this dialog via addButton
30696 this.buttons.push(btn);
30701 * Sets the default button to be focused when the dialog is displayed.
30702 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30703 * @return {Roo.BasicDialog} this
30705 setDefaultButton : function(btn){
30706 this.defaultButton = btn;
30711 getHeaderFooterHeight : function(safe){
30714 height += this.header.getHeight();
30717 var fm = this.footer.getMargins();
30718 height += (this.footer.getHeight()+fm.top+fm.bottom);
30720 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30721 height += this.centerBg.getPadding("tb");
30726 syncBodyHeight : function()
30728 var bd = this.body, // the text
30729 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30731 var height = this.size.height - this.getHeaderFooterHeight(false);
30732 bd.setHeight(height-bd.getMargins("tb"));
30733 var hh = this.header.getHeight();
30734 var h = this.size.height-hh;
30737 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30738 bw.setHeight(h-cb.getPadding("tb"));
30740 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30741 bd.setWidth(bw.getWidth(true));
30743 this.tabs.syncHeight();
30745 this.tabs.el.repaint();
30751 * Restores the previous state of the dialog if Roo.state is configured.
30752 * @return {Roo.BasicDialog} this
30754 restoreState : function(){
30755 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30756 if(box && box.width){
30757 this.xy = [box.x, box.y];
30758 this.resizeTo(box.width, box.height);
30764 beforeShow : function(){
30766 if(this.fixedcenter){
30767 this.xy = this.el.getCenterXY(true);
30770 Roo.get(document.body).addClass("x-body-masked");
30771 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30774 this.constrainXY();
30778 animShow : function(){
30779 var b = Roo.get(this.animateTarget).getBox();
30780 this.proxy.setSize(b.width, b.height);
30781 this.proxy.setLocation(b.x, b.y);
30783 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30784 true, .35, this.showEl.createDelegate(this));
30788 * Shows the dialog.
30789 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30790 * @return {Roo.BasicDialog} this
30792 show : function(animateTarget){
30793 if (this.fireEvent("beforeshow", this) === false){
30796 if(this.syncHeightBeforeShow){
30797 this.syncBodyHeight();
30798 }else if(this.firstShow){
30799 this.firstShow = false;
30800 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30802 this.animateTarget = animateTarget || this.animateTarget;
30803 if(!this.el.isVisible()){
30805 if(this.animateTarget && Roo.get(this.animateTarget)){
30815 showEl : function(){
30817 this.el.setXY(this.xy);
30819 this.adjustAssets(true);
30822 // IE peekaboo bug - fix found by Dave Fenwick
30826 this.fireEvent("show", this);
30830 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30831 * dialog itself will receive focus.
30833 focus : function(){
30834 if(this.defaultButton){
30835 this.defaultButton.focus();
30837 this.focusEl.focus();
30842 constrainXY : function(){
30843 if(this.constraintoviewport !== false){
30844 if(!this.viewSize){
30845 if(this.container){
30846 var s = this.container.getSize();
30847 this.viewSize = [s.width, s.height];
30849 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30852 var s = Roo.get(this.container||document).getScroll();
30854 var x = this.xy[0], y = this.xy[1];
30855 var w = this.size.width, h = this.size.height;
30856 var vw = this.viewSize[0], vh = this.viewSize[1];
30857 // only move it if it needs it
30859 // first validate right/bottom
30860 if(x + w > vw+s.left){
30864 if(y + h > vh+s.top){
30868 // then make sure top/left isn't negative
30880 if(this.isVisible()){
30881 this.el.setLocation(x, y);
30882 this.adjustAssets();
30889 onDrag : function(){
30890 if(!this.proxyDrag){
30891 this.xy = this.el.getXY();
30892 this.adjustAssets();
30897 adjustAssets : function(doShow){
30898 var x = this.xy[0], y = this.xy[1];
30899 var w = this.size.width, h = this.size.height;
30900 if(doShow === true){
30902 this.shadow.show(this.el);
30908 if(this.shadow && this.shadow.isVisible()){
30909 this.shadow.show(this.el);
30911 if(this.shim && this.shim.isVisible()){
30912 this.shim.setBounds(x, y, w, h);
30917 adjustViewport : function(w, h){
30919 w = Roo.lib.Dom.getViewWidth();
30920 h = Roo.lib.Dom.getViewHeight();
30923 this.viewSize = [w, h];
30924 if(this.modal && this.mask.isVisible()){
30925 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30926 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30928 if(this.isVisible()){
30929 this.constrainXY();
30934 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30935 * shadow, proxy, mask, etc.) Also removes all event listeners.
30936 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30938 destroy : function(removeEl){
30939 if(this.isVisible()){
30940 this.animateTarget = null;
30943 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30945 this.tabs.destroy(removeEl);
30958 for(var i = 0, len = this.buttons.length; i < len; i++){
30959 this.buttons[i].destroy();
30962 this.el.removeAllListeners();
30963 if(removeEl === true){
30964 this.el.update("");
30967 Roo.DialogManager.unregister(this);
30971 startMove : function(){
30972 if(this.proxyDrag){
30975 if(this.constraintoviewport !== false){
30976 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30981 endMove : function(){
30982 if(!this.proxyDrag){
30983 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30985 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30988 this.refreshSize();
30989 this.adjustAssets();
30991 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30995 * Brings this dialog to the front of any other visible dialogs
30996 * @return {Roo.BasicDialog} this
30998 toFront : function(){
30999 Roo.DialogManager.bringToFront(this);
31004 * Sends this dialog to the back (under) of any other visible dialogs
31005 * @return {Roo.BasicDialog} this
31007 toBack : function(){
31008 Roo.DialogManager.sendToBack(this);
31013 * Centers this dialog in the viewport
31014 * @return {Roo.BasicDialog} this
31016 center : function(){
31017 var xy = this.el.getCenterXY(true);
31018 this.moveTo(xy[0], xy[1]);
31023 * Moves the dialog's top-left corner to the specified point
31024 * @param {Number} x
31025 * @param {Number} y
31026 * @return {Roo.BasicDialog} this
31028 moveTo : function(x, y){
31030 if(this.isVisible()){
31031 this.el.setXY(this.xy);
31032 this.adjustAssets();
31038 * Aligns the dialog to the specified element
31039 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31040 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31041 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31042 * @return {Roo.BasicDialog} this
31044 alignTo : function(element, position, offsets){
31045 this.xy = this.el.getAlignToXY(element, position, offsets);
31046 if(this.isVisible()){
31047 this.el.setXY(this.xy);
31048 this.adjustAssets();
31054 * Anchors an element to another element and realigns it when the window is resized.
31055 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31056 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31057 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31058 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31059 * is a number, it is used as the buffer delay (defaults to 50ms).
31060 * @return {Roo.BasicDialog} this
31062 anchorTo : function(el, alignment, offsets, monitorScroll){
31063 var action = function(){
31064 this.alignTo(el, alignment, offsets);
31066 Roo.EventManager.onWindowResize(action, this);
31067 var tm = typeof monitorScroll;
31068 if(tm != 'undefined'){
31069 Roo.EventManager.on(window, 'scroll', action, this,
31070 {buffer: tm == 'number' ? monitorScroll : 50});
31077 * Returns true if the dialog is visible
31078 * @return {Boolean}
31080 isVisible : function(){
31081 return this.el.isVisible();
31085 animHide : function(callback){
31086 var b = Roo.get(this.animateTarget).getBox();
31088 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31090 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31091 this.hideEl.createDelegate(this, [callback]));
31095 * Hides the dialog.
31096 * @param {Function} callback (optional) Function to call when the dialog is hidden
31097 * @return {Roo.BasicDialog} this
31099 hide : function(callback){
31100 if (this.fireEvent("beforehide", this) === false){
31104 this.shadow.hide();
31109 // sometimes animateTarget seems to get set.. causing problems...
31110 // this just double checks..
31111 if(this.animateTarget && Roo.get(this.animateTarget)) {
31112 this.animHide(callback);
31115 this.hideEl(callback);
31121 hideEl : function(callback){
31125 Roo.get(document.body).removeClass("x-body-masked");
31127 this.fireEvent("hide", this);
31128 if(typeof callback == "function"){
31134 hideAction : function(){
31135 this.setLeft("-10000px");
31136 this.setTop("-10000px");
31137 this.setStyle("visibility", "hidden");
31141 refreshSize : function(){
31142 this.size = this.el.getSize();
31143 this.xy = this.el.getXY();
31144 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31148 // z-index is managed by the DialogManager and may be overwritten at any time
31149 setZIndex : function(index){
31151 this.mask.setStyle("z-index", index);
31154 this.shim.setStyle("z-index", ++index);
31157 this.shadow.setZIndex(++index);
31159 this.el.setStyle("z-index", ++index);
31161 this.proxy.setStyle("z-index", ++index);
31164 this.resizer.proxy.setStyle("z-index", ++index);
31167 this.lastZIndex = index;
31171 * Returns the element for this dialog
31172 * @return {Roo.Element} The underlying dialog Element
31174 getEl : function(){
31180 * @class Roo.DialogManager
31181 * Provides global access to BasicDialogs that have been created and
31182 * support for z-indexing (layering) multiple open dialogs.
31184 Roo.DialogManager = function(){
31186 var accessList = [];
31190 var sortDialogs = function(d1, d2){
31191 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31195 var orderDialogs = function(){
31196 accessList.sort(sortDialogs);
31197 var seed = Roo.DialogManager.zseed;
31198 for(var i = 0, len = accessList.length; i < len; i++){
31199 var dlg = accessList[i];
31201 dlg.setZIndex(seed + (i*10));
31208 * The starting z-index for BasicDialogs (defaults to 9000)
31209 * @type Number The z-index value
31214 register : function(dlg){
31215 list[dlg.id] = dlg;
31216 accessList.push(dlg);
31220 unregister : function(dlg){
31221 delete list[dlg.id];
31224 if(!accessList.indexOf){
31225 for( i = 0, len = accessList.length; i < len; i++){
31226 if(accessList[i] == dlg){
31227 accessList.splice(i, 1);
31232 i = accessList.indexOf(dlg);
31234 accessList.splice(i, 1);
31240 * Gets a registered dialog by id
31241 * @param {String/Object} id The id of the dialog or a dialog
31242 * @return {Roo.BasicDialog} this
31244 get : function(id){
31245 return typeof id == "object" ? id : list[id];
31249 * Brings the specified dialog to the front
31250 * @param {String/Object} dlg The id of the dialog or a dialog
31251 * @return {Roo.BasicDialog} this
31253 bringToFront : function(dlg){
31254 dlg = this.get(dlg);
31257 dlg._lastAccess = new Date().getTime();
31264 * Sends the specified dialog to the back
31265 * @param {String/Object} dlg The id of the dialog or a dialog
31266 * @return {Roo.BasicDialog} this
31268 sendToBack : function(dlg){
31269 dlg = this.get(dlg);
31270 dlg._lastAccess = -(new Date().getTime());
31276 * Hides all dialogs
31278 hideAll : function(){
31279 for(var id in list){
31280 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31289 * @class Roo.LayoutDialog
31290 * @extends Roo.BasicDialog
31291 * Dialog which provides adjustments for working with a layout in a Dialog.
31292 * Add your necessary layout config options to the dialog's config.<br>
31293 * Example usage (including a nested layout):
31296 dialog = new Roo.LayoutDialog("download-dlg", {
31305 // layout config merges with the dialog config
31307 tabPosition: "top",
31308 alwaysShowTabs: true
31311 dialog.addKeyListener(27, dialog.hide, dialog);
31312 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31313 dialog.addButton("Build It!", this.getDownload, this);
31315 // we can even add nested layouts
31316 var innerLayout = new Roo.BorderLayout("dl-inner", {
31326 innerLayout.beginUpdate();
31327 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31328 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31329 innerLayout.endUpdate(true);
31331 var layout = dialog.getLayout();
31332 layout.beginUpdate();
31333 layout.add("center", new Roo.ContentPanel("standard-panel",
31334 {title: "Download the Source", fitToFrame:true}));
31335 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31336 {title: "Build your own roo.js"}));
31337 layout.getRegion("center").showPanel(sp);
31338 layout.endUpdate();
31342 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31343 * @param {Object} config configuration options
31345 Roo.LayoutDialog = function(el, cfg){
31348 if (typeof(cfg) == 'undefined') {
31349 config = Roo.apply({}, el);
31350 // not sure why we use documentElement here.. - it should always be body.
31351 // IE7 borks horribly if we use documentElement.
31352 // webkit also does not like documentElement - it creates a body element...
31353 el = Roo.get( document.body || document.documentElement ).createChild();
31354 //config.autoCreate = true;
31358 config.autoTabs = false;
31359 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31360 this.body.setStyle({overflow:"hidden", position:"relative"});
31361 this.layout = new Roo.BorderLayout(this.body.dom, config);
31362 this.layout.monitorWindowResize = false;
31363 this.el.addClass("x-dlg-auto-layout");
31364 // fix case when center region overwrites center function
31365 this.center = Roo.BasicDialog.prototype.center;
31366 this.on("show", this.layout.layout, this.layout, true);
31367 if (config.items) {
31368 var xitems = config.items;
31369 delete config.items;
31370 Roo.each(xitems, this.addxtype, this);
31375 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31377 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31380 endUpdate : function(){
31381 this.layout.endUpdate();
31385 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31388 beginUpdate : function(){
31389 this.layout.beginUpdate();
31393 * Get the BorderLayout for this dialog
31394 * @return {Roo.BorderLayout}
31396 getLayout : function(){
31397 return this.layout;
31400 showEl : function(){
31401 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31403 this.layout.layout();
31408 // Use the syncHeightBeforeShow config option to control this automatically
31409 syncBodyHeight : function(){
31410 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31411 if(this.layout){this.layout.layout();}
31415 * Add an xtype element (actually adds to the layout.)
31416 * @return {Object} xdata xtype object data.
31419 addxtype : function(c) {
31420 return this.layout.addxtype(c);
31424 * Ext JS Library 1.1.1
31425 * Copyright(c) 2006-2007, Ext JS, LLC.
31427 * Originally Released Under LGPL - original licence link has changed is not relivant.
31430 * <script type="text/javascript">
31434 * @class Roo.MessageBox
31435 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31439 Roo.Msg.alert('Status', 'Changes saved successfully.');
31441 // Prompt for user data:
31442 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31444 // process text value...
31448 // Show a dialog using config options:
31450 title:'Save Changes?',
31451 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31452 buttons: Roo.Msg.YESNOCANCEL,
31459 Roo.MessageBox = function(){
31460 var dlg, opt, mask, waitTimer;
31461 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31462 var buttons, activeTextEl, bwidth;
31465 var handleButton = function(button){
31467 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31471 var handleHide = function(){
31472 if(opt && opt.cls){
31473 dlg.el.removeClass(opt.cls);
31476 Roo.TaskMgr.stop(waitTimer);
31482 var updateButtons = function(b){
31485 buttons["ok"].hide();
31486 buttons["cancel"].hide();
31487 buttons["yes"].hide();
31488 buttons["no"].hide();
31489 dlg.footer.dom.style.display = 'none';
31492 dlg.footer.dom.style.display = '';
31493 for(var k in buttons){
31494 if(typeof buttons[k] != "function"){
31497 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31498 width += buttons[k].el.getWidth()+15;
31508 var handleEsc = function(d, k, e){
31509 if(opt && opt.closable !== false){
31519 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31520 * @return {Roo.BasicDialog} The BasicDialog element
31522 getDialog : function(){
31524 dlg = new Roo.BasicDialog("x-msg-box", {
31529 constraintoviewport:false,
31531 collapsible : false,
31534 width:400, height:100,
31535 buttonAlign:"center",
31536 closeClick : function(){
31537 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31538 handleButton("no");
31540 handleButton("cancel");
31544 dlg.on("hide", handleHide);
31546 dlg.addKeyListener(27, handleEsc);
31548 var bt = this.buttonText;
31549 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31550 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31551 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31552 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31553 bodyEl = dlg.body.createChild({
31555 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>'
31557 msgEl = bodyEl.dom.firstChild;
31558 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31559 textboxEl.enableDisplayMode();
31560 textboxEl.addKeyListener([10,13], function(){
31561 if(dlg.isVisible() && opt && opt.buttons){
31562 if(opt.buttons.ok){
31563 handleButton("ok");
31564 }else if(opt.buttons.yes){
31565 handleButton("yes");
31569 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31570 textareaEl.enableDisplayMode();
31571 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31572 progressEl.enableDisplayMode();
31573 var pf = progressEl.dom.firstChild;
31575 pp = Roo.get(pf.firstChild);
31576 pp.setHeight(pf.offsetHeight);
31584 * Updates the message box body text
31585 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31586 * the XHTML-compliant non-breaking space character '&#160;')
31587 * @return {Roo.MessageBox} This message box
31589 updateText : function(text){
31590 if(!dlg.isVisible() && !opt.width){
31591 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31593 msgEl.innerHTML = text || ' ';
31595 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31596 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31598 Math.min(opt.width || cw , this.maxWidth),
31599 Math.max(opt.minWidth || this.minWidth, bwidth)
31602 activeTextEl.setWidth(w);
31604 if(dlg.isVisible()){
31605 dlg.fixedcenter = false;
31607 // to big, make it scroll. = But as usual stupid IE does not support
31610 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31611 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31612 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31614 bodyEl.dom.style.height = '';
31615 bodyEl.dom.style.overflowY = '';
31618 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31620 bodyEl.dom.style.overflowX = '';
31623 dlg.setContentSize(w, bodyEl.getHeight());
31624 if(dlg.isVisible()){
31625 dlg.fixedcenter = true;
31631 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31632 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31633 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31634 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31635 * @return {Roo.MessageBox} This message box
31637 updateProgress : function(value, text){
31639 this.updateText(text);
31641 if (pp) { // weird bug on my firefox - for some reason this is not defined
31642 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31648 * Returns true if the message box is currently displayed
31649 * @return {Boolean} True if the message box is visible, else false
31651 isVisible : function(){
31652 return dlg && dlg.isVisible();
31656 * Hides the message box if it is displayed
31659 if(this.isVisible()){
31665 * Displays a new message box, or reinitializes an existing message box, based on the config options
31666 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31667 * The following config object properties are supported:
31669 Property Type Description
31670 ---------- --------------- ------------------------------------------------------------------------------------
31671 animEl String/Element An id or Element from which the message box should animate as it opens and
31672 closes (defaults to undefined)
31673 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31674 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31675 closable Boolean False to hide the top-right close button (defaults to true). Note that
31676 progress and wait dialogs will ignore this property and always hide the
31677 close button as they can only be closed programmatically.
31678 cls String A custom CSS class to apply to the message box element
31679 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31680 displayed (defaults to 75)
31681 fn Function A callback function to execute after closing the dialog. The arguments to the
31682 function will be btn (the name of the button that was clicked, if applicable,
31683 e.g. "ok"), and text (the value of the active text field, if applicable).
31684 Progress and wait dialogs will ignore this option since they do not respond to
31685 user actions and can only be closed programmatically, so any required function
31686 should be called by the same code after it closes the dialog.
31687 icon String A CSS class that provides a background image to be used as an icon for
31688 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31689 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31690 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31691 modal Boolean False to allow user interaction with the page while the message box is
31692 displayed (defaults to true)
31693 msg String A string that will replace the existing message box body text (defaults
31694 to the XHTML-compliant non-breaking space character ' ')
31695 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31696 progress Boolean True to display a progress bar (defaults to false)
31697 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31698 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31699 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31700 title String The title text
31701 value String The string value to set into the active textbox element if displayed
31702 wait Boolean True to display a progress bar (defaults to false)
31703 width Number The width of the dialog in pixels
31710 msg: 'Please enter your address:',
31712 buttons: Roo.MessageBox.OKCANCEL,
31715 animEl: 'addAddressBtn'
31718 * @param {Object} config Configuration options
31719 * @return {Roo.MessageBox} This message box
31721 show : function(options)
31724 // this causes nightmares if you show one dialog after another
31725 // especially on callbacks..
31727 if(this.isVisible()){
31730 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31731 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31732 Roo.log("New Dialog Message:" + options.msg )
31733 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31734 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31737 var d = this.getDialog();
31739 d.setTitle(opt.title || " ");
31740 d.close.setDisplayed(opt.closable !== false);
31741 activeTextEl = textboxEl;
31742 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31747 textareaEl.setHeight(typeof opt.multiline == "number" ?
31748 opt.multiline : this.defaultTextHeight);
31749 activeTextEl = textareaEl;
31758 progressEl.setDisplayed(opt.progress === true);
31759 this.updateProgress(0);
31760 activeTextEl.dom.value = opt.value || "";
31762 dlg.setDefaultButton(activeTextEl);
31764 var bs = opt.buttons;
31767 db = buttons["ok"];
31768 }else if(bs && bs.yes){
31769 db = buttons["yes"];
31771 dlg.setDefaultButton(db);
31773 bwidth = updateButtons(opt.buttons);
31774 this.updateText(opt.msg);
31776 d.el.addClass(opt.cls);
31778 d.proxyDrag = opt.proxyDrag === true;
31779 d.modal = opt.modal !== false;
31780 d.mask = opt.modal !== false ? mask : false;
31781 if(!d.isVisible()){
31782 // force it to the end of the z-index stack so it gets a cursor in FF
31783 document.body.appendChild(dlg.el.dom);
31784 d.animateTarget = null;
31785 d.show(options.animEl);
31791 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31792 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31793 * and closing the message box when the process is complete.
31794 * @param {String} title The title bar text
31795 * @param {String} msg The message box body text
31796 * @return {Roo.MessageBox} This message box
31798 progress : function(title, msg){
31805 minWidth: this.minProgressWidth,
31812 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31813 * If a callback function is passed it will be called after the user clicks the button, and the
31814 * id of the button that was clicked will be passed as the only parameter to the callback
31815 * (could also be the top-right close button).
31816 * @param {String} title The title bar text
31817 * @param {String} msg The message box body text
31818 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31819 * @param {Object} scope (optional) The scope of the callback function
31820 * @return {Roo.MessageBox} This message box
31822 alert : function(title, msg, fn, scope){
31835 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31836 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31837 * You are responsible for closing the message box when the process is complete.
31838 * @param {String} msg The message box body text
31839 * @param {String} title (optional) The title bar text
31840 * @return {Roo.MessageBox} This message box
31842 wait : function(msg, title){
31853 waitTimer = Roo.TaskMgr.start({
31855 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31863 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31864 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31865 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31866 * @param {String} title The title bar text
31867 * @param {String} msg The message box body text
31868 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31869 * @param {Object} scope (optional) The scope of the callback function
31870 * @return {Roo.MessageBox} This message box
31872 confirm : function(title, msg, fn, scope){
31876 buttons: this.YESNO,
31885 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31886 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31887 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31888 * (could also be the top-right close button) and the text that was entered will be passed as the two
31889 * parameters to the callback.
31890 * @param {String} title The title bar text
31891 * @param {String} msg The message box body text
31892 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31893 * @param {Object} scope (optional) The scope of the callback function
31894 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31895 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31896 * @return {Roo.MessageBox} This message box
31898 prompt : function(title, msg, fn, scope, multiline){
31902 buttons: this.OKCANCEL,
31907 multiline: multiline,
31914 * Button config that displays a single OK button
31919 * Button config that displays Yes and No buttons
31922 YESNO : {yes:true, no:true},
31924 * Button config that displays OK and Cancel buttons
31927 OKCANCEL : {ok:true, cancel:true},
31929 * Button config that displays Yes, No and Cancel buttons
31932 YESNOCANCEL : {yes:true, no:true, cancel:true},
31935 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31938 defaultTextHeight : 75,
31940 * The maximum width in pixels of the message box (defaults to 600)
31945 * The minimum width in pixels of the message box (defaults to 100)
31950 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31951 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31954 minProgressWidth : 250,
31956 * An object containing the default button text strings that can be overriden for localized language support.
31957 * Supported properties are: ok, cancel, yes and no.
31958 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31971 * Shorthand for {@link Roo.MessageBox}
31973 Roo.Msg = Roo.MessageBox;/*
31975 * Ext JS Library 1.1.1
31976 * Copyright(c) 2006-2007, Ext JS, LLC.
31978 * Originally Released Under LGPL - original licence link has changed is not relivant.
31981 * <script type="text/javascript">
31984 * @class Roo.QuickTips
31985 * Provides attractive and customizable tooltips for any element.
31988 Roo.QuickTips = function(){
31989 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31990 var ce, bd, xy, dd;
31991 var visible = false, disabled = true, inited = false;
31992 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31994 var onOver = function(e){
31998 var t = e.getTarget();
31999 if(!t || t.nodeType !== 1 || t == document || t == document.body){
32002 if(ce && t == ce.el){
32003 clearTimeout(hideProc);
32006 if(t && tagEls[t.id]){
32007 tagEls[t.id].el = t;
32008 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32011 var ttp, et = Roo.fly(t);
32012 var ns = cfg.namespace;
32013 if(tm.interceptTitles && t.title){
32016 t.removeAttribute("title");
32017 e.preventDefault();
32019 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32022 showProc = show.defer(tm.showDelay, tm, [{
32025 width: et.getAttributeNS(ns, cfg.width),
32026 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32027 title: et.getAttributeNS(ns, cfg.title),
32028 cls: et.getAttributeNS(ns, cfg.cls)
32033 var onOut = function(e){
32034 clearTimeout(showProc);
32035 var t = e.getTarget();
32036 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32037 hideProc = setTimeout(hide, tm.hideDelay);
32041 var onMove = function(e){
32047 if(tm.trackMouse && ce){
32052 var onDown = function(e){
32053 clearTimeout(showProc);
32054 clearTimeout(hideProc);
32056 if(tm.hideOnClick){
32059 tm.enable.defer(100, tm);
32064 var getPad = function(){
32065 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32068 var show = function(o){
32072 clearTimeout(dismissProc);
32074 if(removeCls){ // in case manually hidden
32075 el.removeClass(removeCls);
32079 el.addClass(ce.cls);
32080 removeCls = ce.cls;
32083 tipTitle.update(ce.title);
32086 tipTitle.update('');
32089 el.dom.style.width = tm.maxWidth+'px';
32090 //tipBody.dom.style.width = '';
32091 tipBodyText.update(o.text);
32092 var p = getPad(), w = ce.width;
32094 var td = tipBodyText.dom;
32095 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32096 if(aw > tm.maxWidth){
32098 }else if(aw < tm.minWidth){
32104 //tipBody.setWidth(w);
32105 el.setWidth(parseInt(w, 10) + p);
32106 if(ce.autoHide === false){
32107 close.setDisplayed(true);
32112 close.setDisplayed(false);
32118 el.avoidY = xy[1]-18;
32123 el.setStyle("visibility", "visible");
32124 el.fadeIn({callback: afterShow});
32130 var afterShow = function(){
32134 if(tm.autoDismiss && ce.autoHide !== false){
32135 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32140 var hide = function(noanim){
32141 clearTimeout(dismissProc);
32142 clearTimeout(hideProc);
32144 if(el.isVisible()){
32146 if(noanim !== true && tm.animate){
32147 el.fadeOut({callback: afterHide});
32154 var afterHide = function(){
32157 el.removeClass(removeCls);
32164 * @cfg {Number} minWidth
32165 * The minimum width of the quick tip (defaults to 40)
32169 * @cfg {Number} maxWidth
32170 * The maximum width of the quick tip (defaults to 300)
32174 * @cfg {Boolean} interceptTitles
32175 * True to automatically use the element's DOM title value if available (defaults to false)
32177 interceptTitles : false,
32179 * @cfg {Boolean} trackMouse
32180 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32182 trackMouse : false,
32184 * @cfg {Boolean} hideOnClick
32185 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32187 hideOnClick : true,
32189 * @cfg {Number} showDelay
32190 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32194 * @cfg {Number} hideDelay
32195 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32199 * @cfg {Boolean} autoHide
32200 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32201 * Used in conjunction with hideDelay.
32206 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32207 * (defaults to true). Used in conjunction with autoDismissDelay.
32209 autoDismiss : true,
32212 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32214 autoDismissDelay : 5000,
32216 * @cfg {Boolean} animate
32217 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32222 * @cfg {String} title
32223 * Title text to display (defaults to ''). This can be any valid HTML markup.
32227 * @cfg {String} text
32228 * Body text to display (defaults to ''). This can be any valid HTML markup.
32232 * @cfg {String} cls
32233 * A CSS class to apply to the base quick tip element (defaults to '').
32237 * @cfg {Number} width
32238 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32239 * minWidth or maxWidth.
32244 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32245 * or display QuickTips in a page.
32248 tm = Roo.QuickTips;
32249 cfg = tm.tagConfig;
32251 if(!Roo.isReady){ // allow calling of init() before onReady
32252 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32255 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32256 el.fxDefaults = {stopFx: true};
32257 // maximum custom styling
32258 //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>');
32259 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>');
32260 tipTitle = el.child('h3');
32261 tipTitle.enableDisplayMode("block");
32262 tipBody = el.child('div.x-tip-bd');
32263 tipBodyText = el.child('div.x-tip-bd-inner');
32264 //bdLeft = el.child('div.x-tip-bd-left');
32265 //bdRight = el.child('div.x-tip-bd-right');
32266 close = el.child('div.x-tip-close');
32267 close.enableDisplayMode("block");
32268 close.on("click", hide);
32269 var d = Roo.get(document);
32270 d.on("mousedown", onDown);
32271 d.on("mouseover", onOver);
32272 d.on("mouseout", onOut);
32273 d.on("mousemove", onMove);
32274 esc = d.addKeyListener(27, hide);
32277 dd = el.initDD("default", null, {
32278 onDrag : function(){
32282 dd.setHandleElId(tipTitle.id);
32291 * Configures a new quick tip instance and assigns it to a target element. The following config options
32294 Property Type Description
32295 ---------- --------------------- ------------------------------------------------------------------------
32296 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32298 * @param {Object} config The config object
32300 register : function(config){
32301 var cs = config instanceof Array ? config : arguments;
32302 for(var i = 0, len = cs.length; i < len; i++) {
32304 var target = c.target;
32306 if(target instanceof Array){
32307 for(var j = 0, jlen = target.length; j < jlen; j++){
32308 tagEls[target[j]] = c;
32311 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32318 * Removes this quick tip from its element and destroys it.
32319 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32321 unregister : function(el){
32322 delete tagEls[Roo.id(el)];
32326 * Enable this quick tip.
32328 enable : function(){
32329 if(inited && disabled){
32331 if(locks.length < 1){
32338 * Disable this quick tip.
32340 disable : function(){
32342 clearTimeout(showProc);
32343 clearTimeout(hideProc);
32344 clearTimeout(dismissProc);
32352 * Returns true if the quick tip is enabled, else false.
32354 isEnabled : function(){
32361 attribute : "qtip",
32371 // backwards compat
32372 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32374 * Ext JS Library 1.1.1
32375 * Copyright(c) 2006-2007, Ext JS, LLC.
32377 * Originally Released Under LGPL - original licence link has changed is not relivant.
32380 * <script type="text/javascript">
32385 * @class Roo.tree.TreePanel
32386 * @extends Roo.data.Tree
32388 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32389 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32390 * @cfg {Boolean} enableDD true to enable drag and drop
32391 * @cfg {Boolean} enableDrag true to enable just drag
32392 * @cfg {Boolean} enableDrop true to enable just drop
32393 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32394 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32395 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32396 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32397 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32398 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32399 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32400 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32401 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32402 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32403 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32404 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32405 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32406 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32407 * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / 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>
32408 * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / 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>
32411 * @param {String/HTMLElement/Element} el The container element
32412 * @param {Object} config
32414 Roo.tree.TreePanel = function(el, config){
32416 var loader = false;
32418 root = config.root;
32419 delete config.root;
32421 if (config.loader) {
32422 loader = config.loader;
32423 delete config.loader;
32426 Roo.apply(this, config);
32427 Roo.tree.TreePanel.superclass.constructor.call(this);
32428 this.el = Roo.get(el);
32429 this.el.addClass('x-tree');
32430 //console.log(root);
32432 this.setRootNode( Roo.factory(root, Roo.tree));
32435 this.loader = Roo.factory(loader, Roo.tree);
32438 * Read-only. The id of the container element becomes this TreePanel's id.
32440 this.id = this.el.id;
32443 * @event beforeload
32444 * Fires before a node is loaded, return false to cancel
32445 * @param {Node} node The node being loaded
32447 "beforeload" : true,
32450 * Fires when a node is loaded
32451 * @param {Node} node The node that was loaded
32455 * @event textchange
32456 * Fires when the text for a node is changed
32457 * @param {Node} node The node
32458 * @param {String} text The new text
32459 * @param {String} oldText The old text
32461 "textchange" : true,
32463 * @event beforeexpand
32464 * Fires before a node is expanded, return false to cancel.
32465 * @param {Node} node The node
32466 * @param {Boolean} deep
32467 * @param {Boolean} anim
32469 "beforeexpand" : true,
32471 * @event beforecollapse
32472 * Fires before a node is collapsed, return false to cancel.
32473 * @param {Node} node The node
32474 * @param {Boolean} deep
32475 * @param {Boolean} anim
32477 "beforecollapse" : true,
32480 * Fires when a node is expanded
32481 * @param {Node} node The node
32485 * @event disabledchange
32486 * Fires when the disabled status of a node changes
32487 * @param {Node} node The node
32488 * @param {Boolean} disabled
32490 "disabledchange" : true,
32493 * Fires when a node is collapsed
32494 * @param {Node} node The node
32498 * @event beforeclick
32499 * Fires before click processing on a node. Return false to cancel the default action.
32500 * @param {Node} node The node
32501 * @param {Roo.EventObject} e The event object
32503 "beforeclick":true,
32505 * @event checkchange
32506 * Fires when a node with a checkbox's checked property changes
32507 * @param {Node} this This node
32508 * @param {Boolean} checked
32510 "checkchange":true,
32513 * Fires when a node is clicked
32514 * @param {Node} node The node
32515 * @param {Roo.EventObject} e The event object
32520 * Fires when a node is double clicked
32521 * @param {Node} node The node
32522 * @param {Roo.EventObject} e The event object
32526 * @event contextmenu
32527 * Fires when a node is right clicked
32528 * @param {Node} node The node
32529 * @param {Roo.EventObject} e The event object
32531 "contextmenu":true,
32533 * @event beforechildrenrendered
32534 * Fires right before the child nodes for a node are rendered
32535 * @param {Node} node The node
32537 "beforechildrenrendered":true,
32540 * Fires when a node starts being dragged
32541 * @param {Roo.tree.TreePanel} this
32542 * @param {Roo.tree.TreeNode} node
32543 * @param {event} e The raw browser event
32545 "startdrag" : true,
32548 * Fires when a drag operation is complete
32549 * @param {Roo.tree.TreePanel} this
32550 * @param {Roo.tree.TreeNode} node
32551 * @param {event} e The raw browser event
32556 * Fires when a dragged node is dropped on a valid DD target
32557 * @param {Roo.tree.TreePanel} this
32558 * @param {Roo.tree.TreeNode} node
32559 * @param {DD} dd The dd it was dropped on
32560 * @param {event} e The raw browser event
32564 * @event beforenodedrop
32565 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32566 * passed to handlers has the following properties:<br />
32567 * <ul style="padding:5px;padding-left:16px;">
32568 * <li>tree - The TreePanel</li>
32569 * <li>target - The node being targeted for the drop</li>
32570 * <li>data - The drag data from the drag source</li>
32571 * <li>point - The point of the drop - append, above or below</li>
32572 * <li>source - The drag source</li>
32573 * <li>rawEvent - Raw mouse event</li>
32574 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32575 * to be inserted by setting them on this object.</li>
32576 * <li>cancel - Set this to true to cancel the drop.</li>
32578 * @param {Object} dropEvent
32580 "beforenodedrop" : true,
32583 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32584 * passed to handlers has the following properties:<br />
32585 * <ul style="padding:5px;padding-left:16px;">
32586 * <li>tree - The TreePanel</li>
32587 * <li>target - The node being targeted for the drop</li>
32588 * <li>data - The drag data from the drag source</li>
32589 * <li>point - The point of the drop - append, above or below</li>
32590 * <li>source - The drag source</li>
32591 * <li>rawEvent - Raw mouse event</li>
32592 * <li>dropNode - Dropped node(s).</li>
32594 * @param {Object} dropEvent
32598 * @event nodedragover
32599 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32600 * passed to handlers has the following properties:<br />
32601 * <ul style="padding:5px;padding-left:16px;">
32602 * <li>tree - The TreePanel</li>
32603 * <li>target - The node being targeted for the drop</li>
32604 * <li>data - The drag data from the drag source</li>
32605 * <li>point - The point of the drop - append, above or below</li>
32606 * <li>source - The drag source</li>
32607 * <li>rawEvent - Raw mouse event</li>
32608 * <li>dropNode - Drop node(s) provided by the source.</li>
32609 * <li>cancel - Set this to true to signal drop not allowed.</li>
32611 * @param {Object} dragOverEvent
32613 "nodedragover" : true
32616 if(this.singleExpand){
32617 this.on("beforeexpand", this.restrictExpand, this);
32620 this.editor.tree = this;
32621 this.editor = Roo.factory(this.editor, Roo.tree);
32624 if (this.selModel) {
32625 this.selModel = Roo.factory(this.selModel, Roo.tree);
32629 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32630 rootVisible : true,
32631 animate: Roo.enableFx,
32634 hlDrop : Roo.enableFx,
32638 rendererTip: false,
32640 restrictExpand : function(node){
32641 var p = node.parentNode;
32643 if(p.expandedChild && p.expandedChild.parentNode == p){
32644 p.expandedChild.collapse();
32646 p.expandedChild = node;
32650 // private override
32651 setRootNode : function(node){
32652 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32653 if(!this.rootVisible){
32654 node.ui = new Roo.tree.RootTreeNodeUI(node);
32660 * Returns the container element for this TreePanel
32662 getEl : function(){
32667 * Returns the default TreeLoader for this TreePanel
32669 getLoader : function(){
32670 return this.loader;
32676 expandAll : function(){
32677 this.root.expand(true);
32681 * Collapse all nodes
32683 collapseAll : function(){
32684 this.root.collapse(true);
32688 * Returns the selection model used by this TreePanel
32690 getSelectionModel : function(){
32691 if(!this.selModel){
32692 this.selModel = new Roo.tree.DefaultSelectionModel();
32694 return this.selModel;
32698 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32699 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32700 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32703 getChecked : function(a, startNode){
32704 startNode = startNode || this.root;
32706 var f = function(){
32707 if(this.attributes.checked){
32708 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32711 startNode.cascade(f);
32716 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32717 * @param {String} path
32718 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32719 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32720 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32722 expandPath : function(path, attr, callback){
32723 attr = attr || "id";
32724 var keys = path.split(this.pathSeparator);
32725 var curNode = this.root;
32726 if(curNode.attributes[attr] != keys[1]){ // invalid root
32728 callback(false, null);
32733 var f = function(){
32734 if(++index == keys.length){
32736 callback(true, curNode);
32740 var c = curNode.findChild(attr, keys[index]);
32743 callback(false, curNode);
32748 c.expand(false, false, f);
32750 curNode.expand(false, false, f);
32754 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32755 * @param {String} path
32756 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32757 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32758 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32760 selectPath : function(path, attr, callback){
32761 attr = attr || "id";
32762 var keys = path.split(this.pathSeparator);
32763 var v = keys.pop();
32764 if(keys.length > 0){
32765 var f = function(success, node){
32766 if(success && node){
32767 var n = node.findChild(attr, v);
32773 }else if(callback){
32774 callback(false, n);
32778 callback(false, n);
32782 this.expandPath(keys.join(this.pathSeparator), attr, f);
32784 this.root.select();
32786 callback(true, this.root);
32791 getTreeEl : function(){
32796 * Trigger rendering of this TreePanel
32798 render : function(){
32799 if (this.innerCt) {
32800 return this; // stop it rendering more than once!!
32803 this.innerCt = this.el.createChild({tag:"ul",
32804 cls:"x-tree-root-ct " +
32805 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32807 if(this.containerScroll){
32808 Roo.dd.ScrollManager.register(this.el);
32810 if((this.enableDD || this.enableDrop) && !this.dropZone){
32812 * The dropZone used by this tree if drop is enabled
32813 * @type Roo.tree.TreeDropZone
32815 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32816 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32819 if((this.enableDD || this.enableDrag) && !this.dragZone){
32821 * The dragZone used by this tree if drag is enabled
32822 * @type Roo.tree.TreeDragZone
32824 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32825 ddGroup: this.ddGroup || "TreeDD",
32826 scroll: this.ddScroll
32829 this.getSelectionModel().init(this);
32831 Roo.log("ROOT not set in tree");
32834 this.root.render();
32835 if(!this.rootVisible){
32836 this.root.renderChildren();
32842 * Ext JS Library 1.1.1
32843 * Copyright(c) 2006-2007, Ext JS, LLC.
32845 * Originally Released Under LGPL - original licence link has changed is not relivant.
32848 * <script type="text/javascript">
32853 * @class Roo.tree.DefaultSelectionModel
32854 * @extends Roo.util.Observable
32855 * The default single selection for a TreePanel.
32856 * @param {Object} cfg Configuration
32858 Roo.tree.DefaultSelectionModel = function(cfg){
32859 this.selNode = null;
32865 * @event selectionchange
32866 * Fires when the selected node changes
32867 * @param {DefaultSelectionModel} this
32868 * @param {TreeNode} node the new selection
32870 "selectionchange" : true,
32873 * @event beforeselect
32874 * Fires before the selected node changes, return false to cancel the change
32875 * @param {DefaultSelectionModel} this
32876 * @param {TreeNode} node the new selection
32877 * @param {TreeNode} node the old selection
32879 "beforeselect" : true
32882 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32885 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32886 init : function(tree){
32888 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32889 tree.on("click", this.onNodeClick, this);
32892 onNodeClick : function(node, e){
32893 if (e.ctrlKey && this.selNode == node) {
32894 this.unselect(node);
32902 * @param {TreeNode} node The node to select
32903 * @return {TreeNode} The selected node
32905 select : function(node){
32906 var last = this.selNode;
32907 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32909 last.ui.onSelectedChange(false);
32911 this.selNode = node;
32912 node.ui.onSelectedChange(true);
32913 this.fireEvent("selectionchange", this, node, last);
32920 * @param {TreeNode} node The node to unselect
32922 unselect : function(node){
32923 if(this.selNode == node){
32924 this.clearSelections();
32929 * Clear all selections
32931 clearSelections : function(){
32932 var n = this.selNode;
32934 n.ui.onSelectedChange(false);
32935 this.selNode = null;
32936 this.fireEvent("selectionchange", this, null);
32942 * Get the selected node
32943 * @return {TreeNode} The selected node
32945 getSelectedNode : function(){
32946 return this.selNode;
32950 * Returns true if the node is selected
32951 * @param {TreeNode} node The node to check
32952 * @return {Boolean}
32954 isSelected : function(node){
32955 return this.selNode == node;
32959 * Selects the node above the selected node in the tree, intelligently walking the nodes
32960 * @return TreeNode The new selection
32962 selectPrevious : function(){
32963 var s = this.selNode || this.lastSelNode;
32967 var ps = s.previousSibling;
32969 if(!ps.isExpanded() || ps.childNodes.length < 1){
32970 return this.select(ps);
32972 var lc = ps.lastChild;
32973 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32976 return this.select(lc);
32978 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32979 return this.select(s.parentNode);
32985 * Selects the node above the selected node in the tree, intelligently walking the nodes
32986 * @return TreeNode The new selection
32988 selectNext : function(){
32989 var s = this.selNode || this.lastSelNode;
32993 if(s.firstChild && s.isExpanded()){
32994 return this.select(s.firstChild);
32995 }else if(s.nextSibling){
32996 return this.select(s.nextSibling);
32997 }else if(s.parentNode){
32999 s.parentNode.bubble(function(){
33000 if(this.nextSibling){
33001 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33010 onKeyDown : function(e){
33011 var s = this.selNode || this.lastSelNode;
33012 // undesirable, but required
33017 var k = e.getKey();
33025 this.selectPrevious();
33028 e.preventDefault();
33029 if(s.hasChildNodes()){
33030 if(!s.isExpanded()){
33032 }else if(s.firstChild){
33033 this.select(s.firstChild, e);
33038 e.preventDefault();
33039 if(s.hasChildNodes() && s.isExpanded()){
33041 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33042 this.select(s.parentNode, e);
33050 * @class Roo.tree.MultiSelectionModel
33051 * @extends Roo.util.Observable
33052 * Multi selection for a TreePanel.
33053 * @param {Object} cfg Configuration
33055 Roo.tree.MultiSelectionModel = function(){
33056 this.selNodes = [];
33060 * @event selectionchange
33061 * Fires when the selected nodes change
33062 * @param {MultiSelectionModel} this
33063 * @param {Array} nodes Array of the selected nodes
33065 "selectionchange" : true
33067 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33071 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33072 init : function(tree){
33074 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33075 tree.on("click", this.onNodeClick, this);
33078 onNodeClick : function(node, e){
33079 this.select(node, e, e.ctrlKey);
33084 * @param {TreeNode} node The node to select
33085 * @param {EventObject} e (optional) An event associated with the selection
33086 * @param {Boolean} keepExisting True to retain existing selections
33087 * @return {TreeNode} The selected node
33089 select : function(node, e, keepExisting){
33090 if(keepExisting !== true){
33091 this.clearSelections(true);
33093 if(this.isSelected(node)){
33094 this.lastSelNode = node;
33097 this.selNodes.push(node);
33098 this.selMap[node.id] = node;
33099 this.lastSelNode = node;
33100 node.ui.onSelectedChange(true);
33101 this.fireEvent("selectionchange", this, this.selNodes);
33107 * @param {TreeNode} node The node to unselect
33109 unselect : function(node){
33110 if(this.selMap[node.id]){
33111 node.ui.onSelectedChange(false);
33112 var sn = this.selNodes;
33115 index = sn.indexOf(node);
33117 for(var i = 0, len = sn.length; i < len; i++){
33125 this.selNodes.splice(index, 1);
33127 delete this.selMap[node.id];
33128 this.fireEvent("selectionchange", this, this.selNodes);
33133 * Clear all selections
33135 clearSelections : function(suppressEvent){
33136 var sn = this.selNodes;
33138 for(var i = 0, len = sn.length; i < len; i++){
33139 sn[i].ui.onSelectedChange(false);
33141 this.selNodes = [];
33143 if(suppressEvent !== true){
33144 this.fireEvent("selectionchange", this, this.selNodes);
33150 * Returns true if the node is selected
33151 * @param {TreeNode} node The node to check
33152 * @return {Boolean}
33154 isSelected : function(node){
33155 return this.selMap[node.id] ? true : false;
33159 * Returns an array of the selected nodes
33162 getSelectedNodes : function(){
33163 return this.selNodes;
33166 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33168 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33170 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33173 * Ext JS Library 1.1.1
33174 * Copyright(c) 2006-2007, Ext JS, LLC.
33176 * Originally Released Under LGPL - original licence link has changed is not relivant.
33179 * <script type="text/javascript">
33183 * @class Roo.tree.TreeNode
33184 * @extends Roo.data.Node
33185 * @cfg {String} text The text for this node
33186 * @cfg {Boolean} expanded true to start the node expanded
33187 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33188 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33189 * @cfg {Boolean} disabled true to start the node disabled
33190 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33191 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33192 * @cfg {String} cls A css class to be added to the node
33193 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33194 * @cfg {String} href URL of the link used for the node (defaults to #)
33195 * @cfg {String} hrefTarget target frame for the link
33196 * @cfg {String} qtip An Ext QuickTip for the node
33197 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33198 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33199 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33200 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33201 * (defaults to undefined with no checkbox rendered)
33203 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33205 Roo.tree.TreeNode = function(attributes){
33206 attributes = attributes || {};
33207 if(typeof attributes == "string"){
33208 attributes = {text: attributes};
33210 this.childrenRendered = false;
33211 this.rendered = false;
33212 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33213 this.expanded = attributes.expanded === true;
33214 this.isTarget = attributes.isTarget !== false;
33215 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33216 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33219 * Read-only. The text for this node. To change it use setText().
33222 this.text = attributes.text;
33224 * True if this node is disabled.
33227 this.disabled = attributes.disabled === true;
33231 * @event textchange
33232 * Fires when the text for this node is changed
33233 * @param {Node} this This node
33234 * @param {String} text The new text
33235 * @param {String} oldText The old text
33237 "textchange" : true,
33239 * @event beforeexpand
33240 * Fires before this node is expanded, return false to cancel.
33241 * @param {Node} this This node
33242 * @param {Boolean} deep
33243 * @param {Boolean} anim
33245 "beforeexpand" : true,
33247 * @event beforecollapse
33248 * Fires before this node is collapsed, return false to cancel.
33249 * @param {Node} this This node
33250 * @param {Boolean} deep
33251 * @param {Boolean} anim
33253 "beforecollapse" : true,
33256 * Fires when this node is expanded
33257 * @param {Node} this This node
33261 * @event disabledchange
33262 * Fires when the disabled status of this node changes
33263 * @param {Node} this This node
33264 * @param {Boolean} disabled
33266 "disabledchange" : true,
33269 * Fires when this node is collapsed
33270 * @param {Node} this This node
33274 * @event beforeclick
33275 * Fires before click processing. Return false to cancel the default action.
33276 * @param {Node} this This node
33277 * @param {Roo.EventObject} e The event object
33279 "beforeclick":true,
33281 * @event checkchange
33282 * Fires when a node with a checkbox's checked property changes
33283 * @param {Node} this This node
33284 * @param {Boolean} checked
33286 "checkchange":true,
33289 * Fires when this node is clicked
33290 * @param {Node} this This node
33291 * @param {Roo.EventObject} e The event object
33296 * Fires when this node is double clicked
33297 * @param {Node} this This node
33298 * @param {Roo.EventObject} e The event object
33302 * @event contextmenu
33303 * Fires when this node is right clicked
33304 * @param {Node} this This node
33305 * @param {Roo.EventObject} e The event object
33307 "contextmenu":true,
33309 * @event beforechildrenrendered
33310 * Fires right before the child nodes for this node are rendered
33311 * @param {Node} this This node
33313 "beforechildrenrendered":true
33316 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33319 * Read-only. The UI for this node
33322 this.ui = new uiClass(this);
33324 // finally support items[]
33325 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33330 Roo.each(this.attributes.items, function(c) {
33331 this.appendChild(Roo.factory(c,Roo.Tree));
33333 delete this.attributes.items;
33338 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33339 preventHScroll: true,
33341 * Returns true if this node is expanded
33342 * @return {Boolean}
33344 isExpanded : function(){
33345 return this.expanded;
33349 * Returns the UI object for this node
33350 * @return {TreeNodeUI}
33352 getUI : function(){
33356 // private override
33357 setFirstChild : function(node){
33358 var of = this.firstChild;
33359 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33360 if(this.childrenRendered && of && node != of){
33361 of.renderIndent(true, true);
33364 this.renderIndent(true, true);
33368 // private override
33369 setLastChild : function(node){
33370 var ol = this.lastChild;
33371 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33372 if(this.childrenRendered && ol && node != ol){
33373 ol.renderIndent(true, true);
33376 this.renderIndent(true, true);
33380 // these methods are overridden to provide lazy rendering support
33381 // private override
33382 appendChild : function()
33384 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33385 if(node && this.childrenRendered){
33388 this.ui.updateExpandIcon();
33392 // private override
33393 removeChild : function(node){
33394 this.ownerTree.getSelectionModel().unselect(node);
33395 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33396 // if it's been rendered remove dom node
33397 if(this.childrenRendered){
33400 if(this.childNodes.length < 1){
33401 this.collapse(false, false);
33403 this.ui.updateExpandIcon();
33405 if(!this.firstChild) {
33406 this.childrenRendered = false;
33411 // private override
33412 insertBefore : function(node, refNode){
33413 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33414 if(newNode && refNode && this.childrenRendered){
33417 this.ui.updateExpandIcon();
33422 * Sets the text for this node
33423 * @param {String} text
33425 setText : function(text){
33426 var oldText = this.text;
33428 this.attributes.text = text;
33429 if(this.rendered){ // event without subscribing
33430 this.ui.onTextChange(this, text, oldText);
33432 this.fireEvent("textchange", this, text, oldText);
33436 * Triggers selection of this node
33438 select : function(){
33439 this.getOwnerTree().getSelectionModel().select(this);
33443 * Triggers deselection of this node
33445 unselect : function(){
33446 this.getOwnerTree().getSelectionModel().unselect(this);
33450 * Returns true if this node is selected
33451 * @return {Boolean}
33453 isSelected : function(){
33454 return this.getOwnerTree().getSelectionModel().isSelected(this);
33458 * Expand this node.
33459 * @param {Boolean} deep (optional) True to expand all children as well
33460 * @param {Boolean} anim (optional) false to cancel the default animation
33461 * @param {Function} callback (optional) A callback to be called when
33462 * expanding this node completes (does not wait for deep expand to complete).
33463 * Called with 1 parameter, this node.
33465 expand : function(deep, anim, callback){
33466 if(!this.expanded){
33467 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33470 if(!this.childrenRendered){
33471 this.renderChildren();
33473 this.expanded = true;
33474 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33475 this.ui.animExpand(function(){
33476 this.fireEvent("expand", this);
33477 if(typeof callback == "function"){
33481 this.expandChildNodes(true);
33483 }.createDelegate(this));
33487 this.fireEvent("expand", this);
33488 if(typeof callback == "function"){
33493 if(typeof callback == "function"){
33498 this.expandChildNodes(true);
33502 isHiddenRoot : function(){
33503 return this.isRoot && !this.getOwnerTree().rootVisible;
33507 * Collapse this node.
33508 * @param {Boolean} deep (optional) True to collapse all children as well
33509 * @param {Boolean} anim (optional) false to cancel the default animation
33511 collapse : function(deep, anim){
33512 if(this.expanded && !this.isHiddenRoot()){
33513 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33516 this.expanded = false;
33517 if((this.getOwnerTree().animate && anim !== false) || anim){
33518 this.ui.animCollapse(function(){
33519 this.fireEvent("collapse", this);
33521 this.collapseChildNodes(true);
33523 }.createDelegate(this));
33526 this.ui.collapse();
33527 this.fireEvent("collapse", this);
33531 var cs = this.childNodes;
33532 for(var i = 0, len = cs.length; i < len; i++) {
33533 cs[i].collapse(true, false);
33539 delayedExpand : function(delay){
33540 if(!this.expandProcId){
33541 this.expandProcId = this.expand.defer(delay, this);
33546 cancelExpand : function(){
33547 if(this.expandProcId){
33548 clearTimeout(this.expandProcId);
33550 this.expandProcId = false;
33554 * Toggles expanded/collapsed state of the node
33556 toggle : function(){
33565 * Ensures all parent nodes are expanded
33567 ensureVisible : function(callback){
33568 var tree = this.getOwnerTree();
33569 tree.expandPath(this.parentNode.getPath(), false, function(){
33570 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33571 Roo.callback(callback);
33572 }.createDelegate(this));
33576 * Expand all child nodes
33577 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33579 expandChildNodes : function(deep){
33580 var cs = this.childNodes;
33581 for(var i = 0, len = cs.length; i < len; i++) {
33582 cs[i].expand(deep);
33587 * Collapse all child nodes
33588 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33590 collapseChildNodes : function(deep){
33591 var cs = this.childNodes;
33592 for(var i = 0, len = cs.length; i < len; i++) {
33593 cs[i].collapse(deep);
33598 * Disables this node
33600 disable : function(){
33601 this.disabled = true;
33603 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33604 this.ui.onDisableChange(this, true);
33606 this.fireEvent("disabledchange", this, true);
33610 * Enables this node
33612 enable : function(){
33613 this.disabled = false;
33614 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33615 this.ui.onDisableChange(this, false);
33617 this.fireEvent("disabledchange", this, false);
33621 renderChildren : function(suppressEvent){
33622 if(suppressEvent !== false){
33623 this.fireEvent("beforechildrenrendered", this);
33625 var cs = this.childNodes;
33626 for(var i = 0, len = cs.length; i < len; i++){
33627 cs[i].render(true);
33629 this.childrenRendered = true;
33633 sort : function(fn, scope){
33634 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33635 if(this.childrenRendered){
33636 var cs = this.childNodes;
33637 for(var i = 0, len = cs.length; i < len; i++){
33638 cs[i].render(true);
33644 render : function(bulkRender){
33645 this.ui.render(bulkRender);
33646 if(!this.rendered){
33647 this.rendered = true;
33649 this.expanded = false;
33650 this.expand(false, false);
33656 renderIndent : function(deep, refresh){
33658 this.ui.childIndent = null;
33660 this.ui.renderIndent();
33661 if(deep === true && this.childrenRendered){
33662 var cs = this.childNodes;
33663 for(var i = 0, len = cs.length; i < len; i++){
33664 cs[i].renderIndent(true, refresh);
33670 * Ext JS Library 1.1.1
33671 * Copyright(c) 2006-2007, Ext JS, LLC.
33673 * Originally Released Under LGPL - original licence link has changed is not relivant.
33676 * <script type="text/javascript">
33680 * @class Roo.tree.AsyncTreeNode
33681 * @extends Roo.tree.TreeNode
33682 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33684 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33686 Roo.tree.AsyncTreeNode = function(config){
33687 this.loaded = false;
33688 this.loading = false;
33689 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33691 * @event beforeload
33692 * Fires before this node is loaded, return false to cancel
33693 * @param {Node} this This node
33695 this.addEvents({'beforeload':true, 'load': true});
33698 * Fires when this node is loaded
33699 * @param {Node} this This node
33702 * The loader used by this node (defaults to using the tree's defined loader)
33707 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33708 expand : function(deep, anim, callback){
33709 if(this.loading){ // if an async load is already running, waiting til it's done
33711 var f = function(){
33712 if(!this.loading){ // done loading
33713 clearInterval(timer);
33714 this.expand(deep, anim, callback);
33716 }.createDelegate(this);
33717 timer = setInterval(f, 200);
33721 if(this.fireEvent("beforeload", this) === false){
33724 this.loading = true;
33725 this.ui.beforeLoad(this);
33726 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33728 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33732 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33736 * Returns true if this node is currently loading
33737 * @return {Boolean}
33739 isLoading : function(){
33740 return this.loading;
33743 loadComplete : function(deep, anim, callback){
33744 this.loading = false;
33745 this.loaded = true;
33746 this.ui.afterLoad(this);
33747 this.fireEvent("load", this);
33748 this.expand(deep, anim, callback);
33752 * Returns true if this node has been loaded
33753 * @return {Boolean}
33755 isLoaded : function(){
33756 return this.loaded;
33759 hasChildNodes : function(){
33760 if(!this.isLeaf() && !this.loaded){
33763 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33768 * Trigger a reload for this node
33769 * @param {Function} callback
33771 reload : function(callback){
33772 this.collapse(false, false);
33773 while(this.firstChild){
33774 this.removeChild(this.firstChild);
33776 this.childrenRendered = false;
33777 this.loaded = false;
33778 if(this.isHiddenRoot()){
33779 this.expanded = false;
33781 this.expand(false, false, callback);
33785 * Ext JS Library 1.1.1
33786 * Copyright(c) 2006-2007, Ext JS, LLC.
33788 * Originally Released Under LGPL - original licence link has changed is not relivant.
33791 * <script type="text/javascript">
33795 * @class Roo.tree.TreeNodeUI
33797 * @param {Object} node The node to render
33798 * The TreeNode UI implementation is separate from the
33799 * tree implementation. Unless you are customizing the tree UI,
33800 * you should never have to use this directly.
33802 Roo.tree.TreeNodeUI = function(node){
33804 this.rendered = false;
33805 this.animating = false;
33806 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33809 Roo.tree.TreeNodeUI.prototype = {
33810 removeChild : function(node){
33812 this.ctNode.removeChild(node.ui.getEl());
33816 beforeLoad : function(){
33817 this.addClass("x-tree-node-loading");
33820 afterLoad : function(){
33821 this.removeClass("x-tree-node-loading");
33824 onTextChange : function(node, text, oldText){
33826 this.textNode.innerHTML = text;
33830 onDisableChange : function(node, state){
33831 this.disabled = state;
33833 this.addClass("x-tree-node-disabled");
33835 this.removeClass("x-tree-node-disabled");
33839 onSelectedChange : function(state){
33842 this.addClass("x-tree-selected");
33845 this.removeClass("x-tree-selected");
33849 onMove : function(tree, node, oldParent, newParent, index, refNode){
33850 this.childIndent = null;
33852 var targetNode = newParent.ui.getContainer();
33853 if(!targetNode){//target not rendered
33854 this.holder = document.createElement("div");
33855 this.holder.appendChild(this.wrap);
33858 var insertBefore = refNode ? refNode.ui.getEl() : null;
33860 targetNode.insertBefore(this.wrap, insertBefore);
33862 targetNode.appendChild(this.wrap);
33864 this.node.renderIndent(true);
33868 addClass : function(cls){
33870 Roo.fly(this.elNode).addClass(cls);
33874 removeClass : function(cls){
33876 Roo.fly(this.elNode).removeClass(cls);
33880 remove : function(){
33882 this.holder = document.createElement("div");
33883 this.holder.appendChild(this.wrap);
33887 fireEvent : function(){
33888 return this.node.fireEvent.apply(this.node, arguments);
33891 initEvents : function(){
33892 this.node.on("move", this.onMove, this);
33893 var E = Roo.EventManager;
33894 var a = this.anchor;
33896 var el = Roo.fly(a, '_treeui');
33898 if(Roo.isOpera){ // opera render bug ignores the CSS
33899 el.setStyle("text-decoration", "none");
33902 el.on("click", this.onClick, this);
33903 el.on("dblclick", this.onDblClick, this);
33906 Roo.EventManager.on(this.checkbox,
33907 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33910 el.on("contextmenu", this.onContextMenu, this);
33912 var icon = Roo.fly(this.iconNode);
33913 icon.on("click", this.onClick, this);
33914 icon.on("dblclick", this.onDblClick, this);
33915 icon.on("contextmenu", this.onContextMenu, this);
33916 E.on(this.ecNode, "click", this.ecClick, this, true);
33918 if(this.node.disabled){
33919 this.addClass("x-tree-node-disabled");
33921 if(this.node.hidden){
33922 this.addClass("x-tree-node-disabled");
33924 var ot = this.node.getOwnerTree();
33925 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33926 if(dd && (!this.node.isRoot || ot.rootVisible)){
33927 Roo.dd.Registry.register(this.elNode, {
33929 handles: this.getDDHandles(),
33935 getDDHandles : function(){
33936 return [this.iconNode, this.textNode];
33941 this.wrap.style.display = "none";
33947 this.wrap.style.display = "";
33951 onContextMenu : function(e){
33952 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33953 e.preventDefault();
33955 this.fireEvent("contextmenu", this.node, e);
33959 onClick : function(e){
33964 if(this.fireEvent("beforeclick", this.node, e) !== false){
33965 if(!this.disabled && this.node.attributes.href){
33966 this.fireEvent("click", this.node, e);
33969 e.preventDefault();
33974 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33975 this.node.toggle();
33978 this.fireEvent("click", this.node, e);
33984 onDblClick : function(e){
33985 e.preventDefault();
33990 this.toggleCheck();
33992 if(!this.animating && this.node.hasChildNodes()){
33993 this.node.toggle();
33995 this.fireEvent("dblclick", this.node, e);
33998 onCheckChange : function(){
33999 var checked = this.checkbox.checked;
34000 this.node.attributes.checked = checked;
34001 this.fireEvent('checkchange', this.node, checked);
34004 ecClick : function(e){
34005 if(!this.animating && this.node.hasChildNodes()){
34006 this.node.toggle();
34010 startDrop : function(){
34011 this.dropping = true;
34014 // delayed drop so the click event doesn't get fired on a drop
34015 endDrop : function(){
34016 setTimeout(function(){
34017 this.dropping = false;
34018 }.createDelegate(this), 50);
34021 expand : function(){
34022 this.updateExpandIcon();
34023 this.ctNode.style.display = "";
34026 focus : function(){
34027 if(!this.node.preventHScroll){
34028 try{this.anchor.focus();
34030 }else if(!Roo.isIE){
34032 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34033 var l = noscroll.scrollLeft;
34034 this.anchor.focus();
34035 noscroll.scrollLeft = l;
34040 toggleCheck : function(value){
34041 var cb = this.checkbox;
34043 cb.checked = (value === undefined ? !cb.checked : value);
34049 this.anchor.blur();
34053 animExpand : function(callback){
34054 var ct = Roo.get(this.ctNode);
34056 if(!this.node.hasChildNodes()){
34057 this.updateExpandIcon();
34058 this.ctNode.style.display = "";
34059 Roo.callback(callback);
34062 this.animating = true;
34063 this.updateExpandIcon();
34066 callback : function(){
34067 this.animating = false;
34068 Roo.callback(callback);
34071 duration: this.node.ownerTree.duration || .25
34075 highlight : function(){
34076 var tree = this.node.getOwnerTree();
34077 Roo.fly(this.wrap).highlight(
34078 tree.hlColor || "C3DAF9",
34079 {endColor: tree.hlBaseColor}
34083 collapse : function(){
34084 this.updateExpandIcon();
34085 this.ctNode.style.display = "none";
34088 animCollapse : function(callback){
34089 var ct = Roo.get(this.ctNode);
34090 ct.enableDisplayMode('block');
34093 this.animating = true;
34094 this.updateExpandIcon();
34097 callback : function(){
34098 this.animating = false;
34099 Roo.callback(callback);
34102 duration: this.node.ownerTree.duration || .25
34106 getContainer : function(){
34107 return this.ctNode;
34110 getEl : function(){
34114 appendDDGhost : function(ghostNode){
34115 ghostNode.appendChild(this.elNode.cloneNode(true));
34118 getDDRepairXY : function(){
34119 return Roo.lib.Dom.getXY(this.iconNode);
34122 onRender : function(){
34126 render : function(bulkRender){
34127 var n = this.node, a = n.attributes;
34128 var targetNode = n.parentNode ?
34129 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34131 if(!this.rendered){
34132 this.rendered = true;
34134 this.renderElements(n, a, targetNode, bulkRender);
34137 if(this.textNode.setAttributeNS){
34138 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34140 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34143 this.textNode.setAttribute("ext:qtip", a.qtip);
34145 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34148 }else if(a.qtipCfg){
34149 a.qtipCfg.target = Roo.id(this.textNode);
34150 Roo.QuickTips.register(a.qtipCfg);
34153 if(!this.node.expanded){
34154 this.updateExpandIcon();
34157 if(bulkRender === true) {
34158 targetNode.appendChild(this.wrap);
34163 renderElements : function(n, a, targetNode, bulkRender)
34165 // add some indent caching, this helps performance when rendering a large tree
34166 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34167 var t = n.getOwnerTree();
34168 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34169 if (typeof(n.attributes.html) != 'undefined') {
34170 txt = n.attributes.html;
34172 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34173 var cb = typeof a.checked == 'boolean';
34174 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34175 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34176 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34177 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34178 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34179 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34180 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34181 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34182 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34183 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34186 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34187 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34188 n.nextSibling.ui.getEl(), buf.join(""));
34190 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34193 this.elNode = this.wrap.childNodes[0];
34194 this.ctNode = this.wrap.childNodes[1];
34195 var cs = this.elNode.childNodes;
34196 this.indentNode = cs[0];
34197 this.ecNode = cs[1];
34198 this.iconNode = cs[2];
34201 this.checkbox = cs[3];
34204 this.anchor = cs[index];
34205 this.textNode = cs[index].firstChild;
34208 getAnchor : function(){
34209 return this.anchor;
34212 getTextEl : function(){
34213 return this.textNode;
34216 getIconEl : function(){
34217 return this.iconNode;
34220 isChecked : function(){
34221 return this.checkbox ? this.checkbox.checked : false;
34224 updateExpandIcon : function(){
34226 var n = this.node, c1, c2;
34227 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34228 var hasChild = n.hasChildNodes();
34232 c1 = "x-tree-node-collapsed";
34233 c2 = "x-tree-node-expanded";
34236 c1 = "x-tree-node-expanded";
34237 c2 = "x-tree-node-collapsed";
34240 this.removeClass("x-tree-node-leaf");
34241 this.wasLeaf = false;
34243 if(this.c1 != c1 || this.c2 != c2){
34244 Roo.fly(this.elNode).replaceClass(c1, c2);
34245 this.c1 = c1; this.c2 = c2;
34248 // this changes non-leafs into leafs if they have no children.
34249 // it's not very rational behaviour..
34251 if(!this.wasLeaf && this.node.leaf){
34252 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34255 this.wasLeaf = true;
34258 var ecc = "x-tree-ec-icon "+cls;
34259 if(this.ecc != ecc){
34260 this.ecNode.className = ecc;
34266 getChildIndent : function(){
34267 if(!this.childIndent){
34271 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34273 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34275 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34280 this.childIndent = buf.join("");
34282 return this.childIndent;
34285 renderIndent : function(){
34288 var p = this.node.parentNode;
34290 indent = p.ui.getChildIndent();
34292 if(this.indentMarkup != indent){ // don't rerender if not required
34293 this.indentNode.innerHTML = indent;
34294 this.indentMarkup = indent;
34296 this.updateExpandIcon();
34301 Roo.tree.RootTreeNodeUI = function(){
34302 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34304 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34305 render : function(){
34306 if(!this.rendered){
34307 var targetNode = this.node.ownerTree.innerCt.dom;
34308 this.node.expanded = true;
34309 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34310 this.wrap = this.ctNode = targetNode.firstChild;
34313 collapse : function(){
34315 expand : function(){
34319 * Ext JS Library 1.1.1
34320 * Copyright(c) 2006-2007, Ext JS, LLC.
34322 * Originally Released Under LGPL - original licence link has changed is not relivant.
34325 * <script type="text/javascript">
34328 * @class Roo.tree.TreeLoader
34329 * @extends Roo.util.Observable
34330 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34331 * nodes from a specified URL. The response must be a javascript Array definition
34332 * who's elements are node definition objects. eg:
34337 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34338 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34345 * The old style respose with just an array is still supported, but not recommended.
34348 * A server request is sent, and child nodes are loaded only when a node is expanded.
34349 * The loading node's id is passed to the server under the parameter name "node" to
34350 * enable the server to produce the correct child nodes.
34352 * To pass extra parameters, an event handler may be attached to the "beforeload"
34353 * event, and the parameters specified in the TreeLoader's baseParams property:
34355 myTreeLoader.on("beforeload", function(treeLoader, node) {
34356 this.baseParams.category = node.attributes.category;
34359 * This would pass an HTTP parameter called "category" to the server containing
34360 * the value of the Node's "category" attribute.
34362 * Creates a new Treeloader.
34363 * @param {Object} config A config object containing config properties.
34365 Roo.tree.TreeLoader = function(config){
34366 this.baseParams = {};
34367 this.requestMethod = "POST";
34368 Roo.apply(this, config);
34373 * @event beforeload
34374 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34375 * @param {Object} This TreeLoader object.
34376 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34377 * @param {Object} callback The callback function specified in the {@link #load} call.
34382 * Fires when the node has been successfuly loaded.
34383 * @param {Object} This TreeLoader object.
34384 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34385 * @param {Object} response The response object containing the data from the server.
34389 * @event loadexception
34390 * Fires if the network request failed.
34391 * @param {Object} This TreeLoader object.
34392 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34393 * @param {Object} response The response object containing the data from the server.
34395 loadexception : true,
34398 * Fires before a node is created, enabling you to return custom Node types
34399 * @param {Object} This TreeLoader object.
34400 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34405 Roo.tree.TreeLoader.superclass.constructor.call(this);
34408 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34410 * @cfg {String} dataUrl The URL from which to request a Json string which
34411 * specifies an array of node definition object representing the child nodes
34415 * @cfg {String} requestMethod either GET or POST
34416 * defaults to POST (due to BC)
34420 * @cfg {Object} baseParams (optional) An object containing properties which
34421 * specify HTTP parameters to be passed to each request for child nodes.
34424 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34425 * created by this loader. If the attributes sent by the server have an attribute in this object,
34426 * they take priority.
34429 * @cfg {Object} uiProviders (optional) An object containing properties which
34431 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34432 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34433 * <i>uiProvider</i> attribute of a returned child node is a string rather
34434 * than a reference to a TreeNodeUI implementation, this that string value
34435 * is used as a property name in the uiProviders object. You can define the provider named
34436 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34441 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34442 * child nodes before loading.
34444 clearOnLoad : true,
34447 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34448 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34449 * Grid query { data : [ .....] }
34454 * @cfg {String} queryParam (optional)
34455 * Name of the query as it will be passed on the querystring (defaults to 'node')
34456 * eg. the request will be ?node=[id]
34463 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34464 * This is called automatically when a node is expanded, but may be used to reload
34465 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34466 * @param {Roo.tree.TreeNode} node
34467 * @param {Function} callback
34469 load : function(node, callback){
34470 if(this.clearOnLoad){
34471 while(node.firstChild){
34472 node.removeChild(node.firstChild);
34475 if(node.attributes.children){ // preloaded json children
34476 var cs = node.attributes.children;
34477 for(var i = 0, len = cs.length; i < len; i++){
34478 node.appendChild(this.createNode(cs[i]));
34480 if(typeof callback == "function"){
34483 }else if(this.dataUrl){
34484 this.requestData(node, callback);
34488 getParams: function(node){
34489 var buf = [], bp = this.baseParams;
34490 for(var key in bp){
34491 if(typeof bp[key] != "function"){
34492 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34495 var n = this.queryParam === false ? 'node' : this.queryParam;
34496 buf.push(n + "=", encodeURIComponent(node.id));
34497 return buf.join("");
34500 requestData : function(node, callback){
34501 if(this.fireEvent("beforeload", this, node, callback) !== false){
34502 this.transId = Roo.Ajax.request({
34503 method:this.requestMethod,
34504 url: this.dataUrl||this.url,
34505 success: this.handleResponse,
34506 failure: this.handleFailure,
34508 argument: {callback: callback, node: node},
34509 params: this.getParams(node)
34512 // if the load is cancelled, make sure we notify
34513 // the node that we are done
34514 if(typeof callback == "function"){
34520 isLoading : function(){
34521 return this.transId ? true : false;
34524 abort : function(){
34525 if(this.isLoading()){
34526 Roo.Ajax.abort(this.transId);
34531 createNode : function(attr)
34533 // apply baseAttrs, nice idea Corey!
34534 if(this.baseAttrs){
34535 Roo.applyIf(attr, this.baseAttrs);
34537 if(this.applyLoader !== false){
34538 attr.loader = this;
34540 // uiProvider = depreciated..
34542 if(typeof(attr.uiProvider) == 'string'){
34543 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34544 /** eval:var:attr */ eval(attr.uiProvider);
34546 if(typeof(this.uiProviders['default']) != 'undefined') {
34547 attr.uiProvider = this.uiProviders['default'];
34550 this.fireEvent('create', this, attr);
34552 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34554 new Roo.tree.TreeNode(attr) :
34555 new Roo.tree.AsyncTreeNode(attr));
34558 processResponse : function(response, node, callback)
34560 var json = response.responseText;
34563 var o = Roo.decode(json);
34565 if (this.root === false && typeof(o.success) != undefined) {
34566 this.root = 'data'; // the default behaviour for list like data..
34569 if (this.root !== false && !o.success) {
34570 // it's a failure condition.
34571 var a = response.argument;
34572 this.fireEvent("loadexception", this, a.node, response);
34573 Roo.log("Load failed - should have a handler really");
34579 if (this.root !== false) {
34583 for(var i = 0, len = o.length; i < len; i++){
34584 var n = this.createNode(o[i]);
34586 node.appendChild(n);
34589 if(typeof callback == "function"){
34590 callback(this, node);
34593 this.handleFailure(response);
34597 handleResponse : function(response){
34598 this.transId = false;
34599 var a = response.argument;
34600 this.processResponse(response, a.node, a.callback);
34601 this.fireEvent("load", this, a.node, response);
34604 handleFailure : function(response)
34606 // should handle failure better..
34607 this.transId = false;
34608 var a = response.argument;
34609 this.fireEvent("loadexception", this, a.node, response);
34610 if(typeof a.callback == "function"){
34611 a.callback(this, a.node);
34616 * Ext JS Library 1.1.1
34617 * Copyright(c) 2006-2007, Ext JS, LLC.
34619 * Originally Released Under LGPL - original licence link has changed is not relivant.
34622 * <script type="text/javascript">
34626 * @class Roo.tree.TreeFilter
34627 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34628 * @param {TreePanel} tree
34629 * @param {Object} config (optional)
34631 Roo.tree.TreeFilter = function(tree, config){
34633 this.filtered = {};
34634 Roo.apply(this, config);
34637 Roo.tree.TreeFilter.prototype = {
34644 * Filter the data by a specific attribute.
34645 * @param {String/RegExp} value Either string that the attribute value
34646 * should start with or a RegExp to test against the attribute
34647 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34648 * @param {TreeNode} startNode (optional) The node to start the filter at.
34650 filter : function(value, attr, startNode){
34651 attr = attr || "text";
34653 if(typeof value == "string"){
34654 var vlen = value.length;
34655 // auto clear empty filter
34656 if(vlen == 0 && this.clearBlank){
34660 value = value.toLowerCase();
34662 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34664 }else if(value.exec){ // regex?
34666 return value.test(n.attributes[attr]);
34669 throw 'Illegal filter type, must be string or regex';
34671 this.filterBy(f, null, startNode);
34675 * Filter by a function. The passed function will be called with each
34676 * node in the tree (or from the startNode). If the function returns true, the node is kept
34677 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34678 * @param {Function} fn The filter function
34679 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34681 filterBy : function(fn, scope, startNode){
34682 startNode = startNode || this.tree.root;
34683 if(this.autoClear){
34686 var af = this.filtered, rv = this.reverse;
34687 var f = function(n){
34688 if(n == startNode){
34694 var m = fn.call(scope || n, n);
34702 startNode.cascade(f);
34705 if(typeof id != "function"){
34707 if(n && n.parentNode){
34708 n.parentNode.removeChild(n);
34716 * Clears the current filter. Note: with the "remove" option
34717 * set a filter cannot be cleared.
34719 clear : function(){
34721 var af = this.filtered;
34723 if(typeof id != "function"){
34730 this.filtered = {};
34735 * Ext JS Library 1.1.1
34736 * Copyright(c) 2006-2007, Ext JS, LLC.
34738 * Originally Released Under LGPL - original licence link has changed is not relivant.
34741 * <script type="text/javascript">
34746 * @class Roo.tree.TreeSorter
34747 * Provides sorting of nodes in a TreePanel
34749 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34750 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34751 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34752 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34753 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34754 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34756 * @param {TreePanel} tree
34757 * @param {Object} config
34759 Roo.tree.TreeSorter = function(tree, config){
34760 Roo.apply(this, config);
34761 tree.on("beforechildrenrendered", this.doSort, this);
34762 tree.on("append", this.updateSort, this);
34763 tree.on("insert", this.updateSort, this);
34765 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34766 var p = this.property || "text";
34767 var sortType = this.sortType;
34768 var fs = this.folderSort;
34769 var cs = this.caseSensitive === true;
34770 var leafAttr = this.leafAttr || 'leaf';
34772 this.sortFn = function(n1, n2){
34774 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34777 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34781 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34782 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34784 return dsc ? +1 : -1;
34786 return dsc ? -1 : +1;
34793 Roo.tree.TreeSorter.prototype = {
34794 doSort : function(node){
34795 node.sort(this.sortFn);
34798 compareNodes : function(n1, n2){
34799 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34802 updateSort : function(tree, node){
34803 if(node.childrenRendered){
34804 this.doSort.defer(1, this, [node]);
34809 * Ext JS Library 1.1.1
34810 * Copyright(c) 2006-2007, Ext JS, LLC.
34812 * Originally Released Under LGPL - original licence link has changed is not relivant.
34815 * <script type="text/javascript">
34818 if(Roo.dd.DropZone){
34820 Roo.tree.TreeDropZone = function(tree, config){
34821 this.allowParentInsert = false;
34822 this.allowContainerDrop = false;
34823 this.appendOnly = false;
34824 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34826 this.lastInsertClass = "x-tree-no-status";
34827 this.dragOverData = {};
34830 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34831 ddGroup : "TreeDD",
34834 expandDelay : 1000,
34836 expandNode : function(node){
34837 if(node.hasChildNodes() && !node.isExpanded()){
34838 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34842 queueExpand : function(node){
34843 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34846 cancelExpand : function(){
34847 if(this.expandProcId){
34848 clearTimeout(this.expandProcId);
34849 this.expandProcId = false;
34853 isValidDropPoint : function(n, pt, dd, e, data){
34854 if(!n || !data){ return false; }
34855 var targetNode = n.node;
34856 var dropNode = data.node;
34857 // default drop rules
34858 if(!(targetNode && targetNode.isTarget && pt)){
34861 if(pt == "append" && targetNode.allowChildren === false){
34864 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34867 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34870 // reuse the object
34871 var overEvent = this.dragOverData;
34872 overEvent.tree = this.tree;
34873 overEvent.target = targetNode;
34874 overEvent.data = data;
34875 overEvent.point = pt;
34876 overEvent.source = dd;
34877 overEvent.rawEvent = e;
34878 overEvent.dropNode = dropNode;
34879 overEvent.cancel = false;
34880 var result = this.tree.fireEvent("nodedragover", overEvent);
34881 return overEvent.cancel === false && result !== false;
34884 getDropPoint : function(e, n, dd)
34888 return tn.allowChildren !== false ? "append" : false; // always append for root
34890 var dragEl = n.ddel;
34891 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34892 var y = Roo.lib.Event.getPageY(e);
34893 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34895 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34896 var noAppend = tn.allowChildren === false;
34897 if(this.appendOnly || tn.parentNode.allowChildren === false){
34898 return noAppend ? false : "append";
34900 var noBelow = false;
34901 if(!this.allowParentInsert){
34902 noBelow = tn.hasChildNodes() && tn.isExpanded();
34904 var q = (b - t) / (noAppend ? 2 : 3);
34905 if(y >= t && y < (t + q)){
34907 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34914 onNodeEnter : function(n, dd, e, data)
34916 this.cancelExpand();
34919 onNodeOver : function(n, dd, e, data)
34922 var pt = this.getDropPoint(e, n, dd);
34925 // auto node expand check
34926 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34927 this.queueExpand(node);
34928 }else if(pt != "append"){
34929 this.cancelExpand();
34932 // set the insert point style on the target node
34933 var returnCls = this.dropNotAllowed;
34934 if(this.isValidDropPoint(n, pt, dd, e, data)){
34939 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34940 cls = "x-tree-drag-insert-above";
34941 }else if(pt == "below"){
34942 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34943 cls = "x-tree-drag-insert-below";
34945 returnCls = "x-tree-drop-ok-append";
34946 cls = "x-tree-drag-append";
34948 if(this.lastInsertClass != cls){
34949 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34950 this.lastInsertClass = cls;
34957 onNodeOut : function(n, dd, e, data){
34959 this.cancelExpand();
34960 this.removeDropIndicators(n);
34963 onNodeDrop : function(n, dd, e, data){
34964 var point = this.getDropPoint(e, n, dd);
34965 var targetNode = n.node;
34966 targetNode.ui.startDrop();
34967 if(!this.isValidDropPoint(n, point, dd, e, data)){
34968 targetNode.ui.endDrop();
34971 // first try to find the drop node
34972 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34975 target: targetNode,
34980 dropNode: dropNode,
34983 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34984 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34985 targetNode.ui.endDrop();
34988 // allow target changing
34989 targetNode = dropEvent.target;
34990 if(point == "append" && !targetNode.isExpanded()){
34991 targetNode.expand(false, null, function(){
34992 this.completeDrop(dropEvent);
34993 }.createDelegate(this));
34995 this.completeDrop(dropEvent);
35000 completeDrop : function(de){
35001 var ns = de.dropNode, p = de.point, t = de.target;
35002 if(!(ns instanceof Array)){
35006 for(var i = 0, len = ns.length; i < len; i++){
35009 t.parentNode.insertBefore(n, t);
35010 }else if(p == "below"){
35011 t.parentNode.insertBefore(n, t.nextSibling);
35017 if(this.tree.hlDrop){
35021 this.tree.fireEvent("nodedrop", de);
35024 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35025 if(this.tree.hlDrop){
35026 dropNode.ui.focus();
35027 dropNode.ui.highlight();
35029 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35032 getTree : function(){
35036 removeDropIndicators : function(n){
35039 Roo.fly(el).removeClass([
35040 "x-tree-drag-insert-above",
35041 "x-tree-drag-insert-below",
35042 "x-tree-drag-append"]);
35043 this.lastInsertClass = "_noclass";
35047 beforeDragDrop : function(target, e, id){
35048 this.cancelExpand();
35052 afterRepair : function(data){
35053 if(data && Roo.enableFx){
35054 data.node.ui.highlight();
35064 * Ext JS Library 1.1.1
35065 * Copyright(c) 2006-2007, Ext JS, LLC.
35067 * Originally Released Under LGPL - original licence link has changed is not relivant.
35070 * <script type="text/javascript">
35074 if(Roo.dd.DragZone){
35075 Roo.tree.TreeDragZone = function(tree, config){
35076 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35080 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35081 ddGroup : "TreeDD",
35083 onBeforeDrag : function(data, e){
35085 return n && n.draggable && !n.disabled;
35089 onInitDrag : function(e){
35090 var data = this.dragData;
35091 this.tree.getSelectionModel().select(data.node);
35092 this.proxy.update("");
35093 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35094 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35097 getRepairXY : function(e, data){
35098 return data.node.ui.getDDRepairXY();
35101 onEndDrag : function(data, e){
35102 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35107 onValidDrop : function(dd, e, id){
35108 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35112 beforeInvalidDrop : function(e, id){
35113 // this scrolls the original position back into view
35114 var sm = this.tree.getSelectionModel();
35115 sm.clearSelections();
35116 sm.select(this.dragData.node);
35121 * Ext JS Library 1.1.1
35122 * Copyright(c) 2006-2007, Ext JS, LLC.
35124 * Originally Released Under LGPL - original licence link has changed is not relivant.
35127 * <script type="text/javascript">
35130 * @class Roo.tree.TreeEditor
35131 * @extends Roo.Editor
35132 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35133 * as the editor field.
35135 * @param {Object} config (used to be the tree panel.)
35136 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35138 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35139 * @cfg {Roo.form.TextField|Object} field The field configuration
35143 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35146 if (oldconfig) { // old style..
35147 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35150 tree = config.tree;
35151 config.field = config.field || {};
35152 config.field.xtype = 'TextField';
35153 field = Roo.factory(config.field, Roo.form);
35155 config = config || {};
35160 * @event beforenodeedit
35161 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35162 * false from the handler of this event.
35163 * @param {Editor} this
35164 * @param {Roo.tree.Node} node
35166 "beforenodeedit" : true
35170 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35174 tree.on('beforeclick', this.beforeNodeClick, this);
35175 tree.getTreeEl().on('mousedown', this.hide, this);
35176 this.on('complete', this.updateNode, this);
35177 this.on('beforestartedit', this.fitToTree, this);
35178 this.on('startedit', this.bindScroll, this, {delay:10});
35179 this.on('specialkey', this.onSpecialKey, this);
35182 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35184 * @cfg {String} alignment
35185 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35191 * @cfg {Boolean} hideEl
35192 * True to hide the bound element while the editor is displayed (defaults to false)
35196 * @cfg {String} cls
35197 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35199 cls: "x-small-editor x-tree-editor",
35201 * @cfg {Boolean} shim
35202 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35208 * @cfg {Number} maxWidth
35209 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35210 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35211 * scroll and client offsets into account prior to each edit.
35218 fitToTree : function(ed, el){
35219 var td = this.tree.getTreeEl().dom, nd = el.dom;
35220 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35221 td.scrollLeft = nd.offsetLeft;
35225 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35226 this.setSize(w, '');
35228 return this.fireEvent('beforenodeedit', this, this.editNode);
35233 triggerEdit : function(node){
35234 this.completeEdit();
35235 this.editNode = node;
35236 this.startEdit(node.ui.textNode, node.text);
35240 bindScroll : function(){
35241 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35245 beforeNodeClick : function(node, e){
35246 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35247 this.lastClick = new Date();
35248 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35250 this.triggerEdit(node);
35257 updateNode : function(ed, value){
35258 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35259 this.editNode.setText(value);
35263 onHide : function(){
35264 Roo.tree.TreeEditor.superclass.onHide.call(this);
35266 this.editNode.ui.focus();
35271 onSpecialKey : function(field, e){
35272 var k = e.getKey();
35276 }else if(k == e.ENTER && !e.hasModifier()){
35278 this.completeEdit();
35281 });//<Script type="text/javascript">
35284 * Ext JS Library 1.1.1
35285 * Copyright(c) 2006-2007, Ext JS, LLC.
35287 * Originally Released Under LGPL - original licence link has changed is not relivant.
35290 * <script type="text/javascript">
35294 * Not documented??? - probably should be...
35297 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35298 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35300 renderElements : function(n, a, targetNode, bulkRender){
35301 //consel.log("renderElements?");
35302 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35304 var t = n.getOwnerTree();
35305 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35307 var cols = t.columns;
35308 var bw = t.borderWidth;
35310 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35311 var cb = typeof a.checked == "boolean";
35312 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35313 var colcls = 'x-t-' + tid + '-c0';
35315 '<li class="x-tree-node">',
35318 '<div class="x-tree-node-el ', a.cls,'">',
35320 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35323 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35324 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35325 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35326 (a.icon ? ' x-tree-node-inline-icon' : ''),
35327 (a.iconCls ? ' '+a.iconCls : ''),
35328 '" unselectable="on" />',
35329 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35330 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35332 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35333 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35334 '<span unselectable="on" qtip="' + tx + '">',
35338 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35339 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35341 for(var i = 1, len = cols.length; i < len; i++){
35343 colcls = 'x-t-' + tid + '-c' +i;
35344 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35345 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35346 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35352 '<div class="x-clear"></div></div>',
35353 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35356 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35357 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35358 n.nextSibling.ui.getEl(), buf.join(""));
35360 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35362 var el = this.wrap.firstChild;
35364 this.elNode = el.firstChild;
35365 this.ranchor = el.childNodes[1];
35366 this.ctNode = this.wrap.childNodes[1];
35367 var cs = el.firstChild.childNodes;
35368 this.indentNode = cs[0];
35369 this.ecNode = cs[1];
35370 this.iconNode = cs[2];
35373 this.checkbox = cs[3];
35376 this.anchor = cs[index];
35378 this.textNode = cs[index].firstChild;
35380 //el.on("click", this.onClick, this);
35381 //el.on("dblclick", this.onDblClick, this);
35384 // console.log(this);
35386 initEvents : function(){
35387 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35390 var a = this.ranchor;
35392 var el = Roo.get(a);
35394 if(Roo.isOpera){ // opera render bug ignores the CSS
35395 el.setStyle("text-decoration", "none");
35398 el.on("click", this.onClick, this);
35399 el.on("dblclick", this.onDblClick, this);
35400 el.on("contextmenu", this.onContextMenu, this);
35404 /*onSelectedChange : function(state){
35407 this.addClass("x-tree-selected");
35410 this.removeClass("x-tree-selected");
35413 addClass : function(cls){
35415 Roo.fly(this.elRow).addClass(cls);
35421 removeClass : function(cls){
35423 Roo.fly(this.elRow).removeClass(cls);
35429 });//<Script type="text/javascript">
35433 * Ext JS Library 1.1.1
35434 * Copyright(c) 2006-2007, Ext JS, LLC.
35436 * Originally Released Under LGPL - original licence link has changed is not relivant.
35439 * <script type="text/javascript">
35444 * @class Roo.tree.ColumnTree
35445 * @extends Roo.data.TreePanel
35446 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35447 * @cfg {int} borderWidth compined right/left border allowance
35449 * @param {String/HTMLElement/Element} el The container element
35450 * @param {Object} config
35452 Roo.tree.ColumnTree = function(el, config)
35454 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35458 * Fire this event on a container when it resizes
35459 * @param {int} w Width
35460 * @param {int} h Height
35464 this.on('resize', this.onResize, this);
35467 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35471 borderWidth: Roo.isBorderBox ? 0 : 2,
35474 render : function(){
35475 // add the header.....
35477 Roo.tree.ColumnTree.superclass.render.apply(this);
35479 this.el.addClass('x-column-tree');
35481 this.headers = this.el.createChild(
35482 {cls:'x-tree-headers'},this.innerCt.dom);
35484 var cols = this.columns, c;
35485 var totalWidth = 0;
35487 var len = cols.length;
35488 for(var i = 0; i < len; i++){
35490 totalWidth += c.width;
35491 this.headEls.push(this.headers.createChild({
35492 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35494 cls:'x-tree-hd-text',
35497 style:'width:'+(c.width-this.borderWidth)+'px;'
35500 this.headers.createChild({cls:'x-clear'});
35501 // prevent floats from wrapping when clipped
35502 this.headers.setWidth(totalWidth);
35503 //this.innerCt.setWidth(totalWidth);
35504 this.innerCt.setStyle({ overflow: 'auto' });
35505 this.onResize(this.width, this.height);
35509 onResize : function(w,h)
35514 this.innerCt.setWidth(this.width);
35515 this.innerCt.setHeight(this.height-20);
35518 var cols = this.columns, c;
35519 var totalWidth = 0;
35521 var len = cols.length;
35522 for(var i = 0; i < len; i++){
35524 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35525 // it's the expander..
35526 expEl = this.headEls[i];
35529 totalWidth += c.width;
35533 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35535 this.headers.setWidth(w-20);
35544 * Ext JS Library 1.1.1
35545 * Copyright(c) 2006-2007, Ext JS, LLC.
35547 * Originally Released Under LGPL - original licence link has changed is not relivant.
35550 * <script type="text/javascript">
35554 * @class Roo.menu.Menu
35555 * @extends Roo.util.Observable
35556 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35557 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35559 * Creates a new Menu
35560 * @param {Object} config Configuration options
35562 Roo.menu.Menu = function(config){
35563 Roo.apply(this, config);
35564 this.id = this.id || Roo.id();
35567 * @event beforeshow
35568 * Fires before this menu is displayed
35569 * @param {Roo.menu.Menu} this
35573 * @event beforehide
35574 * Fires before this menu is hidden
35575 * @param {Roo.menu.Menu} this
35580 * Fires after this menu is displayed
35581 * @param {Roo.menu.Menu} this
35586 * Fires after this menu is hidden
35587 * @param {Roo.menu.Menu} this
35592 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35593 * @param {Roo.menu.Menu} this
35594 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35595 * @param {Roo.EventObject} e
35600 * Fires when the mouse is hovering over this menu
35601 * @param {Roo.menu.Menu} this
35602 * @param {Roo.EventObject} e
35603 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35608 * Fires when the mouse exits this menu
35609 * @param {Roo.menu.Menu} this
35610 * @param {Roo.EventObject} e
35611 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35616 * Fires when a menu item contained in this menu is clicked
35617 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35618 * @param {Roo.EventObject} e
35622 if (this.registerMenu) {
35623 Roo.menu.MenuMgr.register(this);
35626 var mis = this.items;
35627 this.items = new Roo.util.MixedCollection();
35629 this.add.apply(this, mis);
35633 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35635 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35639 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35640 * for bottom-right shadow (defaults to "sides")
35644 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35645 * this menu (defaults to "tl-tr?")
35647 subMenuAlign : "tl-tr?",
35649 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35650 * relative to its element of origin (defaults to "tl-bl?")
35652 defaultAlign : "tl-bl?",
35654 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35656 allowOtherMenus : false,
35658 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35660 registerMenu : true,
35665 render : function(){
35669 var el = this.el = new Roo.Layer({
35671 shadow:this.shadow,
35673 parentEl: this.parentEl || document.body,
35677 this.keyNav = new Roo.menu.MenuNav(this);
35680 el.addClass("x-menu-plain");
35683 el.addClass(this.cls);
35685 // generic focus element
35686 this.focusEl = el.createChild({
35687 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35689 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35690 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35692 ul.on("mouseover", this.onMouseOver, this);
35693 ul.on("mouseout", this.onMouseOut, this);
35694 this.items.each(function(item){
35699 var li = document.createElement("li");
35700 li.className = "x-menu-list-item";
35701 ul.dom.appendChild(li);
35702 item.render(li, this);
35709 autoWidth : function(){
35710 var el = this.el, ul = this.ul;
35714 var w = this.width;
35717 }else if(Roo.isIE){
35718 el.setWidth(this.minWidth);
35719 var t = el.dom.offsetWidth; // force recalc
35720 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35725 delayAutoWidth : function(){
35728 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35730 this.awTask.delay(20);
35735 findTargetItem : function(e){
35736 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35737 if(t && t.menuItemId){
35738 return this.items.get(t.menuItemId);
35743 onClick : function(e){
35744 Roo.log("menu.onClick");
35745 var t = this.findTargetItem(e);
35750 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35751 if(t == this.activeItem && t.shouldDeactivate(e)){
35752 this.activeItem.deactivate();
35753 delete this.activeItem;
35757 this.setActiveItem(t, true);
35765 this.fireEvent("click", this, t, e);
35769 setActiveItem : function(item, autoExpand){
35770 if(item != this.activeItem){
35771 if(this.activeItem){
35772 this.activeItem.deactivate();
35774 this.activeItem = item;
35775 item.activate(autoExpand);
35776 }else if(autoExpand){
35782 tryActivate : function(start, step){
35783 var items = this.items;
35784 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35785 var item = items.get(i);
35786 if(!item.disabled && item.canActivate){
35787 this.setActiveItem(item, false);
35795 onMouseOver : function(e){
35797 if(t = this.findTargetItem(e)){
35798 if(t.canActivate && !t.disabled){
35799 this.setActiveItem(t, true);
35802 this.fireEvent("mouseover", this, e, t);
35806 onMouseOut : function(e){
35808 if(t = this.findTargetItem(e)){
35809 if(t == this.activeItem && t.shouldDeactivate(e)){
35810 this.activeItem.deactivate();
35811 delete this.activeItem;
35814 this.fireEvent("mouseout", this, e, t);
35818 * Read-only. Returns true if the menu is currently displayed, else false.
35821 isVisible : function(){
35822 return this.el && !this.hidden;
35826 * Displays this menu relative to another element
35827 * @param {String/HTMLElement/Roo.Element} element The element to align to
35828 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35829 * the element (defaults to this.defaultAlign)
35830 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35832 show : function(el, pos, parentMenu){
35833 this.parentMenu = parentMenu;
35837 this.fireEvent("beforeshow", this);
35838 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35842 * Displays this menu at a specific xy position
35843 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35844 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35846 showAt : function(xy, parentMenu, /* private: */_e){
35847 this.parentMenu = parentMenu;
35852 this.fireEvent("beforeshow", this);
35853 xy = this.el.adjustForConstraints(xy);
35857 this.hidden = false;
35859 this.fireEvent("show", this);
35862 focus : function(){
35864 this.doFocus.defer(50, this);
35868 doFocus : function(){
35870 this.focusEl.focus();
35875 * Hides this menu and optionally all parent menus
35876 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35878 hide : function(deep){
35879 if(this.el && this.isVisible()){
35880 this.fireEvent("beforehide", this);
35881 if(this.activeItem){
35882 this.activeItem.deactivate();
35883 this.activeItem = null;
35886 this.hidden = true;
35887 this.fireEvent("hide", this);
35889 if(deep === true && this.parentMenu){
35890 this.parentMenu.hide(true);
35895 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35896 * Any of the following are valid:
35898 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35899 * <li>An HTMLElement object which will be converted to a menu item</li>
35900 * <li>A menu item config object that will be created as a new menu item</li>
35901 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35902 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35907 var menu = new Roo.menu.Menu();
35909 // Create a menu item to add by reference
35910 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35912 // Add a bunch of items at once using different methods.
35913 // Only the last item added will be returned.
35914 var item = menu.add(
35915 menuItem, // add existing item by ref
35916 'Dynamic Item', // new TextItem
35917 '-', // new separator
35918 { text: 'Config Item' } // new item by config
35921 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35922 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35925 var a = arguments, l = a.length, item;
35926 for(var i = 0; i < l; i++){
35928 if ((typeof(el) == "object") && el.xtype && el.xns) {
35929 el = Roo.factory(el, Roo.menu);
35932 if(el.render){ // some kind of Item
35933 item = this.addItem(el);
35934 }else if(typeof el == "string"){ // string
35935 if(el == "separator" || el == "-"){
35936 item = this.addSeparator();
35938 item = this.addText(el);
35940 }else if(el.tagName || el.el){ // element
35941 item = this.addElement(el);
35942 }else if(typeof el == "object"){ // must be menu item config?
35943 item = this.addMenuItem(el);
35950 * Returns this menu's underlying {@link Roo.Element} object
35951 * @return {Roo.Element} The element
35953 getEl : function(){
35961 * Adds a separator bar to the menu
35962 * @return {Roo.menu.Item} The menu item that was added
35964 addSeparator : function(){
35965 return this.addItem(new Roo.menu.Separator());
35969 * Adds an {@link Roo.Element} object to the menu
35970 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35971 * @return {Roo.menu.Item} The menu item that was added
35973 addElement : function(el){
35974 return this.addItem(new Roo.menu.BaseItem(el));
35978 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35979 * @param {Roo.menu.Item} item The menu item to add
35980 * @return {Roo.menu.Item} The menu item that was added
35982 addItem : function(item){
35983 this.items.add(item);
35985 var li = document.createElement("li");
35986 li.className = "x-menu-list-item";
35987 this.ul.dom.appendChild(li);
35988 item.render(li, this);
35989 this.delayAutoWidth();
35995 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35996 * @param {Object} config A MenuItem config object
35997 * @return {Roo.menu.Item} The menu item that was added
35999 addMenuItem : function(config){
36000 if(!(config instanceof Roo.menu.Item)){
36001 if(typeof config.checked == "boolean"){ // must be check menu item config?
36002 config = new Roo.menu.CheckItem(config);
36004 config = new Roo.menu.Item(config);
36007 return this.addItem(config);
36011 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36012 * @param {String} text The text to display in the menu item
36013 * @return {Roo.menu.Item} The menu item that was added
36015 addText : function(text){
36016 return this.addItem(new Roo.menu.TextItem({ text : text }));
36020 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36021 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36022 * @param {Roo.menu.Item} item The menu item to add
36023 * @return {Roo.menu.Item} The menu item that was added
36025 insert : function(index, item){
36026 this.items.insert(index, item);
36028 var li = document.createElement("li");
36029 li.className = "x-menu-list-item";
36030 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36031 item.render(li, this);
36032 this.delayAutoWidth();
36038 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36039 * @param {Roo.menu.Item} item The menu item to remove
36041 remove : function(item){
36042 this.items.removeKey(item.id);
36047 * Removes and destroys all items in the menu
36049 removeAll : function(){
36051 while(f = this.items.first()){
36057 // MenuNav is a private utility class used internally by the Menu
36058 Roo.menu.MenuNav = function(menu){
36059 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36060 this.scope = this.menu = menu;
36063 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36064 doRelay : function(e, h){
36065 var k = e.getKey();
36066 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36067 this.menu.tryActivate(0, 1);
36070 return h.call(this.scope || this, e, this.menu);
36073 up : function(e, m){
36074 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36075 m.tryActivate(m.items.length-1, -1);
36079 down : function(e, m){
36080 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36081 m.tryActivate(0, 1);
36085 right : function(e, m){
36087 m.activeItem.expandMenu(true);
36091 left : function(e, m){
36093 if(m.parentMenu && m.parentMenu.activeItem){
36094 m.parentMenu.activeItem.activate();
36098 enter : function(e, m){
36100 e.stopPropagation();
36101 m.activeItem.onClick(e);
36102 m.fireEvent("click", this, m.activeItem);
36108 * Ext JS Library 1.1.1
36109 * Copyright(c) 2006-2007, Ext JS, LLC.
36111 * Originally Released Under LGPL - original licence link has changed is not relivant.
36114 * <script type="text/javascript">
36118 * @class Roo.menu.MenuMgr
36119 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36122 Roo.menu.MenuMgr = function(){
36123 var menus, active, groups = {}, attached = false, lastShow = new Date();
36125 // private - called when first menu is created
36128 active = new Roo.util.MixedCollection();
36129 Roo.get(document).addKeyListener(27, function(){
36130 if(active.length > 0){
36137 function hideAll(){
36138 if(active && active.length > 0){
36139 var c = active.clone();
36140 c.each(function(m){
36147 function onHide(m){
36149 if(active.length < 1){
36150 Roo.get(document).un("mousedown", onMouseDown);
36156 function onShow(m){
36157 var last = active.last();
36158 lastShow = new Date();
36161 Roo.get(document).on("mousedown", onMouseDown);
36165 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36166 m.parentMenu.activeChild = m;
36167 }else if(last && last.isVisible()){
36168 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36173 function onBeforeHide(m){
36175 m.activeChild.hide();
36177 if(m.autoHideTimer){
36178 clearTimeout(m.autoHideTimer);
36179 delete m.autoHideTimer;
36184 function onBeforeShow(m){
36185 var pm = m.parentMenu;
36186 if(!pm && !m.allowOtherMenus){
36188 }else if(pm && pm.activeChild && active != m){
36189 pm.activeChild.hide();
36194 function onMouseDown(e){
36195 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36201 function onBeforeCheck(mi, state){
36203 var g = groups[mi.group];
36204 for(var i = 0, l = g.length; i < l; i++){
36206 g[i].setChecked(false);
36215 * Hides all menus that are currently visible
36217 hideAll : function(){
36222 register : function(menu){
36226 menus[menu.id] = menu;
36227 menu.on("beforehide", onBeforeHide);
36228 menu.on("hide", onHide);
36229 menu.on("beforeshow", onBeforeShow);
36230 menu.on("show", onShow);
36231 var g = menu.group;
36232 if(g && menu.events["checkchange"]){
36236 groups[g].push(menu);
36237 menu.on("checkchange", onCheck);
36242 * Returns a {@link Roo.menu.Menu} object
36243 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36244 * be used to generate and return a new Menu instance.
36246 get : function(menu){
36247 if(typeof menu == "string"){ // menu id
36248 return menus[menu];
36249 }else if(menu.events){ // menu instance
36251 }else if(typeof menu.length == 'number'){ // array of menu items?
36252 return new Roo.menu.Menu({items:menu});
36253 }else{ // otherwise, must be a config
36254 return new Roo.menu.Menu(menu);
36259 unregister : function(menu){
36260 delete menus[menu.id];
36261 menu.un("beforehide", onBeforeHide);
36262 menu.un("hide", onHide);
36263 menu.un("beforeshow", onBeforeShow);
36264 menu.un("show", onShow);
36265 var g = menu.group;
36266 if(g && menu.events["checkchange"]){
36267 groups[g].remove(menu);
36268 menu.un("checkchange", onCheck);
36273 registerCheckable : function(menuItem){
36274 var g = menuItem.group;
36279 groups[g].push(menuItem);
36280 menuItem.on("beforecheckchange", onBeforeCheck);
36285 unregisterCheckable : function(menuItem){
36286 var g = menuItem.group;
36288 groups[g].remove(menuItem);
36289 menuItem.un("beforecheckchange", onBeforeCheck);
36295 * Ext JS Library 1.1.1
36296 * Copyright(c) 2006-2007, Ext JS, LLC.
36298 * Originally Released Under LGPL - original licence link has changed is not relivant.
36301 * <script type="text/javascript">
36306 * @class Roo.menu.BaseItem
36307 * @extends Roo.Component
36308 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36309 * management and base configuration options shared by all menu components.
36311 * Creates a new BaseItem
36312 * @param {Object} config Configuration options
36314 Roo.menu.BaseItem = function(config){
36315 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36320 * Fires when this item is clicked
36321 * @param {Roo.menu.BaseItem} this
36322 * @param {Roo.EventObject} e
36327 * Fires when this item is activated
36328 * @param {Roo.menu.BaseItem} this
36332 * @event deactivate
36333 * Fires when this item is deactivated
36334 * @param {Roo.menu.BaseItem} this
36340 this.on("click", this.handler, this.scope, true);
36344 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36346 * @cfg {Function} handler
36347 * A function that will handle the click event of this menu item (defaults to undefined)
36350 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36352 canActivate : false,
36355 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36360 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36362 activeClass : "x-menu-item-active",
36364 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36366 hideOnClick : true,
36368 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36373 ctype: "Roo.menu.BaseItem",
36376 actionMode : "container",
36379 render : function(container, parentMenu){
36380 this.parentMenu = parentMenu;
36381 Roo.menu.BaseItem.superclass.render.call(this, container);
36382 this.container.menuItemId = this.id;
36386 onRender : function(container, position){
36387 this.el = Roo.get(this.el);
36388 container.dom.appendChild(this.el.dom);
36392 onClick : function(e){
36393 if(!this.disabled && this.fireEvent("click", this, e) !== false
36394 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36395 this.handleClick(e);
36402 activate : function(){
36406 var li = this.container;
36407 li.addClass(this.activeClass);
36408 this.region = li.getRegion().adjust(2, 2, -2, -2);
36409 this.fireEvent("activate", this);
36414 deactivate : function(){
36415 this.container.removeClass(this.activeClass);
36416 this.fireEvent("deactivate", this);
36420 shouldDeactivate : function(e){
36421 return !this.region || !this.region.contains(e.getPoint());
36425 handleClick : function(e){
36426 if(this.hideOnClick){
36427 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36432 expandMenu : function(autoActivate){
36437 hideMenu : function(){
36442 * Ext JS Library 1.1.1
36443 * Copyright(c) 2006-2007, Ext JS, LLC.
36445 * Originally Released Under LGPL - original licence link has changed is not relivant.
36448 * <script type="text/javascript">
36452 * @class Roo.menu.Adapter
36453 * @extends Roo.menu.BaseItem
36454 * 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.
36455 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36457 * Creates a new Adapter
36458 * @param {Object} config Configuration options
36460 Roo.menu.Adapter = function(component, config){
36461 Roo.menu.Adapter.superclass.constructor.call(this, config);
36462 this.component = component;
36464 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36466 canActivate : true,
36469 onRender : function(container, position){
36470 this.component.render(container);
36471 this.el = this.component.getEl();
36475 activate : function(){
36479 this.component.focus();
36480 this.fireEvent("activate", this);
36485 deactivate : function(){
36486 this.fireEvent("deactivate", this);
36490 disable : function(){
36491 this.component.disable();
36492 Roo.menu.Adapter.superclass.disable.call(this);
36496 enable : function(){
36497 this.component.enable();
36498 Roo.menu.Adapter.superclass.enable.call(this);
36502 * Ext JS Library 1.1.1
36503 * Copyright(c) 2006-2007, Ext JS, LLC.
36505 * Originally Released Under LGPL - original licence link has changed is not relivant.
36508 * <script type="text/javascript">
36512 * @class Roo.menu.TextItem
36513 * @extends Roo.menu.BaseItem
36514 * Adds a static text string to a menu, usually used as either a heading or group separator.
36515 * Note: old style constructor with text is still supported.
36518 * Creates a new TextItem
36519 * @param {Object} cfg Configuration
36521 Roo.menu.TextItem = function(cfg){
36522 if (typeof(cfg) == 'string') {
36525 Roo.apply(this,cfg);
36528 Roo.menu.TextItem.superclass.constructor.call(this);
36531 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36533 * @cfg {Boolean} text Text to show on item.
36538 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36540 hideOnClick : false,
36542 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36544 itemCls : "x-menu-text",
36547 onRender : function(){
36548 var s = document.createElement("span");
36549 s.className = this.itemCls;
36550 s.innerHTML = this.text;
36552 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36556 * Ext JS Library 1.1.1
36557 * Copyright(c) 2006-2007, Ext JS, LLC.
36559 * Originally Released Under LGPL - original licence link has changed is not relivant.
36562 * <script type="text/javascript">
36566 * @class Roo.menu.Separator
36567 * @extends Roo.menu.BaseItem
36568 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36569 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36571 * @param {Object} config Configuration options
36573 Roo.menu.Separator = function(config){
36574 Roo.menu.Separator.superclass.constructor.call(this, config);
36577 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36579 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36581 itemCls : "x-menu-sep",
36583 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36585 hideOnClick : false,
36588 onRender : function(li){
36589 var s = document.createElement("span");
36590 s.className = this.itemCls;
36591 s.innerHTML = " ";
36593 li.addClass("x-menu-sep-li");
36594 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36598 * Ext JS Library 1.1.1
36599 * Copyright(c) 2006-2007, Ext JS, LLC.
36601 * Originally Released Under LGPL - original licence link has changed is not relivant.
36604 * <script type="text/javascript">
36607 * @class Roo.menu.Item
36608 * @extends Roo.menu.BaseItem
36609 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36610 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36611 * activation and click handling.
36613 * Creates a new Item
36614 * @param {Object} config Configuration options
36616 Roo.menu.Item = function(config){
36617 Roo.menu.Item.superclass.constructor.call(this, config);
36619 this.menu = Roo.menu.MenuMgr.get(this.menu);
36622 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36625 * @cfg {String} text
36626 * The text to show on the menu item.
36630 * @cfg {String} HTML to render in menu
36631 * The text to show on the menu item (HTML version).
36635 * @cfg {String} icon
36636 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36640 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36642 itemCls : "x-menu-item",
36644 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36646 canActivate : true,
36648 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36651 // doc'd in BaseItem
36655 ctype: "Roo.menu.Item",
36658 onRender : function(container, position){
36659 var el = document.createElement("a");
36660 el.hideFocus = true;
36661 el.unselectable = "on";
36662 el.href = this.href || "#";
36663 if(this.hrefTarget){
36664 el.target = this.hrefTarget;
36666 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36668 var html = this.html.length ? this.html : String.format('{0}',this.text);
36670 el.innerHTML = String.format(
36671 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36672 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36674 Roo.menu.Item.superclass.onRender.call(this, container, position);
36678 * Sets the text to display in this menu item
36679 * @param {String} text The text to display
36680 * @param {Boolean} isHTML true to indicate text is pure html.
36682 setText : function(text, isHTML){
36690 var html = this.html.length ? this.html : String.format('{0}',this.text);
36692 this.el.update(String.format(
36693 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36694 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36695 this.parentMenu.autoWidth();
36700 handleClick : function(e){
36701 if(!this.href){ // if no link defined, stop the event automatically
36704 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36708 activate : function(autoExpand){
36709 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36719 shouldDeactivate : function(e){
36720 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36721 if(this.menu && this.menu.isVisible()){
36722 return !this.menu.getEl().getRegion().contains(e.getPoint());
36730 deactivate : function(){
36731 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36736 expandMenu : function(autoActivate){
36737 if(!this.disabled && this.menu){
36738 clearTimeout(this.hideTimer);
36739 delete this.hideTimer;
36740 if(!this.menu.isVisible() && !this.showTimer){
36741 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36742 }else if (this.menu.isVisible() && autoActivate){
36743 this.menu.tryActivate(0, 1);
36749 deferExpand : function(autoActivate){
36750 delete this.showTimer;
36751 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36753 this.menu.tryActivate(0, 1);
36758 hideMenu : function(){
36759 clearTimeout(this.showTimer);
36760 delete this.showTimer;
36761 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36762 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36767 deferHide : function(){
36768 delete this.hideTimer;
36773 * Ext JS Library 1.1.1
36774 * Copyright(c) 2006-2007, Ext JS, LLC.
36776 * Originally Released Under LGPL - original licence link has changed is not relivant.
36779 * <script type="text/javascript">
36783 * @class Roo.menu.CheckItem
36784 * @extends Roo.menu.Item
36785 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36787 * Creates a new CheckItem
36788 * @param {Object} config Configuration options
36790 Roo.menu.CheckItem = function(config){
36791 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36794 * @event beforecheckchange
36795 * Fires before the checked value is set, providing an opportunity to cancel if needed
36796 * @param {Roo.menu.CheckItem} this
36797 * @param {Boolean} checked The new checked value that will be set
36799 "beforecheckchange" : true,
36801 * @event checkchange
36802 * Fires after the checked value has been set
36803 * @param {Roo.menu.CheckItem} this
36804 * @param {Boolean} checked The checked value that was set
36806 "checkchange" : true
36808 if(this.checkHandler){
36809 this.on('checkchange', this.checkHandler, this.scope);
36812 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36814 * @cfg {String} group
36815 * All check items with the same group name will automatically be grouped into a single-select
36816 * radio button group (defaults to '')
36819 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36821 itemCls : "x-menu-item x-menu-check-item",
36823 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36825 groupClass : "x-menu-group-item",
36828 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36829 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36830 * initialized with checked = true will be rendered as checked.
36835 ctype: "Roo.menu.CheckItem",
36838 onRender : function(c){
36839 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36841 this.el.addClass(this.groupClass);
36843 Roo.menu.MenuMgr.registerCheckable(this);
36845 this.checked = false;
36846 this.setChecked(true, true);
36851 destroy : function(){
36853 Roo.menu.MenuMgr.unregisterCheckable(this);
36855 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36859 * Set the checked state of this item
36860 * @param {Boolean} checked The new checked value
36861 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36863 setChecked : function(state, suppressEvent){
36864 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36865 if(this.container){
36866 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36868 this.checked = state;
36869 if(suppressEvent !== true){
36870 this.fireEvent("checkchange", this, state);
36876 handleClick : function(e){
36877 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36878 this.setChecked(!this.checked);
36880 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36884 * Ext JS Library 1.1.1
36885 * Copyright(c) 2006-2007, Ext JS, LLC.
36887 * Originally Released Under LGPL - original licence link has changed is not relivant.
36890 * <script type="text/javascript">
36894 * @class Roo.menu.DateItem
36895 * @extends Roo.menu.Adapter
36896 * A menu item that wraps the {@link Roo.DatPicker} component.
36898 * Creates a new DateItem
36899 * @param {Object} config Configuration options
36901 Roo.menu.DateItem = function(config){
36902 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36903 /** The Roo.DatePicker object @type Roo.DatePicker */
36904 this.picker = this.component;
36905 this.addEvents({select: true});
36907 this.picker.on("render", function(picker){
36908 picker.getEl().swallowEvent("click");
36909 picker.container.addClass("x-menu-date-item");
36912 this.picker.on("select", this.onSelect, this);
36915 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36917 onSelect : function(picker, date){
36918 this.fireEvent("select", this, date, picker);
36919 Roo.menu.DateItem.superclass.handleClick.call(this);
36923 * Ext JS Library 1.1.1
36924 * Copyright(c) 2006-2007, Ext JS, LLC.
36926 * Originally Released Under LGPL - original licence link has changed is not relivant.
36929 * <script type="text/javascript">
36933 * @class Roo.menu.ColorItem
36934 * @extends Roo.menu.Adapter
36935 * A menu item that wraps the {@link Roo.ColorPalette} component.
36937 * Creates a new ColorItem
36938 * @param {Object} config Configuration options
36940 Roo.menu.ColorItem = function(config){
36941 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36942 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36943 this.palette = this.component;
36944 this.relayEvents(this.palette, ["select"]);
36945 if(this.selectHandler){
36946 this.on('select', this.selectHandler, this.scope);
36949 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36951 * Ext JS Library 1.1.1
36952 * Copyright(c) 2006-2007, Ext JS, LLC.
36954 * Originally Released Under LGPL - original licence link has changed is not relivant.
36957 * <script type="text/javascript">
36962 * @class Roo.menu.DateMenu
36963 * @extends Roo.menu.Menu
36964 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36966 * Creates a new DateMenu
36967 * @param {Object} config Configuration options
36969 Roo.menu.DateMenu = function(config){
36970 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36972 var di = new Roo.menu.DateItem(config);
36975 * The {@link Roo.DatePicker} instance for this DateMenu
36978 this.picker = di.picker;
36981 * @param {DatePicker} picker
36982 * @param {Date} date
36984 this.relayEvents(di, ["select"]);
36985 this.on('beforeshow', function(){
36987 this.picker.hideMonthPicker(false);
36991 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36995 * Ext JS Library 1.1.1
36996 * Copyright(c) 2006-2007, Ext JS, LLC.
36998 * Originally Released Under LGPL - original licence link has changed is not relivant.
37001 * <script type="text/javascript">
37006 * @class Roo.menu.ColorMenu
37007 * @extends Roo.menu.Menu
37008 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37010 * Creates a new ColorMenu
37011 * @param {Object} config Configuration options
37013 Roo.menu.ColorMenu = function(config){
37014 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37016 var ci = new Roo.menu.ColorItem(config);
37019 * The {@link Roo.ColorPalette} instance for this ColorMenu
37020 * @type ColorPalette
37022 this.palette = ci.palette;
37025 * @param {ColorPalette} palette
37026 * @param {String} color
37028 this.relayEvents(ci, ["select"]);
37030 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37032 * Ext JS Library 1.1.1
37033 * Copyright(c) 2006-2007, Ext JS, LLC.
37035 * Originally Released Under LGPL - original licence link has changed is not relivant.
37038 * <script type="text/javascript">
37042 * @class Roo.form.Field
37043 * @extends Roo.BoxComponent
37044 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37046 * Creates a new Field
37047 * @param {Object} config Configuration options
37049 Roo.form.Field = function(config){
37050 Roo.form.Field.superclass.constructor.call(this, config);
37053 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37055 * @cfg {String} fieldLabel Label to use when rendering a form.
37058 * @cfg {String} qtip Mouse over tip
37062 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37064 invalidClass : "x-form-invalid",
37066 * @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")
37068 invalidText : "The value in this field is invalid",
37070 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37072 focusClass : "x-form-focus",
37074 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37075 automatic validation (defaults to "keyup").
37077 validationEvent : "keyup",
37079 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37081 validateOnBlur : true,
37083 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37085 validationDelay : 250,
37087 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37088 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37090 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37092 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37094 fieldClass : "x-form-field",
37096 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37099 ----------- ----------------------------------------------------------------------
37100 qtip Display a quick tip when the user hovers over the field
37101 title Display a default browser title attribute popup
37102 under Add a block div beneath the field containing the error text
37103 side Add an error icon to the right of the field with a popup on hover
37104 [element id] Add the error text directly to the innerHTML of the specified element
37107 msgTarget : 'qtip',
37109 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37114 * @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.
37119 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37124 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37126 inputType : undefined,
37129 * @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).
37131 tabIndex : undefined,
37134 isFormField : true,
37139 * @property {Roo.Element} fieldEl
37140 * Element Containing the rendered Field (with label etc.)
37143 * @cfg {Mixed} value A value to initialize this field with.
37148 * @cfg {String} name The field's HTML name attribute.
37151 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37155 initComponent : function(){
37156 Roo.form.Field.superclass.initComponent.call(this);
37160 * Fires when this field receives input focus.
37161 * @param {Roo.form.Field} this
37166 * Fires when this field loses input focus.
37167 * @param {Roo.form.Field} this
37171 * @event specialkey
37172 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37173 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37174 * @param {Roo.form.Field} this
37175 * @param {Roo.EventObject} e The event object
37180 * Fires just before the field blurs if the field value has changed.
37181 * @param {Roo.form.Field} this
37182 * @param {Mixed} newValue The new value
37183 * @param {Mixed} oldValue The original value
37188 * Fires after the field has been marked as invalid.
37189 * @param {Roo.form.Field} this
37190 * @param {String} msg The validation message
37195 * Fires after the field has been validated with no errors.
37196 * @param {Roo.form.Field} this
37201 * Fires after the key up
37202 * @param {Roo.form.Field} this
37203 * @param {Roo.EventObject} e The event Object
37210 * Returns the name attribute of the field if available
37211 * @return {String} name The field name
37213 getName: function(){
37214 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37218 onRender : function(ct, position){
37219 Roo.form.Field.superclass.onRender.call(this, ct, position);
37221 var cfg = this.getAutoCreate();
37223 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37225 if (!cfg.name.length) {
37228 if(this.inputType){
37229 cfg.type = this.inputType;
37231 this.el = ct.createChild(cfg, position);
37233 var type = this.el.dom.type;
37235 if(type == 'password'){
37238 this.el.addClass('x-form-'+type);
37241 this.el.dom.readOnly = true;
37243 if(this.tabIndex !== undefined){
37244 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37247 this.el.addClass([this.fieldClass, this.cls]);
37252 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37253 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37254 * @return {Roo.form.Field} this
37256 applyTo : function(target){
37257 this.allowDomMove = false;
37258 this.el = Roo.get(target);
37259 this.render(this.el.dom.parentNode);
37264 initValue : function(){
37265 if(this.value !== undefined){
37266 this.setValue(this.value);
37267 }else if(this.el.dom.value.length > 0){
37268 this.setValue(this.el.dom.value);
37273 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37275 isDirty : function() {
37276 if(this.disabled) {
37279 return String(this.getValue()) !== String(this.originalValue);
37283 afterRender : function(){
37284 Roo.form.Field.superclass.afterRender.call(this);
37289 fireKey : function(e){
37290 //Roo.log('field ' + e.getKey());
37291 if(e.isNavKeyPress()){
37292 this.fireEvent("specialkey", this, e);
37297 * Resets the current field value to the originally loaded value and clears any validation messages
37299 reset : function(){
37300 this.setValue(this.resetValue);
37301 this.clearInvalid();
37305 initEvents : function(){
37306 // safari killled keypress - so keydown is now used..
37307 this.el.on("keydown" , this.fireKey, this);
37308 this.el.on("focus", this.onFocus, this);
37309 this.el.on("blur", this.onBlur, this);
37310 this.el.relayEvent('keyup', this);
37312 // reference to original value for reset
37313 this.originalValue = this.getValue();
37314 this.resetValue = this.getValue();
37318 onFocus : function(){
37319 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37320 this.el.addClass(this.focusClass);
37322 if(!this.hasFocus){
37323 this.hasFocus = true;
37324 this.startValue = this.getValue();
37325 this.fireEvent("focus", this);
37329 beforeBlur : Roo.emptyFn,
37332 onBlur : function(){
37334 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37335 this.el.removeClass(this.focusClass);
37337 this.hasFocus = false;
37338 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37341 var v = this.getValue();
37342 if(String(v) !== String(this.startValue)){
37343 this.fireEvent('change', this, v, this.startValue);
37345 this.fireEvent("blur", this);
37349 * Returns whether or not the field value is currently valid
37350 * @param {Boolean} preventMark True to disable marking the field invalid
37351 * @return {Boolean} True if the value is valid, else false
37353 isValid : function(preventMark){
37357 var restore = this.preventMark;
37358 this.preventMark = preventMark === true;
37359 var v = this.validateValue(this.processValue(this.getRawValue()));
37360 this.preventMark = restore;
37365 * Validates the field value
37366 * @return {Boolean} True if the value is valid, else false
37368 validate : function(){
37369 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37370 this.clearInvalid();
37376 processValue : function(value){
37381 // Subclasses should provide the validation implementation by overriding this
37382 validateValue : function(value){
37387 * Mark this field as invalid
37388 * @param {String} msg The validation message
37390 markInvalid : function(msg){
37391 if(!this.rendered || this.preventMark){ // not rendered
37395 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37397 obj.el.addClass(this.invalidClass);
37398 msg = msg || this.invalidText;
37399 switch(this.msgTarget){
37401 obj.el.dom.qtip = msg;
37402 obj.el.dom.qclass = 'x-form-invalid-tip';
37403 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37404 Roo.QuickTips.enable();
37408 this.el.dom.title = msg;
37412 var elp = this.el.findParent('.x-form-element', 5, true);
37413 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37414 this.errorEl.setWidth(elp.getWidth(true)-20);
37416 this.errorEl.update(msg);
37417 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37420 if(!this.errorIcon){
37421 var elp = this.el.findParent('.x-form-element', 5, true);
37422 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37424 this.alignErrorIcon();
37425 this.errorIcon.dom.qtip = msg;
37426 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37427 this.errorIcon.show();
37428 this.on('resize', this.alignErrorIcon, this);
37431 var t = Roo.getDom(this.msgTarget);
37433 t.style.display = this.msgDisplay;
37436 this.fireEvent('invalid', this, msg);
37440 alignErrorIcon : function(){
37441 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37445 * Clear any invalid styles/messages for this field
37447 clearInvalid : function(){
37448 if(!this.rendered || this.preventMark){ // not rendered
37451 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37453 obj.el.removeClass(this.invalidClass);
37454 switch(this.msgTarget){
37456 obj.el.dom.qtip = '';
37459 this.el.dom.title = '';
37463 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37467 if(this.errorIcon){
37468 this.errorIcon.dom.qtip = '';
37469 this.errorIcon.hide();
37470 this.un('resize', this.alignErrorIcon, this);
37474 var t = Roo.getDom(this.msgTarget);
37476 t.style.display = 'none';
37479 this.fireEvent('valid', this);
37483 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37484 * @return {Mixed} value The field value
37486 getRawValue : function(){
37487 var v = this.el.getValue();
37493 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37494 * @return {Mixed} value The field value
37496 getValue : function(){
37497 var v = this.el.getValue();
37503 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37504 * @param {Mixed} value The value to set
37506 setRawValue : function(v){
37507 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37511 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37512 * @param {Mixed} value The value to set
37514 setValue : function(v){
37517 this.el.dom.value = (v === null || v === undefined ? '' : v);
37522 adjustSize : function(w, h){
37523 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37524 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37528 adjustWidth : function(tag, w){
37529 tag = tag.toLowerCase();
37530 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37531 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37532 if(tag == 'input'){
37535 if(tag == 'textarea'){
37538 }else if(Roo.isOpera){
37539 if(tag == 'input'){
37542 if(tag == 'textarea'){
37552 // anything other than normal should be considered experimental
37553 Roo.form.Field.msgFx = {
37555 show: function(msgEl, f){
37556 msgEl.setDisplayed('block');
37559 hide : function(msgEl, f){
37560 msgEl.setDisplayed(false).update('');
37565 show: function(msgEl, f){
37566 msgEl.slideIn('t', {stopFx:true});
37569 hide : function(msgEl, f){
37570 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37575 show: function(msgEl, f){
37576 msgEl.fixDisplay();
37577 msgEl.alignTo(f.el, 'tl-tr');
37578 msgEl.slideIn('l', {stopFx:true});
37581 hide : function(msgEl, f){
37582 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37587 * Ext JS Library 1.1.1
37588 * Copyright(c) 2006-2007, Ext JS, LLC.
37590 * Originally Released Under LGPL - original licence link has changed is not relivant.
37593 * <script type="text/javascript">
37598 * @class Roo.form.TextField
37599 * @extends Roo.form.Field
37600 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37601 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37603 * Creates a new TextField
37604 * @param {Object} config Configuration options
37606 Roo.form.TextField = function(config){
37607 Roo.form.TextField.superclass.constructor.call(this, config);
37611 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37612 * according to the default logic, but this event provides a hook for the developer to apply additional
37613 * logic at runtime to resize the field if needed.
37614 * @param {Roo.form.Field} this This text field
37615 * @param {Number} width The new field width
37621 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37623 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37627 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37631 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37635 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37639 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37643 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37645 disableKeyFilter : false,
37647 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37651 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37655 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37657 maxLength : Number.MAX_VALUE,
37659 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37661 minLengthText : "The minimum length for this field is {0}",
37663 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37665 maxLengthText : "The maximum length for this field is {0}",
37667 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37669 selectOnFocus : false,
37671 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37673 blankText : "This field is required",
37675 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37676 * If available, this function will be called only after the basic validators all return true, and will be passed the
37677 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37681 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37682 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37683 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37687 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37691 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37697 initEvents : function()
37699 if (this.emptyText) {
37700 this.el.attr('placeholder', this.emptyText);
37703 Roo.form.TextField.superclass.initEvents.call(this);
37704 if(this.validationEvent == 'keyup'){
37705 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37706 this.el.on('keyup', this.filterValidation, this);
37708 else if(this.validationEvent !== false){
37709 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37712 if(this.selectOnFocus){
37713 this.on("focus", this.preFocus, this);
37716 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37717 this.el.on("keypress", this.filterKeys, this);
37720 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37721 this.el.on("click", this.autoSize, this);
37723 if(this.el.is('input[type=password]') && Roo.isSafari){
37724 this.el.on('keydown', this.SafariOnKeyDown, this);
37728 processValue : function(value){
37729 if(this.stripCharsRe){
37730 var newValue = value.replace(this.stripCharsRe, '');
37731 if(newValue !== value){
37732 this.setRawValue(newValue);
37739 filterValidation : function(e){
37740 if(!e.isNavKeyPress()){
37741 this.validationTask.delay(this.validationDelay);
37746 onKeyUp : function(e){
37747 if(!e.isNavKeyPress()){
37753 * Resets the current field value to the originally-loaded value and clears any validation messages.
37756 reset : function(){
37757 Roo.form.TextField.superclass.reset.call(this);
37763 preFocus : function(){
37765 if(this.selectOnFocus){
37766 this.el.dom.select();
37772 filterKeys : function(e){
37773 var k = e.getKey();
37774 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37777 var c = e.getCharCode(), cc = String.fromCharCode(c);
37778 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37781 if(!this.maskRe.test(cc)){
37786 setValue : function(v){
37788 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37794 * Validates a value according to the field's validation rules and marks the field as invalid
37795 * if the validation fails
37796 * @param {Mixed} value The value to validate
37797 * @return {Boolean} True if the value is valid, else false
37799 validateValue : function(value){
37800 if(value.length < 1) { // if it's blank
37801 if(this.allowBlank){
37802 this.clearInvalid();
37805 this.markInvalid(this.blankText);
37809 if(value.length < this.minLength){
37810 this.markInvalid(String.format(this.minLengthText, this.minLength));
37813 if(value.length > this.maxLength){
37814 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37818 var vt = Roo.form.VTypes;
37819 if(!vt[this.vtype](value, this)){
37820 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37824 if(typeof this.validator == "function"){
37825 var msg = this.validator(value);
37827 this.markInvalid(msg);
37831 if(this.regex && !this.regex.test(value)){
37832 this.markInvalid(this.regexText);
37839 * Selects text in this field
37840 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37841 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37843 selectText : function(start, end){
37844 var v = this.getRawValue();
37846 start = start === undefined ? 0 : start;
37847 end = end === undefined ? v.length : end;
37848 var d = this.el.dom;
37849 if(d.setSelectionRange){
37850 d.setSelectionRange(start, end);
37851 }else if(d.createTextRange){
37852 var range = d.createTextRange();
37853 range.moveStart("character", start);
37854 range.moveEnd("character", v.length-end);
37861 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37862 * This only takes effect if grow = true, and fires the autosize event.
37864 autoSize : function(){
37865 if(!this.grow || !this.rendered){
37869 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37872 var v = el.dom.value;
37873 var d = document.createElement('div');
37874 d.appendChild(document.createTextNode(v));
37878 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37879 this.el.setWidth(w);
37880 this.fireEvent("autosize", this, w);
37884 SafariOnKeyDown : function(event)
37886 // this is a workaround for a password hang bug on chrome/ webkit.
37888 var isSelectAll = false;
37890 if(this.el.dom.selectionEnd > 0){
37891 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37893 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37894 event.preventDefault();
37899 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37901 event.preventDefault();
37902 // this is very hacky as keydown always get's upper case.
37904 var cc = String.fromCharCode(event.getCharCode());
37907 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37915 * Ext JS Library 1.1.1
37916 * Copyright(c) 2006-2007, Ext JS, LLC.
37918 * Originally Released Under LGPL - original licence link has changed is not relivant.
37921 * <script type="text/javascript">
37925 * @class Roo.form.Hidden
37926 * @extends Roo.form.TextField
37927 * Simple Hidden element used on forms
37929 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37932 * Creates a new Hidden form element.
37933 * @param {Object} config Configuration options
37938 // easy hidden field...
37939 Roo.form.Hidden = function(config){
37940 Roo.form.Hidden.superclass.constructor.call(this, config);
37943 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37945 inputType: 'hidden',
37948 labelSeparator: '',
37950 itemCls : 'x-form-item-display-none'
37958 * Ext JS Library 1.1.1
37959 * Copyright(c) 2006-2007, Ext JS, LLC.
37961 * Originally Released Under LGPL - original licence link has changed is not relivant.
37964 * <script type="text/javascript">
37968 * @class Roo.form.TriggerField
37969 * @extends Roo.form.TextField
37970 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37971 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37972 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37973 * for which you can provide a custom implementation. For example:
37975 var trigger = new Roo.form.TriggerField();
37976 trigger.onTriggerClick = myTriggerFn;
37977 trigger.applyTo('my-field');
37980 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37981 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37982 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37983 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37985 * Create a new TriggerField.
37986 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37987 * to the base TextField)
37989 Roo.form.TriggerField = function(config){
37990 this.mimicing = false;
37991 Roo.form.TriggerField.superclass.constructor.call(this, config);
37994 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37996 * @cfg {String} triggerClass A CSS class to apply to the trigger
37999 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38000 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
38002 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38004 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38008 /** @cfg {Boolean} grow @hide */
38009 /** @cfg {Number} growMin @hide */
38010 /** @cfg {Number} growMax @hide */
38016 autoSize: Roo.emptyFn,
38020 deferHeight : true,
38023 actionMode : 'wrap',
38025 onResize : function(w, h){
38026 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38027 if(typeof w == 'number'){
38028 var x = w - this.trigger.getWidth();
38029 this.el.setWidth(this.adjustWidth('input', x));
38030 this.trigger.setStyle('left', x+'px');
38035 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38038 getResizeEl : function(){
38043 getPositionEl : function(){
38048 alignErrorIcon : function(){
38049 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38053 onRender : function(ct, position){
38054 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38055 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38056 this.trigger = this.wrap.createChild(this.triggerConfig ||
38057 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38058 if(this.hideTrigger){
38059 this.trigger.setDisplayed(false);
38061 this.initTrigger();
38063 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38068 initTrigger : function(){
38069 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38070 this.trigger.addClassOnOver('x-form-trigger-over');
38071 this.trigger.addClassOnClick('x-form-trigger-click');
38075 onDestroy : function(){
38077 this.trigger.removeAllListeners();
38078 this.trigger.remove();
38081 this.wrap.remove();
38083 Roo.form.TriggerField.superclass.onDestroy.call(this);
38087 onFocus : function(){
38088 Roo.form.TriggerField.superclass.onFocus.call(this);
38089 if(!this.mimicing){
38090 this.wrap.addClass('x-trigger-wrap-focus');
38091 this.mimicing = true;
38092 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38093 if(this.monitorTab){
38094 this.el.on("keydown", this.checkTab, this);
38100 checkTab : function(e){
38101 if(e.getKey() == e.TAB){
38102 this.triggerBlur();
38107 onBlur : function(){
38112 mimicBlur : function(e, t){
38113 if(!this.wrap.contains(t) && this.validateBlur()){
38114 this.triggerBlur();
38119 triggerBlur : function(){
38120 this.mimicing = false;
38121 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38122 if(this.monitorTab){
38123 this.el.un("keydown", this.checkTab, this);
38125 this.wrap.removeClass('x-trigger-wrap-focus');
38126 Roo.form.TriggerField.superclass.onBlur.call(this);
38130 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38131 validateBlur : function(e, t){
38136 onDisable : function(){
38137 Roo.form.TriggerField.superclass.onDisable.call(this);
38139 this.wrap.addClass('x-item-disabled');
38144 onEnable : function(){
38145 Roo.form.TriggerField.superclass.onEnable.call(this);
38147 this.wrap.removeClass('x-item-disabled');
38152 onShow : function(){
38153 var ae = this.getActionEl();
38156 ae.dom.style.display = '';
38157 ae.dom.style.visibility = 'visible';
38163 onHide : function(){
38164 var ae = this.getActionEl();
38165 ae.dom.style.display = 'none';
38169 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38170 * by an implementing function.
38172 * @param {EventObject} e
38174 onTriggerClick : Roo.emptyFn
38177 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38178 // to be extended by an implementing class. For an example of implementing this class, see the custom
38179 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38180 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38181 initComponent : function(){
38182 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38184 this.triggerConfig = {
38185 tag:'span', cls:'x-form-twin-triggers', cn:[
38186 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38187 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38191 getTrigger : function(index){
38192 return this.triggers[index];
38195 initTrigger : function(){
38196 var ts = this.trigger.select('.x-form-trigger', true);
38197 this.wrap.setStyle('overflow', 'hidden');
38198 var triggerField = this;
38199 ts.each(function(t, all, index){
38200 t.hide = function(){
38201 var w = triggerField.wrap.getWidth();
38202 this.dom.style.display = 'none';
38203 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38205 t.show = function(){
38206 var w = triggerField.wrap.getWidth();
38207 this.dom.style.display = '';
38208 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38210 var triggerIndex = 'Trigger'+(index+1);
38212 if(this['hide'+triggerIndex]){
38213 t.dom.style.display = 'none';
38215 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38216 t.addClassOnOver('x-form-trigger-over');
38217 t.addClassOnClick('x-form-trigger-click');
38219 this.triggers = ts.elements;
38222 onTrigger1Click : Roo.emptyFn,
38223 onTrigger2Click : Roo.emptyFn
38226 * Ext JS Library 1.1.1
38227 * Copyright(c) 2006-2007, Ext JS, LLC.
38229 * Originally Released Under LGPL - original licence link has changed is not relivant.
38232 * <script type="text/javascript">
38236 * @class Roo.form.TextArea
38237 * @extends Roo.form.TextField
38238 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38239 * support for auto-sizing.
38241 * Creates a new TextArea
38242 * @param {Object} config Configuration options
38244 Roo.form.TextArea = function(config){
38245 Roo.form.TextArea.superclass.constructor.call(this, config);
38246 // these are provided exchanges for backwards compat
38247 // minHeight/maxHeight were replaced by growMin/growMax to be
38248 // compatible with TextField growing config values
38249 if(this.minHeight !== undefined){
38250 this.growMin = this.minHeight;
38252 if(this.maxHeight !== undefined){
38253 this.growMax = this.maxHeight;
38257 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38259 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38263 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38267 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38268 * in the field (equivalent to setting overflow: hidden, defaults to false)
38270 preventScrollbars: false,
38272 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38273 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38277 onRender : function(ct, position){
38279 this.defaultAutoCreate = {
38281 style:"width:300px;height:60px;",
38282 autocomplete: "new-password"
38285 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38287 this.textSizeEl = Roo.DomHelper.append(document.body, {
38288 tag: "pre", cls: "x-form-grow-sizer"
38290 if(this.preventScrollbars){
38291 this.el.setStyle("overflow", "hidden");
38293 this.el.setHeight(this.growMin);
38297 onDestroy : function(){
38298 if(this.textSizeEl){
38299 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38301 Roo.form.TextArea.superclass.onDestroy.call(this);
38305 onKeyUp : function(e){
38306 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38312 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38313 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38315 autoSize : function(){
38316 if(!this.grow || !this.textSizeEl){
38320 var v = el.dom.value;
38321 var ts = this.textSizeEl;
38324 ts.appendChild(document.createTextNode(v));
38327 Roo.fly(ts).setWidth(this.el.getWidth());
38329 v = "  ";
38332 v = v.replace(/\n/g, '<p> </p>');
38334 v += " \n ";
38337 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38338 if(h != this.lastHeight){
38339 this.lastHeight = h;
38340 this.el.setHeight(h);
38341 this.fireEvent("autosize", this, h);
38346 * Ext JS Library 1.1.1
38347 * Copyright(c) 2006-2007, Ext JS, LLC.
38349 * Originally Released Under LGPL - original licence link has changed is not relivant.
38352 * <script type="text/javascript">
38357 * @class Roo.form.NumberField
38358 * @extends Roo.form.TextField
38359 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38361 * Creates a new NumberField
38362 * @param {Object} config Configuration options
38364 Roo.form.NumberField = function(config){
38365 Roo.form.NumberField.superclass.constructor.call(this, config);
38368 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38370 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38372 fieldClass: "x-form-field x-form-num-field",
38374 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38376 allowDecimals : true,
38378 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38380 decimalSeparator : ".",
38382 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38384 decimalPrecision : 2,
38386 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38388 allowNegative : true,
38390 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38392 minValue : Number.NEGATIVE_INFINITY,
38394 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38396 maxValue : Number.MAX_VALUE,
38398 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38400 minText : "The minimum value for this field is {0}",
38402 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38404 maxText : "The maximum value for this field is {0}",
38406 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38407 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38409 nanText : "{0} is not a valid number",
38412 initEvents : function(){
38413 Roo.form.NumberField.superclass.initEvents.call(this);
38414 var allowed = "0123456789";
38415 if(this.allowDecimals){
38416 allowed += this.decimalSeparator;
38418 if(this.allowNegative){
38421 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38422 var keyPress = function(e){
38423 var k = e.getKey();
38424 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38427 var c = e.getCharCode();
38428 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38432 this.el.on("keypress", keyPress, this);
38436 validateValue : function(value){
38437 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38440 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38443 var num = this.parseValue(value);
38445 this.markInvalid(String.format(this.nanText, value));
38448 if(num < this.minValue){
38449 this.markInvalid(String.format(this.minText, this.minValue));
38452 if(num > this.maxValue){
38453 this.markInvalid(String.format(this.maxText, this.maxValue));
38459 getValue : function(){
38460 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38464 parseValue : function(value){
38465 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38466 return isNaN(value) ? '' : value;
38470 fixPrecision : function(value){
38471 var nan = isNaN(value);
38472 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38473 return nan ? '' : value;
38475 return parseFloat(value).toFixed(this.decimalPrecision);
38478 setValue : function(v){
38479 v = this.fixPrecision(v);
38480 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38484 decimalPrecisionFcn : function(v){
38485 return Math.floor(v);
38488 beforeBlur : function(){
38489 var v = this.parseValue(this.getRawValue());
38496 * Ext JS Library 1.1.1
38497 * Copyright(c) 2006-2007, Ext JS, LLC.
38499 * Originally Released Under LGPL - original licence link has changed is not relivant.
38502 * <script type="text/javascript">
38506 * @class Roo.form.DateField
38507 * @extends Roo.form.TriggerField
38508 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38510 * Create a new DateField
38511 * @param {Object} config
38513 Roo.form.DateField = function(config){
38514 Roo.form.DateField.superclass.constructor.call(this, config);
38520 * Fires when a date is selected
38521 * @param {Roo.form.DateField} combo This combo box
38522 * @param {Date} date The date selected
38529 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38530 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38531 this.ddMatch = null;
38532 if(this.disabledDates){
38533 var dd = this.disabledDates;
38535 for(var i = 0; i < dd.length; i++){
38537 if(i != dd.length-1) re += "|";
38539 this.ddMatch = new RegExp(re + ")");
38543 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38545 * @cfg {String} format
38546 * The default date format string which can be overriden for localization support. The format must be
38547 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38551 * @cfg {String} altFormats
38552 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38553 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38555 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38557 * @cfg {Array} disabledDays
38558 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38560 disabledDays : null,
38562 * @cfg {String} disabledDaysText
38563 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38565 disabledDaysText : "Disabled",
38567 * @cfg {Array} disabledDates
38568 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38569 * expression so they are very powerful. Some examples:
38571 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38572 * <li>["03/08", "09/16"] would disable those days for every year</li>
38573 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38574 * <li>["03/../2006"] would disable every day in March 2006</li>
38575 * <li>["^03"] would disable every day in every March</li>
38577 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38578 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38580 disabledDates : null,
38582 * @cfg {String} disabledDatesText
38583 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38585 disabledDatesText : "Disabled",
38587 * @cfg {Date/String} minValue
38588 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38589 * valid format (defaults to null).
38593 * @cfg {Date/String} maxValue
38594 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38595 * valid format (defaults to null).
38599 * @cfg {String} minText
38600 * The error text to display when the date in the cell is before minValue (defaults to
38601 * 'The date in this field must be after {minValue}').
38603 minText : "The date in this field must be equal to or after {0}",
38605 * @cfg {String} maxText
38606 * The error text to display when the date in the cell is after maxValue (defaults to
38607 * 'The date in this field must be before {maxValue}').
38609 maxText : "The date in this field must be equal to or before {0}",
38611 * @cfg {String} invalidText
38612 * The error text to display when the date in the field is invalid (defaults to
38613 * '{value} is not a valid date - it must be in the format {format}').
38615 invalidText : "{0} is not a valid date - it must be in the format {1}",
38617 * @cfg {String} triggerClass
38618 * An additional CSS class used to style the trigger button. The trigger will always get the
38619 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38620 * which displays a calendar icon).
38622 triggerClass : 'x-form-date-trigger',
38626 * @cfg {Boolean} useIso
38627 * if enabled, then the date field will use a hidden field to store the
38628 * real value as iso formated date. default (false)
38632 * @cfg {String/Object} autoCreate
38633 * A DomHelper element spec, or true for a default element spec (defaults to
38634 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38637 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38640 hiddenField: false,
38642 onRender : function(ct, position)
38644 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38646 //this.el.dom.removeAttribute('name');
38647 Roo.log("Changing name?");
38648 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38649 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38651 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38652 // prevent input submission
38653 this.hiddenName = this.name;
38660 validateValue : function(value)
38662 value = this.formatDate(value);
38663 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38664 Roo.log('super failed');
38667 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38670 var svalue = value;
38671 value = this.parseDate(value);
38673 Roo.log('parse date failed' + svalue);
38674 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38677 var time = value.getTime();
38678 if(this.minValue && time < this.minValue.getTime()){
38679 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38682 if(this.maxValue && time > this.maxValue.getTime()){
38683 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38686 if(this.disabledDays){
38687 var day = value.getDay();
38688 for(var i = 0; i < this.disabledDays.length; i++) {
38689 if(day === this.disabledDays[i]){
38690 this.markInvalid(this.disabledDaysText);
38695 var fvalue = this.formatDate(value);
38696 if(this.ddMatch && this.ddMatch.test(fvalue)){
38697 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38704 // Provides logic to override the default TriggerField.validateBlur which just returns true
38705 validateBlur : function(){
38706 return !this.menu || !this.menu.isVisible();
38709 getName: function()
38711 // returns hidden if it's set..
38712 if (!this.rendered) {return ''};
38713 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38718 * Returns the current date value of the date field.
38719 * @return {Date} The date value
38721 getValue : function(){
38723 return this.hiddenField ?
38724 this.hiddenField.value :
38725 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38729 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38730 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38731 * (the default format used is "m/d/y").
38734 //All of these calls set the same date value (May 4, 2006)
38736 //Pass a date object:
38737 var dt = new Date('5/4/06');
38738 dateField.setValue(dt);
38740 //Pass a date string (default format):
38741 dateField.setValue('5/4/06');
38743 //Pass a date string (custom format):
38744 dateField.format = 'Y-m-d';
38745 dateField.setValue('2006-5-4');
38747 * @param {String/Date} date The date or valid date string
38749 setValue : function(date){
38750 if (this.hiddenField) {
38751 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38753 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38754 // make sure the value field is always stored as a date..
38755 this.value = this.parseDate(date);
38761 parseDate : function(value){
38762 if(!value || value instanceof Date){
38765 var v = Date.parseDate(value, this.format);
38766 if (!v && this.useIso) {
38767 v = Date.parseDate(value, 'Y-m-d');
38769 if(!v && this.altFormats){
38770 if(!this.altFormatsArray){
38771 this.altFormatsArray = this.altFormats.split("|");
38773 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38774 v = Date.parseDate(value, this.altFormatsArray[i]);
38781 formatDate : function(date, fmt){
38782 return (!date || !(date instanceof Date)) ?
38783 date : date.dateFormat(fmt || this.format);
38788 select: function(m, d){
38791 this.fireEvent('select', this, d);
38793 show : function(){ // retain focus styling
38797 this.focus.defer(10, this);
38798 var ml = this.menuListeners;
38799 this.menu.un("select", ml.select, this);
38800 this.menu.un("show", ml.show, this);
38801 this.menu.un("hide", ml.hide, this);
38806 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38807 onTriggerClick : function(){
38811 if(this.menu == null){
38812 this.menu = new Roo.menu.DateMenu();
38814 Roo.apply(this.menu.picker, {
38815 showClear: this.allowBlank,
38816 minDate : this.minValue,
38817 maxDate : this.maxValue,
38818 disabledDatesRE : this.ddMatch,
38819 disabledDatesText : this.disabledDatesText,
38820 disabledDays : this.disabledDays,
38821 disabledDaysText : this.disabledDaysText,
38822 format : this.useIso ? 'Y-m-d' : this.format,
38823 minText : String.format(this.minText, this.formatDate(this.minValue)),
38824 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38826 this.menu.on(Roo.apply({}, this.menuListeners, {
38829 this.menu.picker.setValue(this.getValue() || new Date());
38830 this.menu.show(this.el, "tl-bl?");
38833 beforeBlur : function(){
38834 var v = this.parseDate(this.getRawValue());
38844 isDirty : function() {
38845 if(this.disabled) {
38849 if(typeof(this.startValue) === 'undefined'){
38853 return String(this.getValue()) !== String(this.startValue);
38858 * Ext JS Library 1.1.1
38859 * Copyright(c) 2006-2007, Ext JS, LLC.
38861 * Originally Released Under LGPL - original licence link has changed is not relivant.
38864 * <script type="text/javascript">
38868 * @class Roo.form.MonthField
38869 * @extends Roo.form.TriggerField
38870 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38872 * Create a new MonthField
38873 * @param {Object} config
38875 Roo.form.MonthField = function(config){
38877 Roo.form.MonthField.superclass.constructor.call(this, config);
38883 * Fires when a date is selected
38884 * @param {Roo.form.MonthFieeld} combo This combo box
38885 * @param {Date} date The date selected
38892 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38893 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38894 this.ddMatch = null;
38895 if(this.disabledDates){
38896 var dd = this.disabledDates;
38898 for(var i = 0; i < dd.length; i++){
38900 if(i != dd.length-1) re += "|";
38902 this.ddMatch = new RegExp(re + ")");
38906 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38908 * @cfg {String} format
38909 * The default date format string which can be overriden for localization support. The format must be
38910 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38914 * @cfg {String} altFormats
38915 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38916 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38918 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38920 * @cfg {Array} disabledDays
38921 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38923 disabledDays : [0,1,2,3,4,5,6],
38925 * @cfg {String} disabledDaysText
38926 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38928 disabledDaysText : "Disabled",
38930 * @cfg {Array} disabledDates
38931 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38932 * expression so they are very powerful. Some examples:
38934 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38935 * <li>["03/08", "09/16"] would disable those days for every year</li>
38936 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38937 * <li>["03/../2006"] would disable every day in March 2006</li>
38938 * <li>["^03"] would disable every day in every March</li>
38940 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38941 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38943 disabledDates : null,
38945 * @cfg {String} disabledDatesText
38946 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38948 disabledDatesText : "Disabled",
38950 * @cfg {Date/String} minValue
38951 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38952 * valid format (defaults to null).
38956 * @cfg {Date/String} maxValue
38957 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38958 * valid format (defaults to null).
38962 * @cfg {String} minText
38963 * The error text to display when the date in the cell is before minValue (defaults to
38964 * 'The date in this field must be after {minValue}').
38966 minText : "The date in this field must be equal to or after {0}",
38968 * @cfg {String} maxTextf
38969 * The error text to display when the date in the cell is after maxValue (defaults to
38970 * 'The date in this field must be before {maxValue}').
38972 maxText : "The date in this field must be equal to or before {0}",
38974 * @cfg {String} invalidText
38975 * The error text to display when the date in the field is invalid (defaults to
38976 * '{value} is not a valid date - it must be in the format {format}').
38978 invalidText : "{0} is not a valid date - it must be in the format {1}",
38980 * @cfg {String} triggerClass
38981 * An additional CSS class used to style the trigger button. The trigger will always get the
38982 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38983 * which displays a calendar icon).
38985 triggerClass : 'x-form-date-trigger',
38989 * @cfg {Boolean} useIso
38990 * if enabled, then the date field will use a hidden field to store the
38991 * real value as iso formated date. default (true)
38995 * @cfg {String/Object} autoCreate
38996 * A DomHelper element spec, or true for a default element spec (defaults to
38997 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
39000 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
39003 hiddenField: false,
39005 hideMonthPicker : false,
39007 onRender : function(ct, position)
39009 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39011 this.el.dom.removeAttribute('name');
39012 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39014 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39015 // prevent input submission
39016 this.hiddenName = this.name;
39023 validateValue : function(value)
39025 value = this.formatDate(value);
39026 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39029 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39032 var svalue = value;
39033 value = this.parseDate(value);
39035 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39038 var time = value.getTime();
39039 if(this.minValue && time < this.minValue.getTime()){
39040 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39043 if(this.maxValue && time > this.maxValue.getTime()){
39044 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39047 /*if(this.disabledDays){
39048 var day = value.getDay();
39049 for(var i = 0; i < this.disabledDays.length; i++) {
39050 if(day === this.disabledDays[i]){
39051 this.markInvalid(this.disabledDaysText);
39057 var fvalue = this.formatDate(value);
39058 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39059 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39067 // Provides logic to override the default TriggerField.validateBlur which just returns true
39068 validateBlur : function(){
39069 return !this.menu || !this.menu.isVisible();
39073 * Returns the current date value of the date field.
39074 * @return {Date} The date value
39076 getValue : function(){
39080 return this.hiddenField ?
39081 this.hiddenField.value :
39082 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39086 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39087 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39088 * (the default format used is "m/d/y").
39091 //All of these calls set the same date value (May 4, 2006)
39093 //Pass a date object:
39094 var dt = new Date('5/4/06');
39095 monthField.setValue(dt);
39097 //Pass a date string (default format):
39098 monthField.setValue('5/4/06');
39100 //Pass a date string (custom format):
39101 monthField.format = 'Y-m-d';
39102 monthField.setValue('2006-5-4');
39104 * @param {String/Date} date The date or valid date string
39106 setValue : function(date){
39107 Roo.log('month setValue' + date);
39108 // can only be first of month..
39110 var val = this.parseDate(date);
39112 if (this.hiddenField) {
39113 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39115 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39116 this.value = this.parseDate(date);
39120 parseDate : function(value){
39121 if(!value || value instanceof Date){
39122 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39125 var v = Date.parseDate(value, this.format);
39126 if (!v && this.useIso) {
39127 v = Date.parseDate(value, 'Y-m-d');
39131 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39135 if(!v && this.altFormats){
39136 if(!this.altFormatsArray){
39137 this.altFormatsArray = this.altFormats.split("|");
39139 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39140 v = Date.parseDate(value, this.altFormatsArray[i]);
39147 formatDate : function(date, fmt){
39148 return (!date || !(date instanceof Date)) ?
39149 date : date.dateFormat(fmt || this.format);
39154 select: function(m, d){
39156 this.fireEvent('select', this, d);
39158 show : function(){ // retain focus styling
39162 this.focus.defer(10, this);
39163 var ml = this.menuListeners;
39164 this.menu.un("select", ml.select, this);
39165 this.menu.un("show", ml.show, this);
39166 this.menu.un("hide", ml.hide, this);
39170 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39171 onTriggerClick : function(){
39175 if(this.menu == null){
39176 this.menu = new Roo.menu.DateMenu();
39180 Roo.apply(this.menu.picker, {
39182 showClear: this.allowBlank,
39183 minDate : this.minValue,
39184 maxDate : this.maxValue,
39185 disabledDatesRE : this.ddMatch,
39186 disabledDatesText : this.disabledDatesText,
39188 format : this.useIso ? 'Y-m-d' : this.format,
39189 minText : String.format(this.minText, this.formatDate(this.minValue)),
39190 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39193 this.menu.on(Roo.apply({}, this.menuListeners, {
39201 // hide month picker get's called when we called by 'before hide';
39203 var ignorehide = true;
39204 p.hideMonthPicker = function(disableAnim){
39208 if(this.monthPicker){
39209 Roo.log("hideMonthPicker called");
39210 if(disableAnim === true){
39211 this.monthPicker.hide();
39213 this.monthPicker.slideOut('t', {duration:.2});
39214 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39215 p.fireEvent("select", this, this.value);
39221 Roo.log('picker set value');
39222 Roo.log(this.getValue());
39223 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39224 m.show(this.el, 'tl-bl?');
39225 ignorehide = false;
39226 // this will trigger hideMonthPicker..
39229 // hidden the day picker
39230 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39236 p.showMonthPicker.defer(100, p);
39242 beforeBlur : function(){
39243 var v = this.parseDate(this.getRawValue());
39249 /** @cfg {Boolean} grow @hide */
39250 /** @cfg {Number} growMin @hide */
39251 /** @cfg {Number} growMax @hide */
39258 * Ext JS Library 1.1.1
39259 * Copyright(c) 2006-2007, Ext JS, LLC.
39261 * Originally Released Under LGPL - original licence link has changed is not relivant.
39264 * <script type="text/javascript">
39269 * @class Roo.form.ComboBox
39270 * @extends Roo.form.TriggerField
39271 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39273 * Create a new ComboBox.
39274 * @param {Object} config Configuration options
39276 Roo.form.ComboBox = function(config){
39277 Roo.form.ComboBox.superclass.constructor.call(this, config);
39281 * Fires when the dropdown list is expanded
39282 * @param {Roo.form.ComboBox} combo This combo box
39287 * Fires when the dropdown list is collapsed
39288 * @param {Roo.form.ComboBox} combo This combo box
39292 * @event beforeselect
39293 * Fires before a list item is selected. Return false to cancel the selection.
39294 * @param {Roo.form.ComboBox} combo This combo box
39295 * @param {Roo.data.Record} record The data record returned from the underlying store
39296 * @param {Number} index The index of the selected item in the dropdown list
39298 'beforeselect' : true,
39301 * Fires when a list item is selected
39302 * @param {Roo.form.ComboBox} combo This combo box
39303 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39304 * @param {Number} index The index of the selected item in the dropdown list
39308 * @event beforequery
39309 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39310 * The event object passed has these properties:
39311 * @param {Roo.form.ComboBox} combo This combo box
39312 * @param {String} query The query
39313 * @param {Boolean} forceAll true to force "all" query
39314 * @param {Boolean} cancel true to cancel the query
39315 * @param {Object} e The query event object
39317 'beforequery': true,
39320 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39321 * @param {Roo.form.ComboBox} combo This combo box
39326 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39327 * @param {Roo.form.ComboBox} combo This combo box
39328 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39334 if(this.transform){
39335 this.allowDomMove = false;
39336 var s = Roo.getDom(this.transform);
39337 if(!this.hiddenName){
39338 this.hiddenName = s.name;
39341 this.mode = 'local';
39342 var d = [], opts = s.options;
39343 for(var i = 0, len = opts.length;i < len; i++){
39345 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39347 this.value = value;
39349 d.push([value, o.text]);
39351 this.store = new Roo.data.SimpleStore({
39353 fields: ['value', 'text'],
39356 this.valueField = 'value';
39357 this.displayField = 'text';
39359 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39360 if(!this.lazyRender){
39361 this.target = true;
39362 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39363 s.parentNode.removeChild(s); // remove it
39364 this.render(this.el.parentNode);
39366 s.parentNode.removeChild(s); // remove it
39371 this.store = Roo.factory(this.store, Roo.data);
39374 this.selectedIndex = -1;
39375 if(this.mode == 'local'){
39376 if(config.queryDelay === undefined){
39377 this.queryDelay = 10;
39379 if(config.minChars === undefined){
39385 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39387 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39390 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39391 * rendering into an Roo.Editor, defaults to false)
39394 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39395 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39398 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39401 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39402 * the dropdown list (defaults to undefined, with no header element)
39406 * @cfg {String/Roo.Template} tpl The template to use to render the output
39410 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39412 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39414 listWidth: undefined,
39416 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39417 * mode = 'remote' or 'text' if mode = 'local')
39419 displayField: undefined,
39421 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39422 * mode = 'remote' or 'value' if mode = 'local').
39423 * Note: use of a valueField requires the user make a selection
39424 * in order for a value to be mapped.
39426 valueField: undefined,
39430 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39431 * field's data value (defaults to the underlying DOM element's name)
39433 hiddenName: undefined,
39435 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39439 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39441 selectedClass: 'x-combo-selected',
39443 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39444 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39445 * which displays a downward arrow icon).
39447 triggerClass : 'x-form-arrow-trigger',
39449 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39453 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39454 * anchor positions (defaults to 'tl-bl')
39456 listAlign: 'tl-bl?',
39458 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39462 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39463 * query specified by the allQuery config option (defaults to 'query')
39465 triggerAction: 'query',
39467 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39468 * (defaults to 4, does not apply if editable = false)
39472 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39473 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39477 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39478 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39482 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39483 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39487 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39488 * when editable = true (defaults to false)
39490 selectOnFocus:false,
39492 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39494 queryParam: 'query',
39496 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39497 * when mode = 'remote' (defaults to 'Loading...')
39499 loadingText: 'Loading...',
39501 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39505 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39509 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39510 * traditional select (defaults to true)
39514 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39518 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39522 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39523 * listWidth has a higher value)
39527 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39528 * allow the user to set arbitrary text into the field (defaults to false)
39530 forceSelection:false,
39532 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39533 * if typeAhead = true (defaults to 250)
39535 typeAheadDelay : 250,
39537 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39538 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39540 valueNotFoundText : undefined,
39542 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39544 blockFocus : false,
39547 * @cfg {Boolean} disableClear Disable showing of clear button.
39549 disableClear : false,
39551 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39553 alwaysQuery : false,
39559 // element that contains real text value.. (when hidden is used..)
39562 onRender : function(ct, position){
39563 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39564 if(this.hiddenName){
39565 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39567 this.hiddenField.value =
39568 this.hiddenValue !== undefined ? this.hiddenValue :
39569 this.value !== undefined ? this.value : '';
39571 // prevent input submission
39572 this.el.dom.removeAttribute('name');
39577 this.el.dom.setAttribute('autocomplete', 'off');
39580 var cls = 'x-combo-list';
39582 this.list = new Roo.Layer({
39583 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39586 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39587 this.list.setWidth(lw);
39588 this.list.swallowEvent('mousewheel');
39589 this.assetHeight = 0;
39592 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39593 this.assetHeight += this.header.getHeight();
39596 this.innerList = this.list.createChild({cls:cls+'-inner'});
39597 this.innerList.on('mouseover', this.onViewOver, this);
39598 this.innerList.on('mousemove', this.onViewMove, this);
39599 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39601 if(this.allowBlank && !this.pageSize && !this.disableClear){
39602 this.footer = this.list.createChild({cls:cls+'-ft'});
39603 this.pageTb = new Roo.Toolbar(this.footer);
39607 this.footer = this.list.createChild({cls:cls+'-ft'});
39608 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39609 {pageSize: this.pageSize});
39613 if (this.pageTb && this.allowBlank && !this.disableClear) {
39615 this.pageTb.add(new Roo.Toolbar.Fill(), {
39616 cls: 'x-btn-icon x-btn-clear',
39618 handler: function()
39621 _this.clearValue();
39622 _this.onSelect(false, -1);
39627 this.assetHeight += this.footer.getHeight();
39632 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39635 this.view = new Roo.View(this.innerList, this.tpl, {
39636 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39639 this.view.on('click', this.onViewClick, this);
39641 this.store.on('beforeload', this.onBeforeLoad, this);
39642 this.store.on('load', this.onLoad, this);
39643 this.store.on('loadexception', this.onLoadException, this);
39645 if(this.resizable){
39646 this.resizer = new Roo.Resizable(this.list, {
39647 pinned:true, handles:'se'
39649 this.resizer.on('resize', function(r, w, h){
39650 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39651 this.listWidth = w;
39652 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39653 this.restrictHeight();
39655 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39657 if(!this.editable){
39658 this.editable = true;
39659 this.setEditable(false);
39663 if (typeof(this.events.add.listeners) != 'undefined') {
39665 this.addicon = this.wrap.createChild(
39666 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39668 this.addicon.on('click', function(e) {
39669 this.fireEvent('add', this);
39672 if (typeof(this.events.edit.listeners) != 'undefined') {
39674 this.editicon = this.wrap.createChild(
39675 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39676 if (this.addicon) {
39677 this.editicon.setStyle('margin-left', '40px');
39679 this.editicon.on('click', function(e) {
39681 // we fire even if inothing is selected..
39682 this.fireEvent('edit', this, this.lastData );
39692 initEvents : function(){
39693 Roo.form.ComboBox.superclass.initEvents.call(this);
39695 this.keyNav = new Roo.KeyNav(this.el, {
39696 "up" : function(e){
39697 this.inKeyMode = true;
39701 "down" : function(e){
39702 if(!this.isExpanded()){
39703 this.onTriggerClick();
39705 this.inKeyMode = true;
39710 "enter" : function(e){
39711 this.onViewClick();
39715 "esc" : function(e){
39719 "tab" : function(e){
39720 this.onViewClick(false);
39721 this.fireEvent("specialkey", this, e);
39727 doRelay : function(foo, bar, hname){
39728 if(hname == 'down' || this.scope.isExpanded()){
39729 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39736 this.queryDelay = Math.max(this.queryDelay || 10,
39737 this.mode == 'local' ? 10 : 250);
39738 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39739 if(this.typeAhead){
39740 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39742 if(this.editable !== false){
39743 this.el.on("keyup", this.onKeyUp, this);
39745 if(this.forceSelection){
39746 this.on('blur', this.doForce, this);
39750 onDestroy : function(){
39752 this.view.setStore(null);
39753 this.view.el.removeAllListeners();
39754 this.view.el.remove();
39755 this.view.purgeListeners();
39758 this.list.destroy();
39761 this.store.un('beforeload', this.onBeforeLoad, this);
39762 this.store.un('load', this.onLoad, this);
39763 this.store.un('loadexception', this.onLoadException, this);
39765 Roo.form.ComboBox.superclass.onDestroy.call(this);
39769 fireKey : function(e){
39770 if(e.isNavKeyPress() && !this.list.isVisible()){
39771 this.fireEvent("specialkey", this, e);
39776 onResize: function(w, h){
39777 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39779 if(typeof w != 'number'){
39780 // we do not handle it!?!?
39783 var tw = this.trigger.getWidth();
39784 tw += this.addicon ? this.addicon.getWidth() : 0;
39785 tw += this.editicon ? this.editicon.getWidth() : 0;
39787 this.el.setWidth( this.adjustWidth('input', x));
39789 this.trigger.setStyle('left', x+'px');
39791 if(this.list && this.listWidth === undefined){
39792 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39793 this.list.setWidth(lw);
39794 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39802 * Allow or prevent the user from directly editing the field text. If false is passed,
39803 * the user will only be able to select from the items defined in the dropdown list. This method
39804 * is the runtime equivalent of setting the 'editable' config option at config time.
39805 * @param {Boolean} value True to allow the user to directly edit the field text
39807 setEditable : function(value){
39808 if(value == this.editable){
39811 this.editable = value;
39813 this.el.dom.setAttribute('readOnly', true);
39814 this.el.on('mousedown', this.onTriggerClick, this);
39815 this.el.addClass('x-combo-noedit');
39817 this.el.dom.setAttribute('readOnly', false);
39818 this.el.un('mousedown', this.onTriggerClick, this);
39819 this.el.removeClass('x-combo-noedit');
39824 onBeforeLoad : function(){
39825 if(!this.hasFocus){
39828 this.innerList.update(this.loadingText ?
39829 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39830 this.restrictHeight();
39831 this.selectedIndex = -1;
39835 onLoad : function(){
39836 if(!this.hasFocus){
39839 if(this.store.getCount() > 0){
39841 this.restrictHeight();
39842 if(this.lastQuery == this.allQuery){
39844 this.el.dom.select();
39846 if(!this.selectByValue(this.value, true)){
39847 this.select(0, true);
39851 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39852 this.taTask.delay(this.typeAheadDelay);
39856 this.onEmptyResults();
39861 onLoadException : function()
39864 Roo.log(this.store.reader.jsonData);
39865 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39866 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39872 onTypeAhead : function(){
39873 if(this.store.getCount() > 0){
39874 var r = this.store.getAt(0);
39875 var newValue = r.data[this.displayField];
39876 var len = newValue.length;
39877 var selStart = this.getRawValue().length;
39878 if(selStart != len){
39879 this.setRawValue(newValue);
39880 this.selectText(selStart, newValue.length);
39886 onSelect : function(record, index){
39887 if(this.fireEvent('beforeselect', this, record, index) !== false){
39888 this.setFromData(index > -1 ? record.data : false);
39890 this.fireEvent('select', this, record, index);
39895 * Returns the currently selected field value or empty string if no value is set.
39896 * @return {String} value The selected value
39898 getValue : function(){
39899 if(this.valueField){
39900 return typeof this.value != 'undefined' ? this.value : '';
39902 return Roo.form.ComboBox.superclass.getValue.call(this);
39906 * Clears any text/value currently set in the field
39908 clearValue : function(){
39909 if(this.hiddenField){
39910 this.hiddenField.value = '';
39913 this.setRawValue('');
39914 this.lastSelectionText = '';
39919 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39920 * will be displayed in the field. If the value does not match the data value of an existing item,
39921 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39922 * Otherwise the field will be blank (although the value will still be set).
39923 * @param {String} value The value to match
39925 setValue : function(v){
39927 if(this.valueField){
39928 var r = this.findRecord(this.valueField, v);
39930 text = r.data[this.displayField];
39931 }else if(this.valueNotFoundText !== undefined){
39932 text = this.valueNotFoundText;
39935 this.lastSelectionText = text;
39936 if(this.hiddenField){
39937 this.hiddenField.value = v;
39939 Roo.form.ComboBox.superclass.setValue.call(this, text);
39943 * @property {Object} the last set data for the element
39948 * Sets the value of the field based on a object which is related to the record format for the store.
39949 * @param {Object} value the value to set as. or false on reset?
39951 setFromData : function(o){
39952 var dv = ''; // display value
39953 var vv = ''; // value value..
39955 if (this.displayField) {
39956 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39958 // this is an error condition!!!
39959 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39962 if(this.valueField){
39963 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39965 if(this.hiddenField){
39966 this.hiddenField.value = vv;
39968 this.lastSelectionText = dv;
39969 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39973 // no hidden field.. - we store the value in 'value', but still display
39974 // display field!!!!
39975 this.lastSelectionText = dv;
39976 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39982 reset : function(){
39983 // overridden so that last data is reset..
39984 this.setValue(this.resetValue);
39985 this.clearInvalid();
39986 this.lastData = false;
39988 this.view.clearSelections();
39992 findRecord : function(prop, value){
39994 if(this.store.getCount() > 0){
39995 this.store.each(function(r){
39996 if(r.data[prop] == value){
40006 getName: function()
40008 // returns hidden if it's set..
40009 if (!this.rendered) {return ''};
40010 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40014 onViewMove : function(e, t){
40015 this.inKeyMode = false;
40019 onViewOver : function(e, t){
40020 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40023 var item = this.view.findItemFromChild(t);
40025 var index = this.view.indexOf(item);
40026 this.select(index, false);
40031 onViewClick : function(doFocus)
40033 var index = this.view.getSelectedIndexes()[0];
40034 var r = this.store.getAt(index);
40036 this.onSelect(r, index);
40038 if(doFocus !== false && !this.blockFocus){
40044 restrictHeight : function(){
40045 this.innerList.dom.style.height = '';
40046 var inner = this.innerList.dom;
40047 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40048 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40049 this.list.beginUpdate();
40050 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40051 this.list.alignTo(this.el, this.listAlign);
40052 this.list.endUpdate();
40056 onEmptyResults : function(){
40061 * Returns true if the dropdown list is expanded, else false.
40063 isExpanded : function(){
40064 return this.list.isVisible();
40068 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40069 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40070 * @param {String} value The data value of the item to select
40071 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40072 * selected item if it is not currently in view (defaults to true)
40073 * @return {Boolean} True if the value matched an item in the list, else false
40075 selectByValue : function(v, scrollIntoView){
40076 if(v !== undefined && v !== null){
40077 var r = this.findRecord(this.valueField || this.displayField, v);
40079 this.select(this.store.indexOf(r), scrollIntoView);
40087 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40088 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40089 * @param {Number} index The zero-based index of the list item to select
40090 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40091 * selected item if it is not currently in view (defaults to true)
40093 select : function(index, scrollIntoView){
40094 this.selectedIndex = index;
40095 this.view.select(index);
40096 if(scrollIntoView !== false){
40097 var el = this.view.getNode(index);
40099 this.innerList.scrollChildIntoView(el, false);
40105 selectNext : function(){
40106 var ct = this.store.getCount();
40108 if(this.selectedIndex == -1){
40110 }else if(this.selectedIndex < ct-1){
40111 this.select(this.selectedIndex+1);
40117 selectPrev : function(){
40118 var ct = this.store.getCount();
40120 if(this.selectedIndex == -1){
40122 }else if(this.selectedIndex != 0){
40123 this.select(this.selectedIndex-1);
40129 onKeyUp : function(e){
40130 if(this.editable !== false && !e.isSpecialKey()){
40131 this.lastKey = e.getKey();
40132 this.dqTask.delay(this.queryDelay);
40137 validateBlur : function(){
40138 return !this.list || !this.list.isVisible();
40142 initQuery : function(){
40143 this.doQuery(this.getRawValue());
40147 doForce : function(){
40148 if(this.el.dom.value.length > 0){
40149 this.el.dom.value =
40150 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40156 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40157 * query allowing the query action to be canceled if needed.
40158 * @param {String} query The SQL query to execute
40159 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40160 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40161 * saved in the current store (defaults to false)
40163 doQuery : function(q, forceAll){
40164 if(q === undefined || q === null){
40169 forceAll: forceAll,
40173 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40177 forceAll = qe.forceAll;
40178 if(forceAll === true || (q.length >= this.minChars)){
40179 if(this.lastQuery != q || this.alwaysQuery){
40180 this.lastQuery = q;
40181 if(this.mode == 'local'){
40182 this.selectedIndex = -1;
40184 this.store.clearFilter();
40186 this.store.filter(this.displayField, q);
40190 this.store.baseParams[this.queryParam] = q;
40192 params: this.getParams(q)
40197 this.selectedIndex = -1;
40204 getParams : function(q){
40206 //p[this.queryParam] = q;
40209 p.limit = this.pageSize;
40215 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40217 collapse : function(){
40218 if(!this.isExpanded()){
40222 Roo.get(document).un('mousedown', this.collapseIf, this);
40223 Roo.get(document).un('mousewheel', this.collapseIf, this);
40224 if (!this.editable) {
40225 Roo.get(document).un('keydown', this.listKeyPress, this);
40227 this.fireEvent('collapse', this);
40231 collapseIf : function(e){
40232 if(!e.within(this.wrap) && !e.within(this.list)){
40238 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40240 expand : function(){
40241 if(this.isExpanded() || !this.hasFocus){
40244 this.list.alignTo(this.el, this.listAlign);
40246 Roo.get(document).on('mousedown', this.collapseIf, this);
40247 Roo.get(document).on('mousewheel', this.collapseIf, this);
40248 if (!this.editable) {
40249 Roo.get(document).on('keydown', this.listKeyPress, this);
40252 this.fireEvent('expand', this);
40256 // Implements the default empty TriggerField.onTriggerClick function
40257 onTriggerClick : function(){
40261 if(this.isExpanded()){
40263 if (!this.blockFocus) {
40268 this.hasFocus = true;
40269 if(this.triggerAction == 'all') {
40270 this.doQuery(this.allQuery, true);
40272 this.doQuery(this.getRawValue());
40274 if (!this.blockFocus) {
40279 listKeyPress : function(e)
40281 //Roo.log('listkeypress');
40282 // scroll to first matching element based on key pres..
40283 if (e.isSpecialKey()) {
40286 var k = String.fromCharCode(e.getKey()).toUpperCase();
40289 var csel = this.view.getSelectedNodes();
40290 var cselitem = false;
40292 var ix = this.view.indexOf(csel[0]);
40293 cselitem = this.store.getAt(ix);
40294 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40300 this.store.each(function(v) {
40302 // start at existing selection.
40303 if (cselitem.id == v.id) {
40309 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40310 match = this.store.indexOf(v);
40315 if (match === false) {
40316 return true; // no more action?
40319 this.view.select(match);
40320 var sn = Roo.get(this.view.getSelectedNodes()[0])
40321 sn.scrollIntoView(sn.dom.parentNode, false);
40325 * @cfg {Boolean} grow
40329 * @cfg {Number} growMin
40333 * @cfg {Number} growMax
40341 * Copyright(c) 2010-2012, Roo J Solutions Limited
40348 * @class Roo.form.ComboBoxArray
40349 * @extends Roo.form.TextField
40350 * A facebook style adder... for lists of email / people / countries etc...
40351 * pick multiple items from a combo box, and shows each one.
40353 * Fred [x] Brian [x] [Pick another |v]
40356 * For this to work: it needs various extra information
40357 * - normal combo problay has
40359 * + displayField, valueField
40361 * For our purpose...
40364 * If we change from 'extends' to wrapping...
40371 * Create a new ComboBoxArray.
40372 * @param {Object} config Configuration options
40376 Roo.form.ComboBoxArray = function(config)
40380 * @event beforeremove
40381 * Fires before remove the value from the list
40382 * @param {Roo.form.ComboBoxArray} _self This combo box array
40383 * @param {Roo.form.ComboBoxArray.Item} item removed item
40385 'beforeremove' : true,
40388 * Fires when remove the value from the list
40389 * @param {Roo.form.ComboBoxArray} _self This combo box array
40390 * @param {Roo.form.ComboBoxArray.Item} item removed item
40397 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40399 this.items = new Roo.util.MixedCollection(false);
40401 // construct the child combo...
40411 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40414 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40419 // behavies liek a hiddne field
40420 inputType: 'hidden',
40422 * @cfg {Number} width The width of the box that displays the selected element
40429 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40433 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40435 hiddenName : false,
40438 // private the array of items that are displayed..
40440 // private - the hidden field el.
40442 // private - the filed el..
40445 //validateValue : function() { return true; }, // all values are ok!
40446 //onAddClick: function() { },
40448 onRender : function(ct, position)
40451 // create the standard hidden element
40452 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40455 // give fake names to child combo;
40456 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40457 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40459 this.combo = Roo.factory(this.combo, Roo.form);
40460 this.combo.onRender(ct, position);
40461 if (typeof(this.combo.width) != 'undefined') {
40462 this.combo.onResize(this.combo.width,0);
40465 this.combo.initEvents();
40467 // assigned so form know we need to do this..
40468 this.store = this.combo.store;
40469 this.valueField = this.combo.valueField;
40470 this.displayField = this.combo.displayField ;
40473 this.combo.wrap.addClass('x-cbarray-grp');
40475 var cbwrap = this.combo.wrap.createChild(
40476 {tag: 'div', cls: 'x-cbarray-cb'},
40481 this.hiddenEl = this.combo.wrap.createChild({
40482 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40484 this.el = this.combo.wrap.createChild({
40485 tag: 'input', type:'hidden' , name: this.name, value : ''
40487 // this.el.dom.removeAttribute("name");
40490 this.outerWrap = this.combo.wrap;
40491 this.wrap = cbwrap;
40493 this.outerWrap.setWidth(this.width);
40494 this.outerWrap.dom.removeChild(this.el.dom);
40496 this.wrap.dom.appendChild(this.el.dom);
40497 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40498 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40500 this.combo.trigger.setStyle('position','relative');
40501 this.combo.trigger.setStyle('left', '0px');
40502 this.combo.trigger.setStyle('top', '2px');
40504 this.combo.el.setStyle('vertical-align', 'text-bottom');
40506 //this.trigger.setStyle('vertical-align', 'top');
40508 // this should use the code from combo really... on('add' ....)
40512 this.adder = this.outerWrap.createChild(
40513 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40515 this.adder.on('click', function(e) {
40516 _t.fireEvent('adderclick', this, e);
40520 //this.adder.on('click', this.onAddClick, _t);
40523 this.combo.on('select', function(cb, rec, ix) {
40524 this.addItem(rec.data);
40527 cb.el.dom.value = '';
40528 //cb.lastData = rec.data;
40537 getName: function()
40539 // returns hidden if it's set..
40540 if (!this.rendered) {return ''};
40541 return this.hiddenName ? this.hiddenName : this.name;
40546 onResize: function(w, h){
40549 // not sure if this is needed..
40550 //this.combo.onResize(w,h);
40552 if(typeof w != 'number'){
40553 // we do not handle it!?!?
40556 var tw = this.combo.trigger.getWidth();
40557 tw += this.addicon ? this.addicon.getWidth() : 0;
40558 tw += this.editicon ? this.editicon.getWidth() : 0;
40560 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40562 this.combo.trigger.setStyle('left', '0px');
40564 if(this.list && this.listWidth === undefined){
40565 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40566 this.list.setWidth(lw);
40567 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40574 addItem: function(rec)
40576 var valueField = this.combo.valueField;
40577 var displayField = this.combo.displayField;
40578 if (this.items.indexOfKey(rec[valueField]) > -1) {
40579 //console.log("GOT " + rec.data.id);
40583 var x = new Roo.form.ComboBoxArray.Item({
40584 //id : rec[this.idField],
40586 displayField : displayField ,
40587 tipField : displayField ,
40591 this.items.add(rec[valueField],x);
40592 // add it before the element..
40593 this.updateHiddenEl();
40594 x.render(this.outerWrap, this.wrap.dom);
40595 // add the image handler..
40598 updateHiddenEl : function()
40601 if (!this.hiddenEl) {
40605 var idField = this.combo.valueField;
40607 this.items.each(function(f) {
40608 ar.push(f.data[idField]);
40611 this.hiddenEl.dom.value = ar.join(',');
40617 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40618 this.items.each(function(f) {
40621 this.el.dom.value = '';
40622 if (this.hiddenEl) {
40623 this.hiddenEl.dom.value = '';
40627 getValue: function()
40629 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40631 setValue: function(v) // not a valid action - must use addItems..
40638 if (this.store.isLocal && (typeof(v) == 'string')) {
40639 // then we can use the store to find the values..
40640 // comma seperated at present.. this needs to allow JSON based encoding..
40641 this.hiddenEl.value = v;
40643 Roo.each(v.split(','), function(k) {
40644 Roo.log("CHECK " + this.valueField + ',' + k);
40645 var li = this.store.query(this.valueField, k);
40650 add[this.valueField] = k;
40651 add[this.displayField] = li.item(0).data[this.displayField];
40657 if (typeof(v) == 'object' ) {
40658 // then let's assume it's an array of objects..
40659 Roo.each(v, function(l) {
40667 setFromData: function(v)
40669 // this recieves an object, if setValues is called.
40671 this.el.dom.value = v[this.displayField];
40672 this.hiddenEl.dom.value = v[this.valueField];
40673 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40676 var kv = v[this.valueField];
40677 var dv = v[this.displayField];
40678 kv = typeof(kv) != 'string' ? '' : kv;
40679 dv = typeof(dv) != 'string' ? '' : dv;
40682 var keys = kv.split(',');
40683 var display = dv.split(',');
40684 for (var i = 0 ; i < keys.length; i++) {
40687 add[this.valueField] = keys[i];
40688 add[this.displayField] = display[i];
40696 * Validates the combox array value
40697 * @return {Boolean} True if the value is valid, else false
40699 validate : function(){
40700 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40701 this.clearInvalid();
40707 validateValue : function(value){
40708 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40716 isDirty : function() {
40717 if(this.disabled) {
40722 var d = Roo.decode(String(this.originalValue));
40724 return String(this.getValue()) !== String(this.originalValue);
40727 var originalValue = [];
40729 for (var i = 0; i < d.length; i++){
40730 originalValue.push(d[i][this.valueField]);
40733 return String(this.getValue()) !== String(originalValue.join(','));
40742 * @class Roo.form.ComboBoxArray.Item
40743 * @extends Roo.BoxComponent
40744 * A selected item in the list
40745 * Fred [x] Brian [x] [Pick another |v]
40748 * Create a new item.
40749 * @param {Object} config Configuration options
40752 Roo.form.ComboBoxArray.Item = function(config) {
40753 config.id = Roo.id();
40754 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40757 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40760 displayField : false,
40764 defaultAutoCreate : {
40766 cls: 'x-cbarray-item',
40773 src : Roo.BLANK_IMAGE_URL ,
40781 onRender : function(ct, position)
40783 Roo.form.Field.superclass.onRender.call(this, ct, position);
40786 var cfg = this.getAutoCreate();
40787 this.el = ct.createChild(cfg, position);
40790 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40792 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40793 this.cb.renderer(this.data) :
40794 String.format('{0}',this.data[this.displayField]);
40797 this.el.child('div').dom.setAttribute('qtip',
40798 String.format('{0}',this.data[this.tipField])
40801 this.el.child('img').on('click', this.remove, this);
40805 remove : function()
40807 if(this.cb.disabled){
40811 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40812 this.cb.items.remove(this);
40813 this.el.child('img').un('click', this.remove, this);
40815 this.cb.updateHiddenEl();
40817 this.cb.fireEvent('remove', this.cb, this);
40823 * Ext JS Library 1.1.1
40824 * Copyright(c) 2006-2007, Ext JS, LLC.
40826 * Originally Released Under LGPL - original licence link has changed is not relivant.
40829 * <script type="text/javascript">
40832 * @class Roo.form.Checkbox
40833 * @extends Roo.form.Field
40834 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40836 * Creates a new Checkbox
40837 * @param {Object} config Configuration options
40839 Roo.form.Checkbox = function(config){
40840 Roo.form.Checkbox.superclass.constructor.call(this, config);
40844 * Fires when the checkbox is checked or unchecked.
40845 * @param {Roo.form.Checkbox} this This checkbox
40846 * @param {Boolean} checked The new checked value
40852 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40854 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40856 focusClass : undefined,
40858 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40860 fieldClass: "x-form-field",
40862 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40866 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40867 * {tag: "input", type: "checkbox", autocomplete: "off"})
40869 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40871 * @cfg {String} boxLabel The text that appears beside the checkbox
40875 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40879 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40881 valueOff: '0', // value when not checked..
40883 actionMode : 'viewEl',
40886 itemCls : 'x-menu-check-item x-form-item',
40887 groupClass : 'x-menu-group-item',
40888 inputType : 'hidden',
40891 inSetChecked: false, // check that we are not calling self...
40893 inputElement: false, // real input element?
40894 basedOn: false, // ????
40896 isFormField: true, // not sure where this is needed!!!!
40898 onResize : function(){
40899 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40900 if(!this.boxLabel){
40901 this.el.alignTo(this.wrap, 'c-c');
40905 initEvents : function(){
40906 Roo.form.Checkbox.superclass.initEvents.call(this);
40907 this.el.on("click", this.onClick, this);
40908 this.el.on("change", this.onClick, this);
40912 getResizeEl : function(){
40916 getPositionEl : function(){
40921 onRender : function(ct, position){
40922 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40924 if(this.inputValue !== undefined){
40925 this.el.dom.value = this.inputValue;
40928 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40929 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40930 var viewEl = this.wrap.createChild({
40931 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40932 this.viewEl = viewEl;
40933 this.wrap.on('click', this.onClick, this);
40935 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40936 this.el.on('propertychange', this.setFromHidden, this); //ie
40941 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40942 // viewEl.on('click', this.onClick, this);
40944 //if(this.checked){
40945 this.setChecked(this.checked);
40947 //this.checked = this.el.dom;
40953 initValue : Roo.emptyFn,
40956 * Returns the checked state of the checkbox.
40957 * @return {Boolean} True if checked, else false
40959 getValue : function(){
40961 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40963 return this.valueOff;
40968 onClick : function(){
40969 if (this.disabled) {
40972 this.setChecked(!this.checked);
40974 //if(this.el.dom.checked != this.checked){
40975 // this.setValue(this.el.dom.checked);
40980 * Sets the checked state of the checkbox.
40981 * On is always based on a string comparison between inputValue and the param.
40982 * @param {Boolean/String} value - the value to set
40983 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40985 setValue : function(v,suppressEvent){
40988 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40989 //if(this.el && this.el.dom){
40990 // this.el.dom.checked = this.checked;
40991 // this.el.dom.defaultChecked = this.checked;
40993 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40994 //this.fireEvent("check", this, this.checked);
40997 setChecked : function(state,suppressEvent)
40999 if (this.inSetChecked) {
41000 this.checked = state;
41006 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41008 this.checked = state;
41009 if(suppressEvent !== true){
41010 this.fireEvent('check', this, state);
41012 this.inSetChecked = true;
41013 this.el.dom.value = state ? this.inputValue : this.valueOff;
41014 this.inSetChecked = false;
41017 // handle setting of hidden value by some other method!!?!?
41018 setFromHidden: function()
41023 //console.log("SET FROM HIDDEN");
41024 //alert('setFrom hidden');
41025 this.setValue(this.el.dom.value);
41028 onDestroy : function()
41031 Roo.get(this.viewEl).remove();
41034 Roo.form.Checkbox.superclass.onDestroy.call(this);
41039 * Ext JS Library 1.1.1
41040 * Copyright(c) 2006-2007, Ext JS, LLC.
41042 * Originally Released Under LGPL - original licence link has changed is not relivant.
41045 * <script type="text/javascript">
41049 * @class Roo.form.Radio
41050 * @extends Roo.form.Checkbox
41051 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41052 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41054 * Creates a new Radio
41055 * @param {Object} config Configuration options
41057 Roo.form.Radio = function(){
41058 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41060 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41061 inputType: 'radio',
41064 * If this radio is part of a group, it will return the selected value
41067 getGroupValue : function(){
41068 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41072 onRender : function(ct, position){
41073 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41075 if(this.inputValue !== undefined){
41076 this.el.dom.value = this.inputValue;
41079 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41080 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41081 //var viewEl = this.wrap.createChild({
41082 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41083 //this.viewEl = viewEl;
41084 //this.wrap.on('click', this.onClick, this);
41086 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41087 //this.el.on('propertychange', this.setFromHidden, this); //ie
41092 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41093 // viewEl.on('click', this.onClick, this);
41096 this.el.dom.checked = 'checked' ;
41102 });//<script type="text/javascript">
41105 * Based Ext JS Library 1.1.1
41106 * Copyright(c) 2006-2007, Ext JS, LLC.
41112 * @class Roo.HtmlEditorCore
41113 * @extends Roo.Component
41114 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41116 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41119 Roo.HtmlEditorCore = function(config){
41122 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41127 * @event initialize
41128 * Fires when the editor is fully initialized (including the iframe)
41129 * @param {Roo.HtmlEditorCore} this
41134 * Fires when the editor is first receives the focus. Any insertion must wait
41135 * until after this event.
41136 * @param {Roo.HtmlEditorCore} this
41140 * @event beforesync
41141 * Fires before the textarea is updated with content from the editor iframe. Return false
41142 * to cancel the sync.
41143 * @param {Roo.HtmlEditorCore} this
41144 * @param {String} html
41148 * @event beforepush
41149 * Fires before the iframe editor is updated with content from the textarea. Return false
41150 * to cancel the push.
41151 * @param {Roo.HtmlEditorCore} this
41152 * @param {String} html
41157 * Fires when the textarea is updated with content from the editor iframe.
41158 * @param {Roo.HtmlEditorCore} this
41159 * @param {String} html
41164 * Fires when the iframe editor is updated with content from the textarea.
41165 * @param {Roo.HtmlEditorCore} this
41166 * @param {String} html
41171 * @event editorevent
41172 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41173 * @param {Roo.HtmlEditorCore} this
41179 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41181 // defaults : white / black...
41182 this.applyBlacklists();
41189 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41193 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41199 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41204 * @cfg {Number} height (in pixels)
41208 * @cfg {Number} width (in pixels)
41213 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41216 stylesheets: false,
41221 // private properties
41222 validationEvent : false,
41224 initialized : false,
41226 sourceEditMode : false,
41227 onFocus : Roo.emptyFn,
41229 hideMode:'offsets',
41233 // blacklist + whitelisted elements..
41240 * Protected method that will not generally be called directly. It
41241 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41242 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41244 getDocMarkup : function(){
41248 // inherit styels from page...??
41249 if (this.stylesheets === false) {
41251 Roo.get(document.head).select('style').each(function(node) {
41252 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41255 Roo.get(document.head).select('link').each(function(node) {
41256 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41259 } else if (!this.stylesheets.length) {
41261 st = '<style type="text/css">' +
41262 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41268 st += '<style type="text/css">' +
41269 'IMG { cursor: pointer } ' +
41273 return '<html><head>' + st +
41274 //<style type="text/css">' +
41275 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41277 ' </head><body class="roo-htmleditor-body"></body></html>';
41281 onRender : function(ct, position)
41284 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41285 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41288 this.el.dom.style.border = '0 none';
41289 this.el.dom.setAttribute('tabIndex', -1);
41290 this.el.addClass('x-hidden hide');
41294 if(Roo.isIE){ // fix IE 1px bogus margin
41295 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41299 this.frameId = Roo.id();
41303 var iframe = this.owner.wrap.createChild({
41305 cls: 'form-control', // bootstrap..
41307 name: this.frameId,
41308 frameBorder : 'no',
41309 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41314 this.iframe = iframe.dom;
41316 this.assignDocWin();
41318 this.doc.designMode = 'on';
41321 this.doc.write(this.getDocMarkup());
41325 var task = { // must defer to wait for browser to be ready
41327 //console.log("run task?" + this.doc.readyState);
41328 this.assignDocWin();
41329 if(this.doc.body || this.doc.readyState == 'complete'){
41331 this.doc.designMode="on";
41335 Roo.TaskMgr.stop(task);
41336 this.initEditor.defer(10, this);
41343 Roo.TaskMgr.start(task);
41348 onResize : function(w, h)
41350 Roo.log('resize: ' +w + ',' + h );
41351 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41355 if(typeof w == 'number'){
41357 this.iframe.style.width = w + 'px';
41359 if(typeof h == 'number'){
41361 this.iframe.style.height = h + 'px';
41363 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41370 * Toggles the editor between standard and source edit mode.
41371 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41373 toggleSourceEdit : function(sourceEditMode){
41375 this.sourceEditMode = sourceEditMode === true;
41377 if(this.sourceEditMode){
41379 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41382 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41383 //this.iframe.className = '';
41386 //this.setSize(this.owner.wrap.getSize());
41387 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41394 * Protected method that will not generally be called directly. If you need/want
41395 * custom HTML cleanup, this is the method you should override.
41396 * @param {String} html The HTML to be cleaned
41397 * return {String} The cleaned HTML
41399 cleanHtml : function(html){
41400 html = String(html);
41401 if(html.length > 5){
41402 if(Roo.isSafari){ // strip safari nonsense
41403 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41406 if(html == ' '){
41413 * HTML Editor -> Textarea
41414 * Protected method that will not generally be called directly. Syncs the contents
41415 * of the editor iframe with the textarea.
41417 syncValue : function(){
41418 if(this.initialized){
41419 var bd = (this.doc.body || this.doc.documentElement);
41420 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41421 var html = bd.innerHTML;
41423 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41424 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41426 html = '<div style="'+m[0]+'">' + html + '</div>';
41429 html = this.cleanHtml(html);
41430 // fix up the special chars.. normaly like back quotes in word...
41431 // however we do not want to do this with chinese..
41432 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41433 var cc = b.charCodeAt();
41435 (cc >= 0x4E00 && cc < 0xA000 ) ||
41436 (cc >= 0x3400 && cc < 0x4E00 ) ||
41437 (cc >= 0xf900 && cc < 0xfb00 )
41443 if(this.owner.fireEvent('beforesync', this, html) !== false){
41444 this.el.dom.value = html;
41445 this.owner.fireEvent('sync', this, html);
41451 * Protected method that will not generally be called directly. Pushes the value of the textarea
41452 * into the iframe editor.
41454 pushValue : function(){
41455 if(this.initialized){
41456 var v = this.el.dom.value.trim();
41458 // if(v.length < 1){
41462 if(this.owner.fireEvent('beforepush', this, v) !== false){
41463 var d = (this.doc.body || this.doc.documentElement);
41465 this.cleanUpPaste();
41466 this.el.dom.value = d.innerHTML;
41467 this.owner.fireEvent('push', this, v);
41473 deferFocus : function(){
41474 this.focus.defer(10, this);
41478 focus : function(){
41479 if(this.win && !this.sourceEditMode){
41486 assignDocWin: function()
41488 var iframe = this.iframe;
41491 this.doc = iframe.contentWindow.document;
41492 this.win = iframe.contentWindow;
41494 // if (!Roo.get(this.frameId)) {
41497 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41498 // this.win = Roo.get(this.frameId).dom.contentWindow;
41500 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41504 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41505 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41510 initEditor : function(){
41511 //console.log("INIT EDITOR");
41512 this.assignDocWin();
41516 this.doc.designMode="on";
41518 this.doc.write(this.getDocMarkup());
41521 var dbody = (this.doc.body || this.doc.documentElement);
41522 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41523 // this copies styles from the containing element into thsi one..
41524 // not sure why we need all of this..
41525 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41527 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41528 //ss['background-attachment'] = 'fixed'; // w3c
41529 dbody.bgProperties = 'fixed'; // ie
41530 //Roo.DomHelper.applyStyles(dbody, ss);
41531 Roo.EventManager.on(this.doc, {
41532 //'mousedown': this.onEditorEvent,
41533 'mouseup': this.onEditorEvent,
41534 'dblclick': this.onEditorEvent,
41535 'click': this.onEditorEvent,
41536 'keyup': this.onEditorEvent,
41541 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41543 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41544 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41546 this.initialized = true;
41548 this.owner.fireEvent('initialize', this);
41553 onDestroy : function(){
41559 //for (var i =0; i < this.toolbars.length;i++) {
41560 // // fixme - ask toolbars for heights?
41561 // this.toolbars[i].onDestroy();
41564 //this.wrap.dom.innerHTML = '';
41565 //this.wrap.remove();
41570 onFirstFocus : function(){
41572 this.assignDocWin();
41575 this.activated = true;
41578 if(Roo.isGecko){ // prevent silly gecko errors
41580 var s = this.win.getSelection();
41581 if(!s.focusNode || s.focusNode.nodeType != 3){
41582 var r = s.getRangeAt(0);
41583 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41588 this.execCmd('useCSS', true);
41589 this.execCmd('styleWithCSS', false);
41592 this.owner.fireEvent('activate', this);
41596 adjustFont: function(btn){
41597 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41598 //if(Roo.isSafari){ // safari
41601 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41602 if(Roo.isSafari){ // safari
41603 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41604 v = (v < 10) ? 10 : v;
41605 v = (v > 48) ? 48 : v;
41606 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41611 v = Math.max(1, v+adjust);
41613 this.execCmd('FontSize', v );
41616 onEditorEvent : function(e)
41618 this.owner.fireEvent('editorevent', this, e);
41619 // this.updateToolbar();
41620 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41623 insertTag : function(tg)
41625 // could be a bit smarter... -> wrap the current selected tRoo..
41626 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41628 range = this.createRange(this.getSelection());
41629 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41630 wrappingNode.appendChild(range.extractContents());
41631 range.insertNode(wrappingNode);
41638 this.execCmd("formatblock", tg);
41642 insertText : function(txt)
41646 var range = this.createRange();
41647 range.deleteContents();
41648 //alert(Sender.getAttribute('label'));
41650 range.insertNode(this.doc.createTextNode(txt));
41656 * Executes a Midas editor command on the editor document and performs necessary focus and
41657 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41658 * @param {String} cmd The Midas command
41659 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41661 relayCmd : function(cmd, value){
41663 this.execCmd(cmd, value);
41664 this.owner.fireEvent('editorevent', this);
41665 //this.updateToolbar();
41666 this.owner.deferFocus();
41670 * Executes a Midas editor command directly on the editor document.
41671 * For visual commands, you should use {@link #relayCmd} instead.
41672 * <b>This should only be called after the editor is initialized.</b>
41673 * @param {String} cmd The Midas command
41674 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41676 execCmd : function(cmd, value){
41677 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41684 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41686 * @param {String} text | dom node..
41688 insertAtCursor : function(text)
41693 if(!this.activated){
41699 var r = this.doc.selection.createRange();
41710 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41714 // from jquery ui (MIT licenced)
41716 var win = this.win;
41718 if (win.getSelection && win.getSelection().getRangeAt) {
41719 range = win.getSelection().getRangeAt(0);
41720 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41721 range.insertNode(node);
41722 } else if (win.document.selection && win.document.selection.createRange) {
41723 // no firefox support
41724 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41725 win.document.selection.createRange().pasteHTML(txt);
41727 // no firefox support
41728 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41729 this.execCmd('InsertHTML', txt);
41738 mozKeyPress : function(e){
41740 var c = e.getCharCode(), cmd;
41743 c = String.fromCharCode(c).toLowerCase();
41757 this.cleanUpPaste.defer(100, this);
41765 e.preventDefault();
41773 fixKeys : function(){ // load time branching for fastest keydown performance
41775 return function(e){
41776 var k = e.getKey(), r;
41779 r = this.doc.selection.createRange();
41782 r.pasteHTML('    ');
41789 r = this.doc.selection.createRange();
41791 var target = r.parentElement();
41792 if(!target || target.tagName.toLowerCase() != 'li'){
41794 r.pasteHTML('<br />');
41800 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41801 this.cleanUpPaste.defer(100, this);
41807 }else if(Roo.isOpera){
41808 return function(e){
41809 var k = e.getKey();
41813 this.execCmd('InsertHTML','    ');
41816 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41817 this.cleanUpPaste.defer(100, this);
41822 }else if(Roo.isSafari){
41823 return function(e){
41824 var k = e.getKey();
41828 this.execCmd('InsertText','\t');
41832 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41833 this.cleanUpPaste.defer(100, this);
41841 getAllAncestors: function()
41843 var p = this.getSelectedNode();
41846 a.push(p); // push blank onto stack..
41847 p = this.getParentElement();
41851 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41855 a.push(this.doc.body);
41859 lastSelNode : false,
41862 getSelection : function()
41864 this.assignDocWin();
41865 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41868 getSelectedNode: function()
41870 // this may only work on Gecko!!!
41872 // should we cache this!!!!
41877 var range = this.createRange(this.getSelection()).cloneRange();
41880 var parent = range.parentElement();
41882 var testRange = range.duplicate();
41883 testRange.moveToElementText(parent);
41884 if (testRange.inRange(range)) {
41887 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41890 parent = parent.parentElement;
41895 // is ancestor a text element.
41896 var ac = range.commonAncestorContainer;
41897 if (ac.nodeType == 3) {
41898 ac = ac.parentNode;
41901 var ar = ac.childNodes;
41904 var other_nodes = [];
41905 var has_other_nodes = false;
41906 for (var i=0;i<ar.length;i++) {
41907 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41910 // fullly contained node.
41912 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41917 // probably selected..
41918 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41919 other_nodes.push(ar[i]);
41923 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41928 has_other_nodes = true;
41930 if (!nodes.length && other_nodes.length) {
41931 nodes= other_nodes;
41933 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41939 createRange: function(sel)
41941 // this has strange effects when using with
41942 // top toolbar - not sure if it's a great idea.
41943 //this.editor.contentWindow.focus();
41944 if (typeof sel != "undefined") {
41946 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41948 return this.doc.createRange();
41951 return this.doc.createRange();
41954 getParentElement: function()
41957 this.assignDocWin();
41958 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41960 var range = this.createRange(sel);
41963 var p = range.commonAncestorContainer;
41964 while (p.nodeType == 3) { // text node
41975 * Range intersection.. the hard stuff...
41979 * [ -- selected range --- ]
41983 * if end is before start or hits it. fail.
41984 * if start is after end or hits it fail.
41986 * if either hits (but other is outside. - then it's not
41992 // @see http://www.thismuchiknow.co.uk/?p=64.
41993 rangeIntersectsNode : function(range, node)
41995 var nodeRange = node.ownerDocument.createRange();
41997 nodeRange.selectNode(node);
41999 nodeRange.selectNodeContents(node);
42002 var rangeStartRange = range.cloneRange();
42003 rangeStartRange.collapse(true);
42005 var rangeEndRange = range.cloneRange();
42006 rangeEndRange.collapse(false);
42008 var nodeStartRange = nodeRange.cloneRange();
42009 nodeStartRange.collapse(true);
42011 var nodeEndRange = nodeRange.cloneRange();
42012 nodeEndRange.collapse(false);
42014 return rangeStartRange.compareBoundaryPoints(
42015 Range.START_TO_START, nodeEndRange) == -1 &&
42016 rangeEndRange.compareBoundaryPoints(
42017 Range.START_TO_START, nodeStartRange) == 1;
42021 rangeCompareNode : function(range, node)
42023 var nodeRange = node.ownerDocument.createRange();
42025 nodeRange.selectNode(node);
42027 nodeRange.selectNodeContents(node);
42031 range.collapse(true);
42033 nodeRange.collapse(true);
42035 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42036 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42038 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42040 var nodeIsBefore = ss == 1;
42041 var nodeIsAfter = ee == -1;
42043 if (nodeIsBefore && nodeIsAfter)
42045 if (!nodeIsBefore && nodeIsAfter)
42046 return 1; //right trailed.
42048 if (nodeIsBefore && !nodeIsAfter)
42049 return 2; // left trailed.
42054 // private? - in a new class?
42055 cleanUpPaste : function()
42057 // cleans up the whole document..
42058 Roo.log('cleanuppaste');
42060 this.cleanUpChildren(this.doc.body);
42061 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42062 if (clean != this.doc.body.innerHTML) {
42063 this.doc.body.innerHTML = clean;
42068 cleanWordChars : function(input) {// change the chars to hex code
42069 var he = Roo.HtmlEditorCore;
42071 var output = input;
42072 Roo.each(he.swapCodes, function(sw) {
42073 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42075 output = output.replace(swapper, sw[1]);
42082 cleanUpChildren : function (n)
42084 if (!n.childNodes.length) {
42087 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42088 this.cleanUpChild(n.childNodes[i]);
42095 cleanUpChild : function (node)
42098 //console.log(node);
42099 if (node.nodeName == "#text") {
42100 // clean up silly Windows -- stuff?
42103 if (node.nodeName == "#comment") {
42104 node.parentNode.removeChild(node);
42105 // clean up silly Windows -- stuff?
42108 var lcname = node.tagName.toLowerCase();
42109 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42110 // whitelist of tags..
42112 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42114 node.parentNode.removeChild(node);
42119 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42121 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42122 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42124 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42125 // remove_keep_children = true;
42128 if (remove_keep_children) {
42129 this.cleanUpChildren(node);
42130 // inserts everything just before this node...
42131 while (node.childNodes.length) {
42132 var cn = node.childNodes[0];
42133 node.removeChild(cn);
42134 node.parentNode.insertBefore(cn, node);
42136 node.parentNode.removeChild(node);
42140 if (!node.attributes || !node.attributes.length) {
42141 this.cleanUpChildren(node);
42145 function cleanAttr(n,v)
42148 if (v.match(/^\./) || v.match(/^\//)) {
42151 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42154 if (v.match(/^#/)) {
42157 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42158 node.removeAttribute(n);
42162 var cwhite = this.cwhite;
42163 var cblack = this.cblack;
42165 function cleanStyle(n,v)
42167 if (v.match(/expression/)) { //XSS?? should we even bother..
42168 node.removeAttribute(n);
42172 var parts = v.split(/;/);
42175 Roo.each(parts, function(p) {
42176 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42180 var l = p.split(':').shift().replace(/\s+/g,'');
42181 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42183 if ( cwhite.length && cblack.indexOf(l) > -1) {
42184 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42185 //node.removeAttribute(n);
42189 // only allow 'c whitelisted system attributes'
42190 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42191 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42192 //node.removeAttribute(n);
42202 if (clean.length) {
42203 node.setAttribute(n, clean.join(';'));
42205 node.removeAttribute(n);
42211 for (var i = node.attributes.length-1; i > -1 ; i--) {
42212 var a = node.attributes[i];
42215 if (a.name.toLowerCase().substr(0,2)=='on') {
42216 node.removeAttribute(a.name);
42219 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42220 node.removeAttribute(a.name);
42223 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42224 cleanAttr(a.name,a.value); // fixme..
42227 if (a.name == 'style') {
42228 cleanStyle(a.name,a.value);
42231 /// clean up MS crap..
42232 // tecnically this should be a list of valid class'es..
42235 if (a.name == 'class') {
42236 if (a.value.match(/^Mso/)) {
42237 node.className = '';
42240 if (a.value.match(/body/)) {
42241 node.className = '';
42252 this.cleanUpChildren(node);
42258 * Clean up MS wordisms...
42260 cleanWord : function(node)
42265 this.cleanWord(this.doc.body);
42268 if (node.nodeName == "#text") {
42269 // clean up silly Windows -- stuff?
42272 if (node.nodeName == "#comment") {
42273 node.parentNode.removeChild(node);
42274 // clean up silly Windows -- stuff?
42278 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42279 node.parentNode.removeChild(node);
42283 // remove - but keep children..
42284 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42285 while (node.childNodes.length) {
42286 var cn = node.childNodes[0];
42287 node.removeChild(cn);
42288 node.parentNode.insertBefore(cn, node);
42290 node.parentNode.removeChild(node);
42291 this.iterateChildren(node, this.cleanWord);
42295 if (node.className.length) {
42297 var cn = node.className.split(/\W+/);
42299 Roo.each(cn, function(cls) {
42300 if (cls.match(/Mso[a-zA-Z]+/)) {
42305 node.className = cna.length ? cna.join(' ') : '';
42307 node.removeAttribute("class");
42311 if (node.hasAttribute("lang")) {
42312 node.removeAttribute("lang");
42315 if (node.hasAttribute("style")) {
42317 var styles = node.getAttribute("style").split(";");
42319 Roo.each(styles, function(s) {
42320 if (!s.match(/:/)) {
42323 var kv = s.split(":");
42324 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42327 // what ever is left... we allow.
42330 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42331 if (!nstyle.length) {
42332 node.removeAttribute('style');
42335 this.iterateChildren(node, this.cleanWord);
42341 * iterateChildren of a Node, calling fn each time, using this as the scole..
42342 * @param {DomNode} node node to iterate children of.
42343 * @param {Function} fn method of this class to call on each item.
42345 iterateChildren : function(node, fn)
42347 if (!node.childNodes.length) {
42350 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42351 fn.call(this, node.childNodes[i])
42357 * cleanTableWidths.
42359 * Quite often pasting from word etc.. results in tables with column and widths.
42360 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42363 cleanTableWidths : function(node)
42368 this.cleanTableWidths(this.doc.body);
42373 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42376 Roo.log(node.tagName);
42377 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42378 this.iterateChildren(node, this.cleanTableWidths);
42381 if (node.hasAttribute('width')) {
42382 node.removeAttribute('width');
42386 if (node.hasAttribute("style")) {
42389 var styles = node.getAttribute("style").split(";");
42391 Roo.each(styles, function(s) {
42392 if (!s.match(/:/)) {
42395 var kv = s.split(":");
42396 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42399 // what ever is left... we allow.
42402 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42403 if (!nstyle.length) {
42404 node.removeAttribute('style');
42408 this.iterateChildren(node, this.cleanTableWidths);
42416 domToHTML : function(currentElement, depth, nopadtext) {
42418 depth = depth || 0;
42419 nopadtext = nopadtext || false;
42421 if (!currentElement) {
42422 return this.domToHTML(this.doc.body);
42425 //Roo.log(currentElement);
42427 var allText = false;
42428 var nodeName = currentElement.nodeName;
42429 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42431 if (nodeName == '#text') {
42433 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42438 if (nodeName != 'BODY') {
42441 // Prints the node tagName, such as <A>, <IMG>, etc
42444 for(i = 0; i < currentElement.attributes.length;i++) {
42446 var aname = currentElement.attributes.item(i).name;
42447 if (!currentElement.attributes.item(i).value.length) {
42450 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42453 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42462 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42465 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42470 // Traverse the tree
42472 var currentElementChild = currentElement.childNodes.item(i);
42473 var allText = true;
42474 var innerHTML = '';
42476 while (currentElementChild) {
42477 // Formatting code (indent the tree so it looks nice on the screen)
42478 var nopad = nopadtext;
42479 if (lastnode == 'SPAN') {
42483 if (currentElementChild.nodeName == '#text') {
42484 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42485 toadd = nopadtext ? toadd : toadd.trim();
42486 if (!nopad && toadd.length > 80) {
42487 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42489 innerHTML += toadd;
42492 currentElementChild = currentElement.childNodes.item(i);
42498 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42500 // Recursively traverse the tree structure of the child node
42501 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42502 lastnode = currentElementChild.nodeName;
42504 currentElementChild=currentElement.childNodes.item(i);
42510 // The remaining code is mostly for formatting the tree
42511 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42516 ret+= "</"+tagName+">";
42522 applyBlacklists : function()
42524 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42525 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42529 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42530 if (b.indexOf(tag) > -1) {
42533 this.white.push(tag);
42537 Roo.each(w, function(tag) {
42538 if (b.indexOf(tag) > -1) {
42541 if (this.white.indexOf(tag) > -1) {
42544 this.white.push(tag);
42549 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42550 if (w.indexOf(tag) > -1) {
42553 this.black.push(tag);
42557 Roo.each(b, function(tag) {
42558 if (w.indexOf(tag) > -1) {
42561 if (this.black.indexOf(tag) > -1) {
42564 this.black.push(tag);
42569 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42570 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42574 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42575 if (b.indexOf(tag) > -1) {
42578 this.cwhite.push(tag);
42582 Roo.each(w, function(tag) {
42583 if (b.indexOf(tag) > -1) {
42586 if (this.cwhite.indexOf(tag) > -1) {
42589 this.cwhite.push(tag);
42594 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42595 if (w.indexOf(tag) > -1) {
42598 this.cblack.push(tag);
42602 Roo.each(b, function(tag) {
42603 if (w.indexOf(tag) > -1) {
42606 if (this.cblack.indexOf(tag) > -1) {
42609 this.cblack.push(tag);
42614 setStylesheets : function(stylesheets)
42616 if(typeof(stylesheets) == 'string'){
42617 Roo.get(this.iframe.contentDocument.head).createChild({
42619 rel : 'stylesheet',
42628 Roo.each(stylesheets, function(s) {
42633 Roo.get(_this.iframe.contentDocument.head).createChild({
42635 rel : 'stylesheet',
42644 removeStylesheets : function()
42648 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42653 // hide stuff that is not compatible
42667 * @event specialkey
42671 * @cfg {String} fieldClass @hide
42674 * @cfg {String} focusClass @hide
42677 * @cfg {String} autoCreate @hide
42680 * @cfg {String} inputType @hide
42683 * @cfg {String} invalidClass @hide
42686 * @cfg {String} invalidText @hide
42689 * @cfg {String} msgFx @hide
42692 * @cfg {String} validateOnBlur @hide
42696 Roo.HtmlEditorCore.white = [
42697 'area', 'br', 'img', 'input', 'hr', 'wbr',
42699 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42700 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42701 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42702 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42703 'table', 'ul', 'xmp',
42705 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42708 'dir', 'menu', 'ol', 'ul', 'dl',
42714 Roo.HtmlEditorCore.black = [
42715 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42717 'base', 'basefont', 'bgsound', 'blink', 'body',
42718 'frame', 'frameset', 'head', 'html', 'ilayer',
42719 'iframe', 'layer', 'link', 'meta', 'object',
42720 'script', 'style' ,'title', 'xml' // clean later..
42722 Roo.HtmlEditorCore.clean = [
42723 'script', 'style', 'title', 'xml'
42725 Roo.HtmlEditorCore.remove = [
42730 Roo.HtmlEditorCore.ablack = [
42734 Roo.HtmlEditorCore.aclean = [
42735 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42739 Roo.HtmlEditorCore.pwhite= [
42740 'http', 'https', 'mailto'
42743 // white listed style attributes.
42744 Roo.HtmlEditorCore.cwhite= [
42745 // 'text-align', /// default is to allow most things..
42751 // black listed style attributes.
42752 Roo.HtmlEditorCore.cblack= [
42753 // 'font-size' -- this can be set by the project
42757 Roo.HtmlEditorCore.swapCodes =[
42768 //<script type="text/javascript">
42771 * Ext JS Library 1.1.1
42772 * Copyright(c) 2006-2007, Ext JS, LLC.
42778 Roo.form.HtmlEditor = function(config){
42782 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42784 if (!this.toolbars) {
42785 this.toolbars = [];
42787 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42793 * @class Roo.form.HtmlEditor
42794 * @extends Roo.form.Field
42795 * Provides a lightweight HTML Editor component.
42797 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42799 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42800 * supported by this editor.</b><br/><br/>
42801 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42802 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42804 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42806 * @cfg {Boolean} clearUp
42810 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42815 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42820 * @cfg {Number} height (in pixels)
42824 * @cfg {Number} width (in pixels)
42829 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42832 stylesheets: false,
42836 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42841 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42847 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42852 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42860 // private properties
42861 validationEvent : false,
42863 initialized : false,
42866 onFocus : Roo.emptyFn,
42868 hideMode:'offsets',
42870 actionMode : 'container', // defaults to hiding it...
42872 defaultAutoCreate : { // modified by initCompnoent..
42874 style:"width:500px;height:300px;",
42875 autocomplete: "new-password"
42879 initComponent : function(){
42882 * @event initialize
42883 * Fires when the editor is fully initialized (including the iframe)
42884 * @param {HtmlEditor} this
42889 * Fires when the editor is first receives the focus. Any insertion must wait
42890 * until after this event.
42891 * @param {HtmlEditor} this
42895 * @event beforesync
42896 * Fires before the textarea is updated with content from the editor iframe. Return false
42897 * to cancel the sync.
42898 * @param {HtmlEditor} this
42899 * @param {String} html
42903 * @event beforepush
42904 * Fires before the iframe editor is updated with content from the textarea. Return false
42905 * to cancel the push.
42906 * @param {HtmlEditor} this
42907 * @param {String} html
42912 * Fires when the textarea is updated with content from the editor iframe.
42913 * @param {HtmlEditor} this
42914 * @param {String} html
42919 * Fires when the iframe editor is updated with content from the textarea.
42920 * @param {HtmlEditor} this
42921 * @param {String} html
42925 * @event editmodechange
42926 * Fires when the editor switches edit modes
42927 * @param {HtmlEditor} this
42928 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42930 editmodechange: true,
42932 * @event editorevent
42933 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42934 * @param {HtmlEditor} this
42938 * @event firstfocus
42939 * Fires when on first focus - needed by toolbars..
42940 * @param {HtmlEditor} this
42945 * Auto save the htmlEditor value as a file into Events
42946 * @param {HtmlEditor} this
42950 * @event savedpreview
42951 * preview the saved version of htmlEditor
42952 * @param {HtmlEditor} this
42954 savedpreview: true,
42957 * @event stylesheetsclick
42958 * Fires when press the Sytlesheets button
42959 * @param {Roo.HtmlEditorCore} this
42961 stylesheetsclick: true
42963 this.defaultAutoCreate = {
42965 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42966 autocomplete: "new-password"
42971 * Protected method that will not generally be called directly. It
42972 * is called when the editor creates its toolbar. Override this method if you need to
42973 * add custom toolbar buttons.
42974 * @param {HtmlEditor} editor
42976 createToolbar : function(editor){
42977 Roo.log("create toolbars");
42978 if (!editor.toolbars || !editor.toolbars.length) {
42979 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42982 for (var i =0 ; i < editor.toolbars.length;i++) {
42983 editor.toolbars[i] = Roo.factory(
42984 typeof(editor.toolbars[i]) == 'string' ?
42985 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42986 Roo.form.HtmlEditor);
42987 editor.toolbars[i].init(editor);
42995 onRender : function(ct, position)
42998 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
43000 this.wrap = this.el.wrap({
43001 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43004 this.editorcore.onRender(ct, position);
43006 if (this.resizable) {
43007 this.resizeEl = new Roo.Resizable(this.wrap, {
43011 minHeight : this.height,
43012 height: this.height,
43013 handles : this.resizable,
43016 resize : function(r, w, h) {
43017 _t.onResize(w,h); // -something
43023 this.createToolbar(this);
43027 this.setSize(this.wrap.getSize());
43029 if (this.resizeEl) {
43030 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43031 // should trigger onReize..
43034 this.keyNav = new Roo.KeyNav(this.el, {
43036 "tab" : function(e){
43037 e.preventDefault();
43039 var value = this.getValue();
43041 var start = this.el.dom.selectionStart;
43042 var end = this.el.dom.selectionEnd;
43046 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43047 this.el.dom.setSelectionRange(end + 1, end + 1);
43051 var f = value.substring(0, start).split("\t");
43053 if(f.pop().length != 0){
43057 this.setValue(f.join("\t") + value.substring(end));
43058 this.el.dom.setSelectionRange(start - 1, start - 1);
43062 "home" : function(e){
43063 e.preventDefault();
43065 var curr = this.el.dom.selectionStart;
43066 var lines = this.getValue().split("\n");
43073 this.el.dom.setSelectionRange(0, 0);
43079 for (var i = 0; i < lines.length;i++) {
43080 pos += lines[i].length;
43090 pos -= lines[i].length;
43096 this.el.dom.setSelectionRange(pos, pos);
43100 this.el.dom.selectionStart = pos;
43101 this.el.dom.selectionEnd = curr;
43104 "end" : function(e){
43105 e.preventDefault();
43107 var curr = this.el.dom.selectionStart;
43108 var lines = this.getValue().split("\n");
43115 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43121 for (var i = 0; i < lines.length;i++) {
43123 pos += lines[i].length;
43137 this.el.dom.setSelectionRange(pos, pos);
43141 this.el.dom.selectionStart = curr;
43142 this.el.dom.selectionEnd = pos;
43147 doRelay : function(foo, bar, hname){
43148 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43154 // if(this.autosave && this.w){
43155 // this.autoSaveFn = setInterval(this.autosave, 1000);
43160 onResize : function(w, h)
43162 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43167 if(typeof w == 'number'){
43168 var aw = w - this.wrap.getFrameWidth('lr');
43169 this.el.setWidth(this.adjustWidth('textarea', aw));
43172 if(typeof h == 'number'){
43174 for (var i =0; i < this.toolbars.length;i++) {
43175 // fixme - ask toolbars for heights?
43176 tbh += this.toolbars[i].tb.el.getHeight();
43177 if (this.toolbars[i].footer) {
43178 tbh += this.toolbars[i].footer.el.getHeight();
43185 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43186 ah -= 5; // knock a few pixes off for look..
43188 this.el.setHeight(this.adjustWidth('textarea', ah));
43192 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43193 this.editorcore.onResize(ew,eh);
43198 * Toggles the editor between standard and source edit mode.
43199 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43201 toggleSourceEdit : function(sourceEditMode)
43203 this.editorcore.toggleSourceEdit(sourceEditMode);
43205 if(this.editorcore.sourceEditMode){
43206 Roo.log('editor - showing textarea');
43209 // Roo.log(this.syncValue());
43210 this.editorcore.syncValue();
43211 this.el.removeClass('x-hidden');
43212 this.el.dom.removeAttribute('tabIndex');
43215 for (var i = 0; i < this.toolbars.length; i++) {
43216 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43217 this.toolbars[i].tb.hide();
43218 this.toolbars[i].footer.hide();
43223 Roo.log('editor - hiding textarea');
43225 // Roo.log(this.pushValue());
43226 this.editorcore.pushValue();
43228 this.el.addClass('x-hidden');
43229 this.el.dom.setAttribute('tabIndex', -1);
43231 for (var i = 0; i < this.toolbars.length; i++) {
43232 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43233 this.toolbars[i].tb.show();
43234 this.toolbars[i].footer.show();
43238 //this.deferFocus();
43241 this.setSize(this.wrap.getSize());
43242 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43244 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43247 // private (for BoxComponent)
43248 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43250 // private (for BoxComponent)
43251 getResizeEl : function(){
43255 // private (for BoxComponent)
43256 getPositionEl : function(){
43261 initEvents : function(){
43262 this.originalValue = this.getValue();
43266 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43269 markInvalid : Roo.emptyFn,
43271 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43274 clearInvalid : Roo.emptyFn,
43276 setValue : function(v){
43277 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43278 this.editorcore.pushValue();
43283 deferFocus : function(){
43284 this.focus.defer(10, this);
43288 focus : function(){
43289 this.editorcore.focus();
43295 onDestroy : function(){
43301 for (var i =0; i < this.toolbars.length;i++) {
43302 // fixme - ask toolbars for heights?
43303 this.toolbars[i].onDestroy();
43306 this.wrap.dom.innerHTML = '';
43307 this.wrap.remove();
43312 onFirstFocus : function(){
43313 //Roo.log("onFirstFocus");
43314 this.editorcore.onFirstFocus();
43315 for (var i =0; i < this.toolbars.length;i++) {
43316 this.toolbars[i].onFirstFocus();
43322 syncValue : function()
43324 this.editorcore.syncValue();
43327 pushValue : function()
43329 this.editorcore.pushValue();
43332 setStylesheets : function(stylesheets)
43334 this.editorcore.setStylesheets(stylesheets);
43337 removeStylesheets : function()
43339 this.editorcore.removeStylesheets();
43343 // hide stuff that is not compatible
43357 * @event specialkey
43361 * @cfg {String} fieldClass @hide
43364 * @cfg {String} focusClass @hide
43367 * @cfg {String} autoCreate @hide
43370 * @cfg {String} inputType @hide
43373 * @cfg {String} invalidClass @hide
43376 * @cfg {String} invalidText @hide
43379 * @cfg {String} msgFx @hide
43382 * @cfg {String} validateOnBlur @hide
43386 // <script type="text/javascript">
43389 * Ext JS Library 1.1.1
43390 * Copyright(c) 2006-2007, Ext JS, LLC.
43396 * @class Roo.form.HtmlEditorToolbar1
43401 new Roo.form.HtmlEditor({
43404 new Roo.form.HtmlEditorToolbar1({
43405 disable : { fonts: 1 , format: 1, ..., ... , ...],
43411 * @cfg {Object} disable List of elements to disable..
43412 * @cfg {Array} btns List of additional buttons.
43416 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43419 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43422 Roo.apply(this, config);
43424 // default disabled, based on 'good practice'..
43425 this.disable = this.disable || {};
43426 Roo.applyIf(this.disable, {
43429 specialElements : true
43433 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43434 // dont call parent... till later.
43437 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43444 editorcore : false,
43446 * @cfg {Object} disable List of toolbar elements to disable
43453 * @cfg {String} createLinkText The default text for the create link prompt
43455 createLinkText : 'Please enter the URL for the link:',
43457 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43459 defaultLinkValue : 'http:/'+'/',
43463 * @cfg {Array} fontFamilies An array of available font families
43481 // "á" , ?? a acute?
43486 "°" // , // degrees
43488 // "é" , // e ecute
43489 // "ú" , // u ecute?
43492 specialElements : [
43494 text: "Insert Table",
43497 ihtml : '<table><tr><td>Cell</td></tr></table>'
43501 text: "Insert Image",
43504 ihtml : '<img src="about:blank"/>'
43513 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43514 "input:submit", "input:button", "select", "textarea", "label" ],
43517 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43519 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43527 * @cfg {String} defaultFont default font to use.
43529 defaultFont: 'tahoma',
43531 fontSelect : false,
43534 formatCombo : false,
43536 init : function(editor)
43538 this.editor = editor;
43539 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43540 var editorcore = this.editorcore;
43544 var fid = editorcore.frameId;
43546 function btn(id, toggle, handler){
43547 var xid = fid + '-'+ id ;
43551 cls : 'x-btn-icon x-edit-'+id,
43552 enableToggle:toggle !== false,
43553 scope: _t, // was editor...
43554 handler:handler||_t.relayBtnCmd,
43555 clickEvent:'mousedown',
43556 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43563 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43565 // stop form submits
43566 tb.el.on('click', function(e){
43567 e.preventDefault(); // what does this do?
43570 if(!this.disable.font) { // && !Roo.isSafari){
43571 /* why no safari for fonts
43572 editor.fontSelect = tb.el.createChild({
43575 cls:'x-font-select',
43576 html: this.createFontOptions()
43579 editor.fontSelect.on('change', function(){
43580 var font = editor.fontSelect.dom.value;
43581 editor.relayCmd('fontname', font);
43582 editor.deferFocus();
43586 editor.fontSelect.dom,
43592 if(!this.disable.formats){
43593 this.formatCombo = new Roo.form.ComboBox({
43594 store: new Roo.data.SimpleStore({
43597 data : this.formats // from states.js
43601 //autoCreate : {tag: "div", size: "20"},
43602 displayField:'tag',
43606 triggerAction: 'all',
43607 emptyText:'Add tag',
43608 selectOnFocus:true,
43611 'select': function(c, r, i) {
43612 editorcore.insertTag(r.get('tag'));
43618 tb.addField(this.formatCombo);
43622 if(!this.disable.format){
43629 if(!this.disable.fontSize){
43634 btn('increasefontsize', false, editorcore.adjustFont),
43635 btn('decreasefontsize', false, editorcore.adjustFont)
43640 if(!this.disable.colors){
43643 id:editorcore.frameId +'-forecolor',
43644 cls:'x-btn-icon x-edit-forecolor',
43645 clickEvent:'mousedown',
43646 tooltip: this.buttonTips['forecolor'] || undefined,
43648 menu : new Roo.menu.ColorMenu({
43649 allowReselect: true,
43650 focus: Roo.emptyFn,
43653 selectHandler: function(cp, color){
43654 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43655 editor.deferFocus();
43658 clickEvent:'mousedown'
43661 id:editorcore.frameId +'backcolor',
43662 cls:'x-btn-icon x-edit-backcolor',
43663 clickEvent:'mousedown',
43664 tooltip: this.buttonTips['backcolor'] || undefined,
43666 menu : new Roo.menu.ColorMenu({
43667 focus: Roo.emptyFn,
43670 allowReselect: true,
43671 selectHandler: function(cp, color){
43673 editorcore.execCmd('useCSS', false);
43674 editorcore.execCmd('hilitecolor', color);
43675 editorcore.execCmd('useCSS', true);
43676 editor.deferFocus();
43678 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43679 Roo.isSafari || Roo.isIE ? '#'+color : color);
43680 editor.deferFocus();
43684 clickEvent:'mousedown'
43689 // now add all the items...
43692 if(!this.disable.alignments){
43695 btn('justifyleft'),
43696 btn('justifycenter'),
43697 btn('justifyright')
43701 //if(!Roo.isSafari){
43702 if(!this.disable.links){
43705 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43709 if(!this.disable.lists){
43712 btn('insertorderedlist'),
43713 btn('insertunorderedlist')
43716 if(!this.disable.sourceEdit){
43719 btn('sourceedit', true, function(btn){
43720 this.toggleSourceEdit(btn.pressed);
43727 // special menu.. - needs to be tidied up..
43728 if (!this.disable.special) {
43731 cls: 'x-edit-none',
43737 for (var i =0; i < this.specialChars.length; i++) {
43738 smenu.menu.items.push({
43740 html: this.specialChars[i],
43741 handler: function(a,b) {
43742 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43743 //editor.insertAtCursor(a.html);
43757 if (!this.disable.cleanStyles) {
43759 cls: 'x-btn-icon x-btn-clear',
43765 for (var i =0; i < this.cleanStyles.length; i++) {
43766 cmenu.menu.items.push({
43767 actiontype : this.cleanStyles[i],
43768 html: 'Remove ' + this.cleanStyles[i],
43769 handler: function(a,b) {
43772 var c = Roo.get(editorcore.doc.body);
43773 c.select('[style]').each(function(s) {
43774 s.dom.style.removeProperty(a.actiontype);
43776 editorcore.syncValue();
43781 cmenu.menu.items.push({
43782 actiontype : 'tablewidths',
43783 html: 'Remove Table Widths',
43784 handler: function(a,b) {
43785 editorcore.cleanTableWidths();
43786 editorcore.syncValue();
43790 cmenu.menu.items.push({
43791 actiontype : 'word',
43792 html: 'Remove MS Word Formating',
43793 handler: function(a,b) {
43794 editorcore.cleanWord();
43795 editorcore.syncValue();
43800 cmenu.menu.items.push({
43801 actiontype : 'all',
43802 html: 'Remove All Styles',
43803 handler: function(a,b) {
43805 var c = Roo.get(editorcore.doc.body);
43806 c.select('[style]').each(function(s) {
43807 s.dom.removeAttribute('style');
43809 editorcore.syncValue();
43813 cmenu.menu.items.push({
43814 actiontype : 'tidy',
43815 html: 'Tidy HTML Source',
43816 handler: function(a,b) {
43817 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43818 editorcore.syncValue();
43827 if (!this.disable.specialElements) {
43830 cls: 'x-edit-none',
43835 for (var i =0; i < this.specialElements.length; i++) {
43836 semenu.menu.items.push(
43838 handler: function(a,b) {
43839 editor.insertAtCursor(this.ihtml);
43841 }, this.specialElements[i])
43853 for(var i =0; i< this.btns.length;i++) {
43854 var b = Roo.factory(this.btns[i],Roo.form);
43855 b.cls = 'x-edit-none';
43857 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43858 b.cls += ' x-init-enable';
43861 b.scope = editorcore;
43869 // disable everything...
43871 this.tb.items.each(function(item){
43874 item.id != editorcore.frameId+ '-sourceedit' &&
43875 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43881 this.rendered = true;
43883 // the all the btns;
43884 editor.on('editorevent', this.updateToolbar, this);
43885 // other toolbars need to implement this..
43886 //editor.on('editmodechange', this.updateToolbar, this);
43890 relayBtnCmd : function(btn) {
43891 this.editorcore.relayCmd(btn.cmd);
43893 // private used internally
43894 createLink : function(){
43895 Roo.log("create link?");
43896 var url = prompt(this.createLinkText, this.defaultLinkValue);
43897 if(url && url != 'http:/'+'/'){
43898 this.editorcore.relayCmd('createlink', url);
43904 * Protected method that will not generally be called directly. It triggers
43905 * a toolbar update by reading the markup state of the current selection in the editor.
43907 updateToolbar: function(){
43909 if(!this.editorcore.activated){
43910 this.editor.onFirstFocus();
43914 var btns = this.tb.items.map,
43915 doc = this.editorcore.doc,
43916 frameId = this.editorcore.frameId;
43918 if(!this.disable.font && !Roo.isSafari){
43920 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43921 if(name != this.fontSelect.dom.value){
43922 this.fontSelect.dom.value = name;
43926 if(!this.disable.format){
43927 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43928 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43929 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43931 if(!this.disable.alignments){
43932 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43933 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43934 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43936 if(!Roo.isSafari && !this.disable.lists){
43937 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43938 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43941 var ans = this.editorcore.getAllAncestors();
43942 if (this.formatCombo) {
43945 var store = this.formatCombo.store;
43946 this.formatCombo.setValue("");
43947 for (var i =0; i < ans.length;i++) {
43948 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43950 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43958 // hides menus... - so this cant be on a menu...
43959 Roo.menu.MenuMgr.hideAll();
43961 //this.editorsyncValue();
43965 createFontOptions : function(){
43966 var buf = [], fs = this.fontFamilies, ff, lc;
43970 for(var i = 0, len = fs.length; i< len; i++){
43972 lc = ff.toLowerCase();
43974 '<option value="',lc,'" style="font-family:',ff,';"',
43975 (this.defaultFont == lc ? ' selected="true">' : '>'),
43980 return buf.join('');
43983 toggleSourceEdit : function(sourceEditMode){
43985 Roo.log("toolbar toogle");
43986 if(sourceEditMode === undefined){
43987 sourceEditMode = !this.sourceEditMode;
43989 this.sourceEditMode = sourceEditMode === true;
43990 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43991 // just toggle the button?
43992 if(btn.pressed !== this.sourceEditMode){
43993 btn.toggle(this.sourceEditMode);
43997 if(sourceEditMode){
43998 Roo.log("disabling buttons");
43999 this.tb.items.each(function(item){
44000 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44006 Roo.log("enabling buttons");
44007 if(this.editorcore.initialized){
44008 this.tb.items.each(function(item){
44014 Roo.log("calling toggole on editor");
44015 // tell the editor that it's been pressed..
44016 this.editor.toggleSourceEdit(sourceEditMode);
44020 * Object collection of toolbar tooltips for the buttons in the editor. The key
44021 * is the command id associated with that button and the value is a valid QuickTips object.
44026 title: 'Bold (Ctrl+B)',
44027 text: 'Make the selected text bold.',
44028 cls: 'x-html-editor-tip'
44031 title: 'Italic (Ctrl+I)',
44032 text: 'Make the selected text italic.',
44033 cls: 'x-html-editor-tip'
44041 title: 'Bold (Ctrl+B)',
44042 text: 'Make the selected text bold.',
44043 cls: 'x-html-editor-tip'
44046 title: 'Italic (Ctrl+I)',
44047 text: 'Make the selected text italic.',
44048 cls: 'x-html-editor-tip'
44051 title: 'Underline (Ctrl+U)',
44052 text: 'Underline the selected text.',
44053 cls: 'x-html-editor-tip'
44055 increasefontsize : {
44056 title: 'Grow Text',
44057 text: 'Increase the font size.',
44058 cls: 'x-html-editor-tip'
44060 decreasefontsize : {
44061 title: 'Shrink Text',
44062 text: 'Decrease the font size.',
44063 cls: 'x-html-editor-tip'
44066 title: 'Text Highlight Color',
44067 text: 'Change the background color of the selected text.',
44068 cls: 'x-html-editor-tip'
44071 title: 'Font Color',
44072 text: 'Change the color of the selected text.',
44073 cls: 'x-html-editor-tip'
44076 title: 'Align Text Left',
44077 text: 'Align text to the left.',
44078 cls: 'x-html-editor-tip'
44081 title: 'Center Text',
44082 text: 'Center text in the editor.',
44083 cls: 'x-html-editor-tip'
44086 title: 'Align Text Right',
44087 text: 'Align text to the right.',
44088 cls: 'x-html-editor-tip'
44090 insertunorderedlist : {
44091 title: 'Bullet List',
44092 text: 'Start a bulleted list.',
44093 cls: 'x-html-editor-tip'
44095 insertorderedlist : {
44096 title: 'Numbered List',
44097 text: 'Start a numbered list.',
44098 cls: 'x-html-editor-tip'
44101 title: 'Hyperlink',
44102 text: 'Make the selected text a hyperlink.',
44103 cls: 'x-html-editor-tip'
44106 title: 'Source Edit',
44107 text: 'Switch to source editing mode.',
44108 cls: 'x-html-editor-tip'
44112 onDestroy : function(){
44115 this.tb.items.each(function(item){
44117 item.menu.removeAll();
44119 item.menu.el.destroy();
44127 onFirstFocus: function() {
44128 this.tb.items.each(function(item){
44137 // <script type="text/javascript">
44140 * Ext JS Library 1.1.1
44141 * Copyright(c) 2006-2007, Ext JS, LLC.
44148 * @class Roo.form.HtmlEditor.ToolbarContext
44153 new Roo.form.HtmlEditor({
44156 { xtype: 'ToolbarStandard', styles : {} }
44157 { xtype: 'ToolbarContext', disable : {} }
44163 * @config : {Object} disable List of elements to disable.. (not done yet.)
44164 * @config : {Object} styles Map of styles available.
44168 Roo.form.HtmlEditor.ToolbarContext = function(config)
44171 Roo.apply(this, config);
44172 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44173 // dont call parent... till later.
44174 this.styles = this.styles || {};
44179 Roo.form.HtmlEditor.ToolbarContext.types = {
44191 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44257 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44262 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44272 style : 'fontFamily',
44273 displayField: 'display',
44274 optname : 'font-family',
44323 // should we really allow this??
44324 // should this just be
44335 style : 'fontFamily',
44336 displayField: 'display',
44337 optname : 'font-family',
44344 style : 'fontFamily',
44345 displayField: 'display',
44346 optname : 'font-family',
44353 style : 'fontFamily',
44354 displayField: 'display',
44355 optname : 'font-family',
44366 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44367 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44369 Roo.form.HtmlEditor.ToolbarContext.options = {
44371 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44372 [ 'Courier New', 'Courier New'],
44373 [ 'Tahoma', 'Tahoma'],
44374 [ 'Times New Roman,serif', 'Times'],
44375 [ 'Verdana','Verdana' ]
44379 // fixme - these need to be configurable..
44382 Roo.form.HtmlEditor.ToolbarContext.types
44385 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44392 editorcore : false,
44394 * @cfg {Object} disable List of toolbar elements to disable
44399 * @cfg {Object} styles List of styles
44400 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44402 * These must be defined in the page, so they get rendered correctly..
44413 init : function(editor)
44415 this.editor = editor;
44416 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44417 var editorcore = this.editorcore;
44419 var fid = editorcore.frameId;
44421 function btn(id, toggle, handler){
44422 var xid = fid + '-'+ id ;
44426 cls : 'x-btn-icon x-edit-'+id,
44427 enableToggle:toggle !== false,
44428 scope: editorcore, // was editor...
44429 handler:handler||editorcore.relayBtnCmd,
44430 clickEvent:'mousedown',
44431 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44435 // create a new element.
44436 var wdiv = editor.wrap.createChild({
44438 }, editor.wrap.dom.firstChild.nextSibling, true);
44440 // can we do this more than once??
44442 // stop form submits
44445 // disable everything...
44446 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44447 this.toolbars = {};
44449 for (var i in ty) {
44451 this.toolbars[i] = this.buildToolbar(ty[i],i);
44453 this.tb = this.toolbars.BODY;
44455 this.buildFooter();
44456 this.footer.show();
44457 editor.on('hide', function( ) { this.footer.hide() }, this);
44458 editor.on('show', function( ) { this.footer.show() }, this);
44461 this.rendered = true;
44463 // the all the btns;
44464 editor.on('editorevent', this.updateToolbar, this);
44465 // other toolbars need to implement this..
44466 //editor.on('editmodechange', this.updateToolbar, this);
44472 * Protected method that will not generally be called directly. It triggers
44473 * a toolbar update by reading the markup state of the current selection in the editor.
44475 * Note you can force an update by calling on('editorevent', scope, false)
44477 updateToolbar: function(editor,ev,sel){
44480 // capture mouse up - this is handy for selecting images..
44481 // perhaps should go somewhere else...
44482 if(!this.editorcore.activated){
44483 this.editor.onFirstFocus();
44489 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44490 // selectNode - might want to handle IE?
44492 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44493 ev.target && ev.target.tagName == 'IMG') {
44494 // they have click on an image...
44495 // let's see if we can change the selection...
44498 var nodeRange = sel.ownerDocument.createRange();
44500 nodeRange.selectNode(sel);
44502 nodeRange.selectNodeContents(sel);
44504 //nodeRange.collapse(true);
44505 var s = this.editorcore.win.getSelection();
44506 s.removeAllRanges();
44507 s.addRange(nodeRange);
44511 var updateFooter = sel ? false : true;
44514 var ans = this.editorcore.getAllAncestors();
44517 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44520 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44521 sel = sel ? sel : this.editorcore.doc.body;
44522 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44525 // pick a menu that exists..
44526 var tn = sel.tagName.toUpperCase();
44527 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44529 tn = sel.tagName.toUpperCase();
44531 var lastSel = this.tb.selectedNode
44533 this.tb.selectedNode = sel;
44535 // if current menu does not match..
44537 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44540 ///console.log("show: " + tn);
44541 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44544 this.tb.items.first().el.innerHTML = tn + ': ';
44547 // update attributes
44548 if (this.tb.fields) {
44549 this.tb.fields.each(function(e) {
44551 e.setValue(sel.style[e.stylename]);
44554 e.setValue(sel.getAttribute(e.attrname));
44558 var hasStyles = false;
44559 for(var i in this.styles) {
44566 var st = this.tb.fields.item(0);
44568 st.store.removeAll();
44571 var cn = sel.className.split(/\s+/);
44574 if (this.styles['*']) {
44576 Roo.each(this.styles['*'], function(v) {
44577 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44580 if (this.styles[tn]) {
44581 Roo.each(this.styles[tn], function(v) {
44582 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44586 st.store.loadData(avs);
44590 // flag our selected Node.
44591 this.tb.selectedNode = sel;
44594 Roo.menu.MenuMgr.hideAll();
44598 if (!updateFooter) {
44599 //this.footDisp.dom.innerHTML = '';
44602 // update the footer
44606 this.footerEls = ans.reverse();
44607 Roo.each(this.footerEls, function(a,i) {
44608 if (!a) { return; }
44609 html += html.length ? ' > ' : '';
44611 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44616 var sz = this.footDisp.up('td').getSize();
44617 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44618 this.footDisp.dom.style.marginLeft = '5px';
44620 this.footDisp.dom.style.overflow = 'hidden';
44622 this.footDisp.dom.innerHTML = html;
44624 //this.editorsyncValue();
44631 onDestroy : function(){
44634 this.tb.items.each(function(item){
44636 item.menu.removeAll();
44638 item.menu.el.destroy();
44646 onFirstFocus: function() {
44647 // need to do this for all the toolbars..
44648 this.tb.items.each(function(item){
44652 buildToolbar: function(tlist, nm)
44654 var editor = this.editor;
44655 var editorcore = this.editorcore;
44656 // create a new element.
44657 var wdiv = editor.wrap.createChild({
44659 }, editor.wrap.dom.firstChild.nextSibling, true);
44662 var tb = new Roo.Toolbar(wdiv);
44665 tb.add(nm+ ": ");
44668 for(var i in this.styles) {
44673 if (styles && styles.length) {
44675 // this needs a multi-select checkbox...
44676 tb.addField( new Roo.form.ComboBox({
44677 store: new Roo.data.SimpleStore({
44679 fields: ['val', 'selected'],
44682 name : '-roo-edit-className',
44683 attrname : 'className',
44684 displayField: 'val',
44688 triggerAction: 'all',
44689 emptyText:'Select Style',
44690 selectOnFocus:true,
44693 'select': function(c, r, i) {
44694 // initial support only for on class per el..
44695 tb.selectedNode.className = r ? r.get('val') : '';
44696 editorcore.syncValue();
44703 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44704 var tbops = tbc.options;
44706 for (var i in tlist) {
44708 var item = tlist[i];
44709 tb.add(item.title + ": ");
44712 //optname == used so you can configure the options available..
44713 var opts = item.opts ? item.opts : false;
44714 if (item.optname) {
44715 opts = tbops[item.optname];
44720 // opts == pulldown..
44721 tb.addField( new Roo.form.ComboBox({
44722 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44724 fields: ['val', 'display'],
44727 name : '-roo-edit-' + i,
44729 stylename : item.style ? item.style : false,
44730 displayField: item.displayField ? item.displayField : 'val',
44731 valueField : 'val',
44733 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44735 triggerAction: 'all',
44736 emptyText:'Select',
44737 selectOnFocus:true,
44738 width: item.width ? item.width : 130,
44740 'select': function(c, r, i) {
44742 tb.selectedNode.style[c.stylename] = r.get('val');
44745 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44754 tb.addField( new Roo.form.TextField({
44757 //allowBlank:false,
44762 tb.addField( new Roo.form.TextField({
44763 name: '-roo-edit-' + i,
44770 'change' : function(f, nv, ov) {
44771 tb.selectedNode.setAttribute(f.attrname, nv);
44784 text: 'Stylesheets',
44787 click : function ()
44789 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44797 text: 'Remove Tag',
44800 click : function ()
44803 // undo does not work.
44805 var sn = tb.selectedNode;
44807 var pn = sn.parentNode;
44809 var stn = sn.childNodes[0];
44810 var en = sn.childNodes[sn.childNodes.length - 1 ];
44811 while (sn.childNodes.length) {
44812 var node = sn.childNodes[0];
44813 sn.removeChild(node);
44815 pn.insertBefore(node, sn);
44818 pn.removeChild(sn);
44819 var range = editorcore.createRange();
44821 range.setStart(stn,0);
44822 range.setEnd(en,0); //????
44823 //range.selectNode(sel);
44826 var selection = editorcore.getSelection();
44827 selection.removeAllRanges();
44828 selection.addRange(range);
44832 //_this.updateToolbar(null, null, pn);
44833 _this.updateToolbar(null, null, null);
44834 _this.footDisp.dom.innerHTML = '';
44844 tb.el.on('click', function(e){
44845 e.preventDefault(); // what does this do?
44847 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44850 // dont need to disable them... as they will get hidden
44855 buildFooter : function()
44858 var fel = this.editor.wrap.createChild();
44859 this.footer = new Roo.Toolbar(fel);
44860 // toolbar has scrolly on left / right?
44861 var footDisp= new Roo.Toolbar.Fill();
44867 handler : function() {
44868 _t.footDisp.scrollTo('left',0,true)
44872 this.footer.add( footDisp );
44877 handler : function() {
44879 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44883 var fel = Roo.get(footDisp.el);
44884 fel.addClass('x-editor-context');
44885 this.footDispWrap = fel;
44886 this.footDispWrap.overflow = 'hidden';
44888 this.footDisp = fel.createChild();
44889 this.footDispWrap.on('click', this.onContextClick, this)
44893 onContextClick : function (ev,dom)
44895 ev.preventDefault();
44896 var cn = dom.className;
44898 if (!cn.match(/x-ed-loc-/)) {
44901 var n = cn.split('-').pop();
44902 var ans = this.footerEls;
44906 var range = this.editorcore.createRange();
44908 range.selectNodeContents(sel);
44909 //range.selectNode(sel);
44912 var selection = this.editorcore.getSelection();
44913 selection.removeAllRanges();
44914 selection.addRange(range);
44918 this.updateToolbar(null, null, sel);
44935 * Ext JS Library 1.1.1
44936 * Copyright(c) 2006-2007, Ext JS, LLC.
44938 * Originally Released Under LGPL - original licence link has changed is not relivant.
44941 * <script type="text/javascript">
44945 * @class Roo.form.BasicForm
44946 * @extends Roo.util.Observable
44947 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44949 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44950 * @param {Object} config Configuration options
44952 Roo.form.BasicForm = function(el, config){
44953 this.allItems = [];
44954 this.childForms = [];
44955 Roo.apply(this, config);
44957 * The Roo.form.Field items in this form.
44958 * @type MixedCollection
44962 this.items = new Roo.util.MixedCollection(false, function(o){
44963 return o.id || (o.id = Roo.id());
44967 * @event beforeaction
44968 * Fires before any action is performed. Return false to cancel the action.
44969 * @param {Form} this
44970 * @param {Action} action The action to be performed
44972 beforeaction: true,
44974 * @event actionfailed
44975 * Fires when an action fails.
44976 * @param {Form} this
44977 * @param {Action} action The action that failed
44979 actionfailed : true,
44981 * @event actioncomplete
44982 * Fires when an action is completed.
44983 * @param {Form} this
44984 * @param {Action} action The action that completed
44986 actioncomplete : true
44991 Roo.form.BasicForm.superclass.constructor.call(this);
44994 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44996 * @cfg {String} method
44997 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
45000 * @cfg {DataReader} reader
45001 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
45002 * This is optional as there is built-in support for processing JSON.
45005 * @cfg {DataReader} errorReader
45006 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45007 * This is completely optional as there is built-in support for processing JSON.
45010 * @cfg {String} url
45011 * The URL to use for form actions if one isn't supplied in the action options.
45014 * @cfg {Boolean} fileUpload
45015 * Set to true if this form is a file upload.
45019 * @cfg {Object} baseParams
45020 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45025 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45030 activeAction : null,
45033 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45034 * or setValues() data instead of when the form was first created.
45036 trackResetOnLoad : false,
45040 * childForms - used for multi-tab forms
45043 childForms : false,
45046 * allItems - full list of fields.
45052 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45053 * element by passing it or its id or mask the form itself by passing in true.
45056 waitMsgTarget : false,
45059 initEl : function(el){
45060 this.el = Roo.get(el);
45061 this.id = this.el.id || Roo.id();
45062 this.el.on('submit', this.onSubmit, this);
45063 this.el.addClass('x-form');
45067 onSubmit : function(e){
45072 * Returns true if client-side validation on the form is successful.
45075 isValid : function(){
45077 this.items.each(function(f){
45086 * Returns true if any fields in this form have changed since their original load.
45089 isDirty : function(){
45091 this.items.each(function(f){
45101 * Performs a predefined action (submit or load) or custom actions you define on this form.
45102 * @param {String} actionName The name of the action type
45103 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45104 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45105 * accept other config options):
45107 Property Type Description
45108 ---------------- --------------- ----------------------------------------------------------------------------------
45109 url String The url for the action (defaults to the form's url)
45110 method String The form method to use (defaults to the form's method, or POST if not defined)
45111 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45112 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45113 validate the form on the client (defaults to false)
45115 * @return {BasicForm} this
45117 doAction : function(action, options){
45118 if(typeof action == 'string'){
45119 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45121 if(this.fireEvent('beforeaction', this, action) !== false){
45122 this.beforeAction(action);
45123 action.run.defer(100, action);
45129 * Shortcut to do a submit action.
45130 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45131 * @return {BasicForm} this
45133 submit : function(options){
45134 this.doAction('submit', options);
45139 * Shortcut to do a load action.
45140 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45141 * @return {BasicForm} this
45143 load : function(options){
45144 this.doAction('load', options);
45149 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45150 * @param {Record} record The record to edit
45151 * @return {BasicForm} this
45153 updateRecord : function(record){
45154 record.beginEdit();
45155 var fs = record.fields;
45156 fs.each(function(f){
45157 var field = this.findField(f.name);
45159 record.set(f.name, field.getValue());
45167 * Loads an Roo.data.Record into this form.
45168 * @param {Record} record The record to load
45169 * @return {BasicForm} this
45171 loadRecord : function(record){
45172 this.setValues(record.data);
45177 beforeAction : function(action){
45178 var o = action.options;
45181 if(this.waitMsgTarget === true){
45182 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45183 }else if(this.waitMsgTarget){
45184 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45185 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45187 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45193 afterAction : function(action, success){
45194 this.activeAction = null;
45195 var o = action.options;
45197 if(this.waitMsgTarget === true){
45199 }else if(this.waitMsgTarget){
45200 this.waitMsgTarget.unmask();
45202 Roo.MessageBox.updateProgress(1);
45203 Roo.MessageBox.hide();
45210 Roo.callback(o.success, o.scope, [this, action]);
45211 this.fireEvent('actioncomplete', this, action);
45215 // failure condition..
45216 // we have a scenario where updates need confirming.
45217 // eg. if a locking scenario exists..
45218 // we look for { errors : { needs_confirm : true }} in the response.
45220 (typeof(action.result) != 'undefined') &&
45221 (typeof(action.result.errors) != 'undefined') &&
45222 (typeof(action.result.errors.needs_confirm) != 'undefined')
45225 Roo.MessageBox.confirm(
45226 "Change requires confirmation",
45227 action.result.errorMsg,
45232 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45242 Roo.callback(o.failure, o.scope, [this, action]);
45243 // show an error message if no failed handler is set..
45244 if (!this.hasListener('actionfailed')) {
45245 Roo.MessageBox.alert("Error",
45246 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45247 action.result.errorMsg :
45248 "Saving Failed, please check your entries or try again"
45252 this.fireEvent('actionfailed', this, action);
45258 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45259 * @param {String} id The value to search for
45262 findField : function(id){
45263 var field = this.items.get(id);
45265 this.items.each(function(f){
45266 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45272 return field || null;
45276 * Add a secondary form to this one,
45277 * Used to provide tabbed forms. One form is primary, with hidden values
45278 * which mirror the elements from the other forms.
45280 * @param {Roo.form.Form} form to add.
45283 addForm : function(form)
45286 if (this.childForms.indexOf(form) > -1) {
45290 this.childForms.push(form);
45292 Roo.each(form.allItems, function (fe) {
45294 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45295 if (this.findField(n)) { // already added..
45298 var add = new Roo.form.Hidden({
45301 add.render(this.el);
45308 * Mark fields in this form invalid in bulk.
45309 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45310 * @return {BasicForm} this
45312 markInvalid : function(errors){
45313 if(errors instanceof Array){
45314 for(var i = 0, len = errors.length; i < len; i++){
45315 var fieldError = errors[i];
45316 var f = this.findField(fieldError.id);
45318 f.markInvalid(fieldError.msg);
45324 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45325 field.markInvalid(errors[id]);
45329 Roo.each(this.childForms || [], function (f) {
45330 f.markInvalid(errors);
45337 * Set values for fields in this form in bulk.
45338 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45339 * @return {BasicForm} this
45341 setValues : function(values){
45342 if(values instanceof Array){ // array of objects
45343 for(var i = 0, len = values.length; i < len; i++){
45345 var f = this.findField(v.id);
45347 f.setValue(v.value);
45348 if(this.trackResetOnLoad){
45349 f.originalValue = f.getValue();
45353 }else{ // object hash
45356 if(typeof values[id] != 'function' && (field = this.findField(id))){
45358 if (field.setFromData &&
45359 field.valueField &&
45360 field.displayField &&
45361 // combos' with local stores can
45362 // be queried via setValue()
45363 // to set their value..
45364 (field.store && !field.store.isLocal)
45368 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45369 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45370 field.setFromData(sd);
45373 field.setValue(values[id]);
45377 if(this.trackResetOnLoad){
45378 field.originalValue = field.getValue();
45384 Roo.each(this.childForms || [], function (f) {
45385 f.setValues(values);
45392 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45393 * they are returned as an array.
45394 * @param {Boolean} asString
45397 getValues : function(asString){
45398 if (this.childForms) {
45399 // copy values from the child forms
45400 Roo.each(this.childForms, function (f) {
45401 this.setValues(f.getValues());
45407 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45408 if(asString === true){
45411 return Roo.urlDecode(fs);
45415 * Returns the fields in this form as an object with key/value pairs.
45416 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45419 getFieldValues : function(with_hidden)
45421 if (this.childForms) {
45422 // copy values from the child forms
45423 // should this call getFieldValues - probably not as we do not currently copy
45424 // hidden fields when we generate..
45425 Roo.each(this.childForms, function (f) {
45426 this.setValues(f.getValues());
45431 this.items.each(function(f){
45432 if (!f.getName()) {
45435 var v = f.getValue();
45436 if (f.inputType =='radio') {
45437 if (typeof(ret[f.getName()]) == 'undefined') {
45438 ret[f.getName()] = ''; // empty..
45441 if (!f.el.dom.checked) {
45445 v = f.el.dom.value;
45449 // not sure if this supported any more..
45450 if ((typeof(v) == 'object') && f.getRawValue) {
45451 v = f.getRawValue() ; // dates..
45453 // combo boxes where name != hiddenName...
45454 if (f.name != f.getName()) {
45455 ret[f.name] = f.getRawValue();
45457 ret[f.getName()] = v;
45464 * Clears all invalid messages in this form.
45465 * @return {BasicForm} this
45467 clearInvalid : function(){
45468 this.items.each(function(f){
45472 Roo.each(this.childForms || [], function (f) {
45481 * Resets this form.
45482 * @return {BasicForm} this
45484 reset : function(){
45485 this.items.each(function(f){
45489 Roo.each(this.childForms || [], function (f) {
45498 * Add Roo.form components to this form.
45499 * @param {Field} field1
45500 * @param {Field} field2 (optional)
45501 * @param {Field} etc (optional)
45502 * @return {BasicForm} this
45505 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45511 * Removes a field from the items collection (does NOT remove its markup).
45512 * @param {Field} field
45513 * @return {BasicForm} this
45515 remove : function(field){
45516 this.items.remove(field);
45521 * Looks at the fields in this form, checks them for an id attribute,
45522 * and calls applyTo on the existing dom element with that id.
45523 * @return {BasicForm} this
45525 render : function(){
45526 this.items.each(function(f){
45527 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45535 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45536 * @param {Object} values
45537 * @return {BasicForm} this
45539 applyToFields : function(o){
45540 this.items.each(function(f){
45547 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45548 * @param {Object} values
45549 * @return {BasicForm} this
45551 applyIfToFields : function(o){
45552 this.items.each(function(f){
45560 Roo.BasicForm = Roo.form.BasicForm;/*
45562 * Ext JS Library 1.1.1
45563 * Copyright(c) 2006-2007, Ext JS, LLC.
45565 * Originally Released Under LGPL - original licence link has changed is not relivant.
45568 * <script type="text/javascript">
45572 * @class Roo.form.Form
45573 * @extends Roo.form.BasicForm
45574 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45576 * @param {Object} config Configuration options
45578 Roo.form.Form = function(config){
45580 if (config.items) {
45581 xitems = config.items;
45582 delete config.items;
45586 Roo.form.Form.superclass.constructor.call(this, null, config);
45587 this.url = this.url || this.action;
45589 this.root = new Roo.form.Layout(Roo.applyIf({
45593 this.active = this.root;
45595 * Array of all the buttons that have been added to this form via {@link addButton}
45599 this.allItems = [];
45602 * @event clientvalidation
45603 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45604 * @param {Form} this
45605 * @param {Boolean} valid true if the form has passed client-side validation
45607 clientvalidation: true,
45610 * Fires when the form is rendered
45611 * @param {Roo.form.Form} form
45616 if (this.progressUrl) {
45617 // push a hidden field onto the list of fields..
45621 name : 'UPLOAD_IDENTIFIER'
45626 Roo.each(xitems, this.addxtype, this);
45632 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45634 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45637 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45640 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45642 buttonAlign:'center',
45645 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45650 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45651 * This property cascades to child containers if not set.
45656 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45657 * fires a looping event with that state. This is required to bind buttons to the valid
45658 * state using the config value formBind:true on the button.
45660 monitorValid : false,
45663 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45668 * @cfg {String} progressUrl - Url to return progress data
45671 progressUrl : false,
45674 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45675 * fields are added and the column is closed. If no fields are passed the column remains open
45676 * until end() is called.
45677 * @param {Object} config The config to pass to the column
45678 * @param {Field} field1 (optional)
45679 * @param {Field} field2 (optional)
45680 * @param {Field} etc (optional)
45681 * @return Column The column container object
45683 column : function(c){
45684 var col = new Roo.form.Column(c);
45686 if(arguments.length > 1){ // duplicate code required because of Opera
45687 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45694 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45695 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45696 * until end() is called.
45697 * @param {Object} config The config to pass to the fieldset
45698 * @param {Field} field1 (optional)
45699 * @param {Field} field2 (optional)
45700 * @param {Field} etc (optional)
45701 * @return FieldSet The fieldset container object
45703 fieldset : function(c){
45704 var fs = new Roo.form.FieldSet(c);
45706 if(arguments.length > 1){ // duplicate code required because of Opera
45707 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45714 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45715 * fields are added and the container is closed. If no fields are passed the container remains open
45716 * until end() is called.
45717 * @param {Object} config The config to pass to the Layout
45718 * @param {Field} field1 (optional)
45719 * @param {Field} field2 (optional)
45720 * @param {Field} etc (optional)
45721 * @return Layout The container object
45723 container : function(c){
45724 var l = new Roo.form.Layout(c);
45726 if(arguments.length > 1){ // duplicate code required because of Opera
45727 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45734 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45735 * @param {Object} container A Roo.form.Layout or subclass of Layout
45736 * @return {Form} this
45738 start : function(c){
45739 // cascade label info
45740 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45741 this.active.stack.push(c);
45742 c.ownerCt = this.active;
45748 * Closes the current open container
45749 * @return {Form} this
45752 if(this.active == this.root){
45755 this.active = this.active.ownerCt;
45760 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45761 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45762 * as the label of the field.
45763 * @param {Field} field1
45764 * @param {Field} field2 (optional)
45765 * @param {Field} etc. (optional)
45766 * @return {Form} this
45769 this.active.stack.push.apply(this.active.stack, arguments);
45770 this.allItems.push.apply(this.allItems,arguments);
45772 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45773 if(a[i].isFormField){
45778 Roo.form.Form.superclass.add.apply(this, r);
45788 * Find any element that has been added to a form, using it's ID or name
45789 * This can include framesets, columns etc. along with regular fields..
45790 * @param {String} id - id or name to find.
45792 * @return {Element} e - or false if nothing found.
45794 findbyId : function(id)
45800 Roo.each(this.allItems, function(f){
45801 if (f.id == id || f.name == id ){
45812 * Render this form into the passed container. This should only be called once!
45813 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45814 * @return {Form} this
45816 render : function(ct)
45822 var o = this.autoCreate || {
45824 method : this.method || 'POST',
45825 id : this.id || Roo.id()
45827 this.initEl(ct.createChild(o));
45829 this.root.render(this.el);
45833 this.items.each(function(f){
45834 f.render('x-form-el-'+f.id);
45837 if(this.buttons.length > 0){
45838 // tables are required to maintain order and for correct IE layout
45839 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45840 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45841 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45843 var tr = tb.getElementsByTagName('tr')[0];
45844 for(var i = 0, len = this.buttons.length; i < len; i++) {
45845 var b = this.buttons[i];
45846 var td = document.createElement('td');
45847 td.className = 'x-form-btn-td';
45848 b.render(tr.appendChild(td));
45851 if(this.monitorValid){ // initialize after render
45852 this.startMonitoring();
45854 this.fireEvent('rendered', this);
45859 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45860 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45861 * object or a valid Roo.DomHelper element config
45862 * @param {Function} handler The function called when the button is clicked
45863 * @param {Object} scope (optional) The scope of the handler function
45864 * @return {Roo.Button}
45866 addButton : function(config, handler, scope){
45870 minWidth: this.minButtonWidth,
45873 if(typeof config == "string"){
45876 Roo.apply(bc, config);
45878 var btn = new Roo.Button(null, bc);
45879 this.buttons.push(btn);
45884 * Adds a series of form elements (using the xtype property as the factory method.
45885 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45886 * @param {Object} config
45889 addxtype : function()
45891 var ar = Array.prototype.slice.call(arguments, 0);
45893 for(var i = 0; i < ar.length; i++) {
45895 continue; // skip -- if this happends something invalid got sent, we
45896 // should ignore it, as basically that interface element will not show up
45897 // and that should be pretty obvious!!
45900 if (Roo.form[ar[i].xtype]) {
45902 var fe = Roo.factory(ar[i], Roo.form);
45908 fe.store.form = this;
45913 this.allItems.push(fe);
45914 if (fe.items && fe.addxtype) {
45915 fe.addxtype.apply(fe, fe.items);
45925 // console.log('adding ' + ar[i].xtype);
45927 if (ar[i].xtype == 'Button') {
45928 //console.log('adding button');
45929 //console.log(ar[i]);
45930 this.addButton(ar[i]);
45931 this.allItems.push(fe);
45935 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45936 alert('end is not supported on xtype any more, use items');
45938 // //console.log('adding end');
45946 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45947 * option "monitorValid"
45949 startMonitoring : function(){
45952 Roo.TaskMgr.start({
45953 run : this.bindHandler,
45954 interval : this.monitorPoll || 200,
45961 * Stops monitoring of the valid state of this form
45963 stopMonitoring : function(){
45964 this.bound = false;
45968 bindHandler : function(){
45970 return false; // stops binding
45973 this.items.each(function(f){
45974 if(!f.isValid(true)){
45979 for(var i = 0, len = this.buttons.length; i < len; i++){
45980 var btn = this.buttons[i];
45981 if(btn.formBind === true && btn.disabled === valid){
45982 btn.setDisabled(!valid);
45985 this.fireEvent('clientvalidation', this, valid);
45999 Roo.Form = Roo.form.Form;
46002 * Ext JS Library 1.1.1
46003 * Copyright(c) 2006-2007, Ext JS, LLC.
46005 * Originally Released Under LGPL - original licence link has changed is not relivant.
46008 * <script type="text/javascript">
46011 // as we use this in bootstrap.
46012 Roo.namespace('Roo.form');
46014 * @class Roo.form.Action
46015 * Internal Class used to handle form actions
46017 * @param {Roo.form.BasicForm} el The form element or its id
46018 * @param {Object} config Configuration options
46023 // define the action interface
46024 Roo.form.Action = function(form, options){
46026 this.options = options || {};
46029 * Client Validation Failed
46032 Roo.form.Action.CLIENT_INVALID = 'client';
46034 * Server Validation Failed
46037 Roo.form.Action.SERVER_INVALID = 'server';
46039 * Connect to Server Failed
46042 Roo.form.Action.CONNECT_FAILURE = 'connect';
46044 * Reading Data from Server Failed
46047 Roo.form.Action.LOAD_FAILURE = 'load';
46049 Roo.form.Action.prototype = {
46051 failureType : undefined,
46052 response : undefined,
46053 result : undefined,
46055 // interface method
46056 run : function(options){
46060 // interface method
46061 success : function(response){
46065 // interface method
46066 handleResponse : function(response){
46070 // default connection failure
46071 failure : function(response){
46073 this.response = response;
46074 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46075 this.form.afterAction(this, false);
46078 processResponse : function(response){
46079 this.response = response;
46080 if(!response.responseText){
46083 this.result = this.handleResponse(response);
46084 return this.result;
46087 // utility functions used internally
46088 getUrl : function(appendParams){
46089 var url = this.options.url || this.form.url || this.form.el.dom.action;
46091 var p = this.getParams();
46093 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46099 getMethod : function(){
46100 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46103 getParams : function(){
46104 var bp = this.form.baseParams;
46105 var p = this.options.params;
46107 if(typeof p == "object"){
46108 p = Roo.urlEncode(Roo.applyIf(p, bp));
46109 }else if(typeof p == 'string' && bp){
46110 p += '&' + Roo.urlEncode(bp);
46113 p = Roo.urlEncode(bp);
46118 createCallback : function(){
46120 success: this.success,
46121 failure: this.failure,
46123 timeout: (this.form.timeout*1000),
46124 upload: this.form.fileUpload ? this.success : undefined
46129 Roo.form.Action.Submit = function(form, options){
46130 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46133 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46136 haveProgress : false,
46137 uploadComplete : false,
46139 // uploadProgress indicator.
46140 uploadProgress : function()
46142 if (!this.form.progressUrl) {
46146 if (!this.haveProgress) {
46147 Roo.MessageBox.progress("Uploading", "Uploading");
46149 if (this.uploadComplete) {
46150 Roo.MessageBox.hide();
46154 this.haveProgress = true;
46156 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46158 var c = new Roo.data.Connection();
46160 url : this.form.progressUrl,
46165 success : function(req){
46166 //console.log(data);
46170 rdata = Roo.decode(req.responseText)
46172 Roo.log("Invalid data from server..");
46176 if (!rdata || !rdata.success) {
46178 Roo.MessageBox.alert(Roo.encode(rdata));
46181 var data = rdata.data;
46183 if (this.uploadComplete) {
46184 Roo.MessageBox.hide();
46189 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46190 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46193 this.uploadProgress.defer(2000,this);
46196 failure: function(data) {
46197 Roo.log('progress url failed ');
46208 // run get Values on the form, so it syncs any secondary forms.
46209 this.form.getValues();
46211 var o = this.options;
46212 var method = this.getMethod();
46213 var isPost = method == 'POST';
46214 if(o.clientValidation === false || this.form.isValid()){
46216 if (this.form.progressUrl) {
46217 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46218 (new Date() * 1) + '' + Math.random());
46223 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46224 form:this.form.el.dom,
46225 url:this.getUrl(!isPost),
46227 params:isPost ? this.getParams() : null,
46228 isUpload: this.form.fileUpload
46231 this.uploadProgress();
46233 }else if (o.clientValidation !== false){ // client validation failed
46234 this.failureType = Roo.form.Action.CLIENT_INVALID;
46235 this.form.afterAction(this, false);
46239 success : function(response)
46241 this.uploadComplete= true;
46242 if (this.haveProgress) {
46243 Roo.MessageBox.hide();
46247 var result = this.processResponse(response);
46248 if(result === true || result.success){
46249 this.form.afterAction(this, true);
46253 this.form.markInvalid(result.errors);
46254 this.failureType = Roo.form.Action.SERVER_INVALID;
46256 this.form.afterAction(this, false);
46258 failure : function(response)
46260 this.uploadComplete= true;
46261 if (this.haveProgress) {
46262 Roo.MessageBox.hide();
46265 this.response = response;
46266 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46267 this.form.afterAction(this, false);
46270 handleResponse : function(response){
46271 if(this.form.errorReader){
46272 var rs = this.form.errorReader.read(response);
46275 for(var i = 0, len = rs.records.length; i < len; i++) {
46276 var r = rs.records[i];
46277 errors[i] = r.data;
46280 if(errors.length < 1){
46284 success : rs.success,
46290 ret = Roo.decode(response.responseText);
46294 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46304 Roo.form.Action.Load = function(form, options){
46305 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46306 this.reader = this.form.reader;
46309 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46314 Roo.Ajax.request(Roo.apply(
46315 this.createCallback(), {
46316 method:this.getMethod(),
46317 url:this.getUrl(false),
46318 params:this.getParams()
46322 success : function(response){
46324 var result = this.processResponse(response);
46325 if(result === true || !result.success || !result.data){
46326 this.failureType = Roo.form.Action.LOAD_FAILURE;
46327 this.form.afterAction(this, false);
46330 this.form.clearInvalid();
46331 this.form.setValues(result.data);
46332 this.form.afterAction(this, true);
46335 handleResponse : function(response){
46336 if(this.form.reader){
46337 var rs = this.form.reader.read(response);
46338 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46340 success : rs.success,
46344 return Roo.decode(response.responseText);
46348 Roo.form.Action.ACTION_TYPES = {
46349 'load' : Roo.form.Action.Load,
46350 'submit' : Roo.form.Action.Submit
46353 * Ext JS Library 1.1.1
46354 * Copyright(c) 2006-2007, Ext JS, LLC.
46356 * Originally Released Under LGPL - original licence link has changed is not relivant.
46359 * <script type="text/javascript">
46363 * @class Roo.form.Layout
46364 * @extends Roo.Component
46365 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46367 * @param {Object} config Configuration options
46369 Roo.form.Layout = function(config){
46371 if (config.items) {
46372 xitems = config.items;
46373 delete config.items;
46375 Roo.form.Layout.superclass.constructor.call(this, config);
46377 Roo.each(xitems, this.addxtype, this);
46381 Roo.extend(Roo.form.Layout, Roo.Component, {
46383 * @cfg {String/Object} autoCreate
46384 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46387 * @cfg {String/Object/Function} style
46388 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46389 * a function which returns such a specification.
46392 * @cfg {String} labelAlign
46393 * Valid values are "left," "top" and "right" (defaults to "left")
46396 * @cfg {Number} labelWidth
46397 * Fixed width in pixels of all field labels (defaults to undefined)
46400 * @cfg {Boolean} clear
46401 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46405 * @cfg {String} labelSeparator
46406 * The separator to use after field labels (defaults to ':')
46408 labelSeparator : ':',
46410 * @cfg {Boolean} hideLabels
46411 * True to suppress the display of field labels in this layout (defaults to false)
46413 hideLabels : false,
46416 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46421 onRender : function(ct, position){
46422 if(this.el){ // from markup
46423 this.el = Roo.get(this.el);
46424 }else { // generate
46425 var cfg = this.getAutoCreate();
46426 this.el = ct.createChild(cfg, position);
46429 this.el.applyStyles(this.style);
46431 if(this.labelAlign){
46432 this.el.addClass('x-form-label-'+this.labelAlign);
46434 if(this.hideLabels){
46435 this.labelStyle = "display:none";
46436 this.elementStyle = "padding-left:0;";
46438 if(typeof this.labelWidth == 'number'){
46439 this.labelStyle = "width:"+this.labelWidth+"px;";
46440 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46442 if(this.labelAlign == 'top'){
46443 this.labelStyle = "width:auto;";
46444 this.elementStyle = "padding-left:0;";
46447 var stack = this.stack;
46448 var slen = stack.length;
46450 if(!this.fieldTpl){
46451 var t = new Roo.Template(
46452 '<div class="x-form-item {5}">',
46453 '<label for="{0}" style="{2}">{1}{4}</label>',
46454 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46456 '</div><div class="x-form-clear-left"></div>'
46458 t.disableFormats = true;
46460 Roo.form.Layout.prototype.fieldTpl = t;
46462 for(var i = 0; i < slen; i++) {
46463 if(stack[i].isFormField){
46464 this.renderField(stack[i]);
46466 this.renderComponent(stack[i]);
46471 this.el.createChild({cls:'x-form-clear'});
46476 renderField : function(f){
46477 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46480 f.labelStyle||this.labelStyle||'', //2
46481 this.elementStyle||'', //3
46482 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46483 f.itemCls||this.itemCls||'' //5
46484 ], true).getPrevSibling());
46488 renderComponent : function(c){
46489 c.render(c.isLayout ? this.el : this.el.createChild());
46492 * Adds a object form elements (using the xtype property as the factory method.)
46493 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46494 * @param {Object} config
46496 addxtype : function(o)
46498 // create the lement.
46499 o.form = this.form;
46500 var fe = Roo.factory(o, Roo.form);
46501 this.form.allItems.push(fe);
46502 this.stack.push(fe);
46504 if (fe.isFormField) {
46505 this.form.items.add(fe);
46513 * @class Roo.form.Column
46514 * @extends Roo.form.Layout
46515 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46517 * @param {Object} config Configuration options
46519 Roo.form.Column = function(config){
46520 Roo.form.Column.superclass.constructor.call(this, config);
46523 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46525 * @cfg {Number/String} width
46526 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46529 * @cfg {String/Object} autoCreate
46530 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46534 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46537 onRender : function(ct, position){
46538 Roo.form.Column.superclass.onRender.call(this, ct, position);
46540 this.el.setWidth(this.width);
46547 * @class Roo.form.Row
46548 * @extends Roo.form.Layout
46549 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46551 * @param {Object} config Configuration options
46555 Roo.form.Row = function(config){
46556 Roo.form.Row.superclass.constructor.call(this, config);
46559 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46561 * @cfg {Number/String} width
46562 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46565 * @cfg {Number/String} height
46566 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46568 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46572 onRender : function(ct, position){
46573 //console.log('row render');
46575 var t = new Roo.Template(
46576 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46577 '<label for="{0}" style="{2}">{1}{4}</label>',
46578 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46582 t.disableFormats = true;
46584 Roo.form.Layout.prototype.rowTpl = t;
46586 this.fieldTpl = this.rowTpl;
46588 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46589 var labelWidth = 100;
46591 if ((this.labelAlign != 'top')) {
46592 if (typeof this.labelWidth == 'number') {
46593 labelWidth = this.labelWidth
46595 this.padWidth = 20 + labelWidth;
46599 Roo.form.Column.superclass.onRender.call(this, ct, position);
46601 this.el.setWidth(this.width);
46604 this.el.setHeight(this.height);
46609 renderField : function(f){
46610 f.fieldEl = this.fieldTpl.append(this.el, [
46611 f.id, f.fieldLabel,
46612 f.labelStyle||this.labelStyle||'',
46613 this.elementStyle||'',
46614 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46615 f.itemCls||this.itemCls||'',
46616 f.width ? f.width + this.padWidth : 160 + this.padWidth
46623 * @class Roo.form.FieldSet
46624 * @extends Roo.form.Layout
46625 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46627 * @param {Object} config Configuration options
46629 Roo.form.FieldSet = function(config){
46630 Roo.form.FieldSet.superclass.constructor.call(this, config);
46633 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46635 * @cfg {String} legend
46636 * The text to display as the legend for the FieldSet (defaults to '')
46639 * @cfg {String/Object} autoCreate
46640 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46644 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46647 onRender : function(ct, position){
46648 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46650 this.setLegend(this.legend);
46655 setLegend : function(text){
46657 this.el.child('legend').update(text);
46662 * Ext JS Library 1.1.1
46663 * Copyright(c) 2006-2007, Ext JS, LLC.
46665 * Originally Released Under LGPL - original licence link has changed is not relivant.
46668 * <script type="text/javascript">
46671 * @class Roo.form.VTypes
46672 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46675 Roo.form.VTypes = function(){
46676 // closure these in so they are only created once.
46677 var alpha = /^[a-zA-Z_]+$/;
46678 var alphanum = /^[a-zA-Z0-9_]+$/;
46679 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46680 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46682 // All these messages and functions are configurable
46685 * The function used to validate email addresses
46686 * @param {String} value The email address
46688 'email' : function(v){
46689 return email.test(v);
46692 * The error text to display when the email validation function returns false
46695 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46697 * The keystroke filter mask to be applied on email input
46700 'emailMask' : /[a-z0-9_\.\-@]/i,
46703 * The function used to validate URLs
46704 * @param {String} value The URL
46706 'url' : function(v){
46707 return url.test(v);
46710 * The error text to display when the url validation function returns false
46713 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46716 * The function used to validate alpha values
46717 * @param {String} value The value
46719 'alpha' : function(v){
46720 return alpha.test(v);
46723 * The error text to display when the alpha validation function returns false
46726 'alphaText' : 'This field should only contain letters and _',
46728 * The keystroke filter mask to be applied on alpha input
46731 'alphaMask' : /[a-z_]/i,
46734 * The function used to validate alphanumeric values
46735 * @param {String} value The value
46737 'alphanum' : function(v){
46738 return alphanum.test(v);
46741 * The error text to display when the alphanumeric validation function returns false
46744 'alphanumText' : 'This field should only contain letters, numbers and _',
46746 * The keystroke filter mask to be applied on alphanumeric input
46749 'alphanumMask' : /[a-z0-9_]/i
46751 }();//<script type="text/javascript">
46754 * @class Roo.form.FCKeditor
46755 * @extends Roo.form.TextArea
46756 * Wrapper around the FCKEditor http://www.fckeditor.net
46758 * Creates a new FCKeditor
46759 * @param {Object} config Configuration options
46761 Roo.form.FCKeditor = function(config){
46762 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46765 * @event editorinit
46766 * Fired when the editor is initialized - you can add extra handlers here..
46767 * @param {FCKeditor} this
46768 * @param {Object} the FCK object.
46775 Roo.form.FCKeditor.editors = { };
46776 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46778 //defaultAutoCreate : {
46779 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46783 * @cfg {Object} fck options - see fck manual for details.
46788 * @cfg {Object} fck toolbar set (Basic or Default)
46790 toolbarSet : 'Basic',
46792 * @cfg {Object} fck BasePath
46794 basePath : '/fckeditor/',
46802 onRender : function(ct, position)
46805 this.defaultAutoCreate = {
46807 style:"width:300px;height:60px;",
46808 autocomplete: "new-password"
46811 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46814 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46815 if(this.preventScrollbars){
46816 this.el.setStyle("overflow", "hidden");
46818 this.el.setHeight(this.growMin);
46821 //console.log('onrender' + this.getId() );
46822 Roo.form.FCKeditor.editors[this.getId()] = this;
46825 this.replaceTextarea() ;
46829 getEditor : function() {
46830 return this.fckEditor;
46833 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46834 * @param {Mixed} value The value to set
46838 setValue : function(value)
46840 //console.log('setValue: ' + value);
46842 if(typeof(value) == 'undefined') { // not sure why this is happending...
46845 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46847 //if(!this.el || !this.getEditor()) {
46848 // this.value = value;
46849 //this.setValue.defer(100,this,[value]);
46853 if(!this.getEditor()) {
46857 this.getEditor().SetData(value);
46864 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46865 * @return {Mixed} value The field value
46867 getValue : function()
46870 if (this.frame && this.frame.dom.style.display == 'none') {
46871 return Roo.form.FCKeditor.superclass.getValue.call(this);
46874 if(!this.el || !this.getEditor()) {
46876 // this.getValue.defer(100,this);
46881 var value=this.getEditor().GetData();
46882 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46883 return Roo.form.FCKeditor.superclass.getValue.call(this);
46889 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46890 * @return {Mixed} value The field value
46892 getRawValue : function()
46894 if (this.frame && this.frame.dom.style.display == 'none') {
46895 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46898 if(!this.el || !this.getEditor()) {
46899 //this.getRawValue.defer(100,this);
46906 var value=this.getEditor().GetData();
46907 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46908 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46912 setSize : function(w,h) {
46916 //if (this.frame && this.frame.dom.style.display == 'none') {
46917 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46920 //if(!this.el || !this.getEditor()) {
46921 // this.setSize.defer(100,this, [w,h]);
46927 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46929 this.frame.dom.setAttribute('width', w);
46930 this.frame.dom.setAttribute('height', h);
46931 this.frame.setSize(w,h);
46935 toggleSourceEdit : function(value) {
46939 this.el.dom.style.display = value ? '' : 'none';
46940 this.frame.dom.style.display = value ? 'none' : '';
46945 focus: function(tag)
46947 if (this.frame.dom.style.display == 'none') {
46948 return Roo.form.FCKeditor.superclass.focus.call(this);
46950 if(!this.el || !this.getEditor()) {
46951 this.focus.defer(100,this, [tag]);
46958 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46959 this.getEditor().Focus();
46961 if (!this.getEditor().Selection.GetSelection()) {
46962 this.focus.defer(100,this, [tag]);
46967 var r = this.getEditor().EditorDocument.createRange();
46968 r.setStart(tgs[0],0);
46969 r.setEnd(tgs[0],0);
46970 this.getEditor().Selection.GetSelection().removeAllRanges();
46971 this.getEditor().Selection.GetSelection().addRange(r);
46972 this.getEditor().Focus();
46979 replaceTextarea : function()
46981 if ( document.getElementById( this.getId() + '___Frame' ) )
46983 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46985 // We must check the elements firstly using the Id and then the name.
46986 var oTextarea = document.getElementById( this.getId() );
46988 var colElementsByName = document.getElementsByName( this.getId() ) ;
46990 oTextarea.style.display = 'none' ;
46992 if ( oTextarea.tabIndex ) {
46993 this.TabIndex = oTextarea.tabIndex ;
46996 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46997 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46998 this.frame = Roo.get(this.getId() + '___Frame')
47001 _getConfigHtml : function()
47005 for ( var o in this.fckconfig ) {
47006 sConfig += sConfig.length > 0 ? '&' : '';
47007 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47010 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47014 _getIFrameHtml : function()
47016 var sFile = 'fckeditor.html' ;
47017 /* no idea what this is about..
47020 if ( (/fcksource=true/i).test( window.top.location.search ) )
47021 sFile = 'fckeditor.original.html' ;
47026 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47027 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47030 var html = '<iframe id="' + this.getId() +
47031 '___Frame" src="' + sLink +
47032 '" width="' + this.width +
47033 '" height="' + this.height + '"' +
47034 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47035 ' frameborder="0" scrolling="no"></iframe>' ;
47040 _insertHtmlBefore : function( html, element )
47042 if ( element.insertAdjacentHTML ) {
47044 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47046 var oRange = document.createRange() ;
47047 oRange.setStartBefore( element ) ;
47048 var oFragment = oRange.createContextualFragment( html );
47049 element.parentNode.insertBefore( oFragment, element ) ;
47062 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47064 function FCKeditor_OnComplete(editorInstance){
47065 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47066 f.fckEditor = editorInstance;
47067 //console.log("loaded");
47068 f.fireEvent('editorinit', f, editorInstance);
47088 //<script type="text/javascript">
47090 * @class Roo.form.GridField
47091 * @extends Roo.form.Field
47092 * Embed a grid (or editable grid into a form)
47095 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47097 * xgrid.store = Roo.data.Store
47098 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47099 * xgrid.store.reader = Roo.data.JsonReader
47103 * Creates a new GridField
47104 * @param {Object} config Configuration options
47106 Roo.form.GridField = function(config){
47107 Roo.form.GridField.superclass.constructor.call(this, config);
47111 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47113 * @cfg {Number} width - used to restrict width of grid..
47117 * @cfg {Number} height - used to restrict height of grid..
47121 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47127 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47128 * {tag: "input", type: "checkbox", autocomplete: "off"})
47130 // defaultAutoCreate : { tag: 'div' },
47131 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47133 * @cfg {String} addTitle Text to include for adding a title.
47137 onResize : function(){
47138 Roo.form.Field.superclass.onResize.apply(this, arguments);
47141 initEvents : function(){
47142 // Roo.form.Checkbox.superclass.initEvents.call(this);
47143 // has no events...
47148 getResizeEl : function(){
47152 getPositionEl : function(){
47157 onRender : function(ct, position){
47159 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47160 var style = this.style;
47163 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47164 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47165 this.viewEl = this.wrap.createChild({ tag: 'div' });
47167 this.viewEl.applyStyles(style);
47170 this.viewEl.setWidth(this.width);
47173 this.viewEl.setHeight(this.height);
47175 //if(this.inputValue !== undefined){
47176 //this.setValue(this.value);
47179 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47182 this.grid.render();
47183 this.grid.getDataSource().on('remove', this.refreshValue, this);
47184 this.grid.getDataSource().on('update', this.refreshValue, this);
47185 this.grid.on('afteredit', this.refreshValue, this);
47191 * Sets the value of the item.
47192 * @param {String} either an object or a string..
47194 setValue : function(v){
47196 v = v || []; // empty set..
47197 // this does not seem smart - it really only affects memoryproxy grids..
47198 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47199 var ds = this.grid.getDataSource();
47200 // assumes a json reader..
47202 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47203 ds.loadData( data);
47205 // clear selection so it does not get stale.
47206 if (this.grid.sm) {
47207 this.grid.sm.clearSelections();
47210 Roo.form.GridField.superclass.setValue.call(this, v);
47211 this.refreshValue();
47212 // should load data in the grid really....
47216 refreshValue: function() {
47218 this.grid.getDataSource().each(function(r) {
47221 this.el.dom.value = Roo.encode(val);
47229 * Ext JS Library 1.1.1
47230 * Copyright(c) 2006-2007, Ext JS, LLC.
47232 * Originally Released Under LGPL - original licence link has changed is not relivant.
47235 * <script type="text/javascript">
47238 * @class Roo.form.DisplayField
47239 * @extends Roo.form.Field
47240 * A generic Field to display non-editable data.
47242 * Creates a new Display Field item.
47243 * @param {Object} config Configuration options
47245 Roo.form.DisplayField = function(config){
47246 Roo.form.DisplayField.superclass.constructor.call(this, config);
47250 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47251 inputType: 'hidden',
47257 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47259 focusClass : undefined,
47261 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47263 fieldClass: 'x-form-field',
47266 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47268 valueRenderer: undefined,
47272 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47273 * {tag: "input", type: "checkbox", autocomplete: "off"})
47276 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47278 onResize : function(){
47279 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47283 initEvents : function(){
47284 // Roo.form.Checkbox.superclass.initEvents.call(this);
47285 // has no events...
47290 getResizeEl : function(){
47294 getPositionEl : function(){
47299 onRender : function(ct, position){
47301 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47302 //if(this.inputValue !== undefined){
47303 this.wrap = this.el.wrap();
47305 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47307 if (this.bodyStyle) {
47308 this.viewEl.applyStyles(this.bodyStyle);
47310 //this.viewEl.setStyle('padding', '2px');
47312 this.setValue(this.value);
47317 initValue : Roo.emptyFn,
47322 onClick : function(){
47327 * Sets the checked state of the checkbox.
47328 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47330 setValue : function(v){
47332 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47333 // this might be called before we have a dom element..
47334 if (!this.viewEl) {
47337 this.viewEl.dom.innerHTML = html;
47338 Roo.form.DisplayField.superclass.setValue.call(this, v);
47348 * @class Roo.form.DayPicker
47349 * @extends Roo.form.Field
47350 * A Day picker show [M] [T] [W] ....
47352 * Creates a new Day Picker
47353 * @param {Object} config Configuration options
47355 Roo.form.DayPicker= function(config){
47356 Roo.form.DayPicker.superclass.constructor.call(this, config);
47360 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47362 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47364 focusClass : undefined,
47366 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47368 fieldClass: "x-form-field",
47371 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47372 * {tag: "input", type: "checkbox", autocomplete: "off"})
47374 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47377 actionMode : 'viewEl',
47381 inputType : 'hidden',
47384 inputElement: false, // real input element?
47385 basedOn: false, // ????
47387 isFormField: true, // not sure where this is needed!!!!
47389 onResize : function(){
47390 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47391 if(!this.boxLabel){
47392 this.el.alignTo(this.wrap, 'c-c');
47396 initEvents : function(){
47397 Roo.form.Checkbox.superclass.initEvents.call(this);
47398 this.el.on("click", this.onClick, this);
47399 this.el.on("change", this.onClick, this);
47403 getResizeEl : function(){
47407 getPositionEl : function(){
47413 onRender : function(ct, position){
47414 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47416 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47418 var r1 = '<table><tr>';
47419 var r2 = '<tr class="x-form-daypick-icons">';
47420 for (var i=0; i < 7; i++) {
47421 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47422 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47425 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47426 viewEl.select('img').on('click', this.onClick, this);
47427 this.viewEl = viewEl;
47430 // this will not work on Chrome!!!
47431 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47432 this.el.on('propertychange', this.setFromHidden, this); //ie
47440 initValue : Roo.emptyFn,
47443 * Returns the checked state of the checkbox.
47444 * @return {Boolean} True if checked, else false
47446 getValue : function(){
47447 return this.el.dom.value;
47452 onClick : function(e){
47453 //this.setChecked(!this.checked);
47454 Roo.get(e.target).toggleClass('x-menu-item-checked');
47455 this.refreshValue();
47456 //if(this.el.dom.checked != this.checked){
47457 // this.setValue(this.el.dom.checked);
47462 refreshValue : function()
47465 this.viewEl.select('img',true).each(function(e,i,n) {
47466 val += e.is(".x-menu-item-checked") ? String(n) : '';
47468 this.setValue(val, true);
47472 * Sets the checked state of the checkbox.
47473 * On is always based on a string comparison between inputValue and the param.
47474 * @param {Boolean/String} value - the value to set
47475 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47477 setValue : function(v,suppressEvent){
47478 if (!this.el.dom) {
47481 var old = this.el.dom.value ;
47482 this.el.dom.value = v;
47483 if (suppressEvent) {
47487 // update display..
47488 this.viewEl.select('img',true).each(function(e,i,n) {
47490 var on = e.is(".x-menu-item-checked");
47491 var newv = v.indexOf(String(n)) > -1;
47493 e.toggleClass('x-menu-item-checked');
47499 this.fireEvent('change', this, v, old);
47504 // handle setting of hidden value by some other method!!?!?
47505 setFromHidden: function()
47510 //console.log("SET FROM HIDDEN");
47511 //alert('setFrom hidden');
47512 this.setValue(this.el.dom.value);
47515 onDestroy : function()
47518 Roo.get(this.viewEl).remove();
47521 Roo.form.DayPicker.superclass.onDestroy.call(this);
47525 * RooJS Library 1.1.1
47526 * Copyright(c) 2008-2011 Alan Knowles
47533 * @class Roo.form.ComboCheck
47534 * @extends Roo.form.ComboBox
47535 * A combobox for multiple select items.
47537 * FIXME - could do with a reset button..
47540 * Create a new ComboCheck
47541 * @param {Object} config Configuration options
47543 Roo.form.ComboCheck = function(config){
47544 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47545 // should verify some data...
47547 // hiddenName = required..
47548 // displayField = required
47549 // valudField == required
47550 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47552 Roo.each(req, function(e) {
47553 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47554 throw "Roo.form.ComboCheck : missing value for: " + e;
47561 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47566 selectedClass: 'x-menu-item-checked',
47569 onRender : function(ct, position){
47575 var cls = 'x-combo-list';
47578 this.tpl = new Roo.Template({
47579 html : '<div class="'+cls+'-item x-menu-check-item">' +
47580 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47581 '<span>{' + this.displayField + '}</span>' +
47588 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47589 this.view.singleSelect = false;
47590 this.view.multiSelect = true;
47591 this.view.toggleSelect = true;
47592 this.pageTb.add(new Roo.Toolbar.Fill(), {
47595 handler: function()
47602 onViewOver : function(e, t){
47608 onViewClick : function(doFocus,index){
47612 select: function () {
47613 //Roo.log("SELECT CALLED");
47616 selectByValue : function(xv, scrollIntoView){
47617 var ar = this.getValueArray();
47620 Roo.each(ar, function(v) {
47621 if(v === undefined || v === null){
47624 var r = this.findRecord(this.valueField, v);
47626 sels.push(this.store.indexOf(r))
47630 this.view.select(sels);
47636 onSelect : function(record, index){
47637 // Roo.log("onselect Called");
47638 // this is only called by the clear button now..
47639 this.view.clearSelections();
47640 this.setValue('[]');
47641 if (this.value != this.valueBefore) {
47642 this.fireEvent('change', this, this.value, this.valueBefore);
47643 this.valueBefore = this.value;
47646 getValueArray : function()
47651 //Roo.log(this.value);
47652 if (typeof(this.value) == 'undefined') {
47655 var ar = Roo.decode(this.value);
47656 return ar instanceof Array ? ar : []; //?? valid?
47659 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47664 expand : function ()
47667 Roo.form.ComboCheck.superclass.expand.call(this);
47668 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47669 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47674 collapse : function(){
47675 Roo.form.ComboCheck.superclass.collapse.call(this);
47676 var sl = this.view.getSelectedIndexes();
47677 var st = this.store;
47681 Roo.each(sl, function(i) {
47683 nv.push(r.get(this.valueField));
47685 this.setValue(Roo.encode(nv));
47686 if (this.value != this.valueBefore) {
47688 this.fireEvent('change', this, this.value, this.valueBefore);
47689 this.valueBefore = this.value;
47694 setValue : function(v){
47698 var vals = this.getValueArray();
47700 Roo.each(vals, function(k) {
47701 var r = this.findRecord(this.valueField, k);
47703 tv.push(r.data[this.displayField]);
47704 }else if(this.valueNotFoundText !== undefined){
47705 tv.push( this.valueNotFoundText );
47710 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47711 this.hiddenField.value = v;
47717 * Ext JS Library 1.1.1
47718 * Copyright(c) 2006-2007, Ext JS, LLC.
47720 * Originally Released Under LGPL - original licence link has changed is not relivant.
47723 * <script type="text/javascript">
47727 * @class Roo.form.Signature
47728 * @extends Roo.form.Field
47732 * @param {Object} config Configuration options
47735 Roo.form.Signature = function(config){
47736 Roo.form.Signature.superclass.constructor.call(this, config);
47738 this.addEvents({// not in used??
47741 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47742 * @param {Roo.form.Signature} combo This combo box
47747 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47748 * @param {Roo.form.ComboBox} combo This combo box
47749 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47755 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47757 * @cfg {Object} labels Label to use when rendering a form.
47761 * confirm : "Confirm"
47766 confirm : "Confirm"
47769 * @cfg {Number} width The signature panel width (defaults to 300)
47773 * @cfg {Number} height The signature panel height (defaults to 100)
47777 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47779 allowBlank : false,
47782 // {Object} signPanel The signature SVG panel element (defaults to {})
47784 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47785 isMouseDown : false,
47786 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47787 isConfirmed : false,
47788 // {String} signatureTmp SVG mapping string (defaults to empty string)
47792 defaultAutoCreate : { // modified by initCompnoent..
47798 onRender : function(ct, position){
47800 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47802 this.wrap = this.el.wrap({
47803 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47806 this.createToolbar(this);
47807 this.signPanel = this.wrap.createChild({
47809 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47813 this.svgID = Roo.id();
47814 this.svgEl = this.signPanel.createChild({
47815 xmlns : 'http://www.w3.org/2000/svg',
47817 id : this.svgID + "-svg",
47819 height: this.height,
47820 viewBox: '0 0 '+this.width+' '+this.height,
47824 id: this.svgID + "-svg-r",
47826 height: this.height,
47831 id: this.svgID + "-svg-l",
47833 y1: (this.height*0.8), // start set the line in 80% of height
47834 x2: this.width, // end
47835 y2: (this.height*0.8), // end set the line in 80% of height
47837 'stroke-width': "1",
47838 'stroke-dasharray': "3",
47839 'shape-rendering': "crispEdges",
47840 'pointer-events': "none"
47844 id: this.svgID + "-svg-p",
47846 'stroke-width': "3",
47848 'pointer-events': 'none'
47853 this.svgBox = this.svgEl.dom.getScreenCTM();
47855 createSVG : function(){
47856 var svg = this.signPanel;
47857 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47860 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47861 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47862 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47863 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47864 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47865 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47866 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47869 isTouchEvent : function(e){
47870 return e.type.match(/^touch/);
47872 getCoords : function (e) {
47873 var pt = this.svgEl.dom.createSVGPoint();
47876 if (this.isTouchEvent(e)) {
47877 pt.x = e.targetTouches[0].clientX
47878 pt.y = e.targetTouches[0].clientY;
47880 var a = this.svgEl.dom.getScreenCTM();
47881 var b = a.inverse();
47882 var mx = pt.matrixTransform(b);
47883 return mx.x + ',' + mx.y;
47885 //mouse event headler
47886 down : function (e) {
47887 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47888 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47890 this.isMouseDown = true;
47892 e.preventDefault();
47894 move : function (e) {
47895 if (this.isMouseDown) {
47896 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47897 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47900 e.preventDefault();
47902 up : function (e) {
47903 this.isMouseDown = false;
47904 var sp = this.signatureTmp.split(' ');
47907 if(!sp[sp.length-2].match(/^L/)){
47911 this.signatureTmp = sp.join(" ");
47914 if(this.getValue() != this.signatureTmp){
47915 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47916 this.isConfirmed = false;
47918 e.preventDefault();
47922 * Protected method that will not generally be called directly. It
47923 * is called when the editor creates its toolbar. Override this method if you need to
47924 * add custom toolbar buttons.
47925 * @param {HtmlEditor} editor
47927 createToolbar : function(editor){
47928 function btn(id, toggle, handler){
47929 var xid = fid + '-'+ id ;
47933 cls : 'x-btn-icon x-edit-'+id,
47934 enableToggle:toggle !== false,
47935 scope: editor, // was editor...
47936 handler:handler||editor.relayBtnCmd,
47937 clickEvent:'mousedown',
47938 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47944 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47948 cls : ' x-signature-btn x-signature-'+id,
47949 scope: editor, // was editor...
47950 handler: this.reset,
47951 clickEvent:'mousedown',
47952 text: this.labels.clear
47959 cls : ' x-signature-btn x-signature-'+id,
47960 scope: editor, // was editor...
47961 handler: this.confirmHandler,
47962 clickEvent:'mousedown',
47963 text: this.labels.confirm
47970 * when user is clicked confirm then show this image.....
47972 * @return {String} Image Data URI
47974 getImageDataURI : function(){
47975 var svg = this.svgEl.dom.parentNode.innerHTML;
47976 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47981 * @return {Boolean} this.isConfirmed
47983 getConfirmed : function(){
47984 return this.isConfirmed;
47988 * @return {Number} this.width
47990 getWidth : function(){
47995 * @return {Number} this.height
47997 getHeight : function(){
47998 return this.height;
48001 getSignature : function(){
48002 return this.signatureTmp;
48005 reset : function(){
48006 this.signatureTmp = '';
48007 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48008 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48009 this.isConfirmed = false;
48010 Roo.form.Signature.superclass.reset.call(this);
48012 setSignature : function(s){
48013 this.signatureTmp = s;
48014 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48015 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48017 this.isConfirmed = false;
48018 Roo.form.Signature.superclass.reset.call(this);
48021 // Roo.log(this.signPanel.dom.contentWindow.up())
48024 setConfirmed : function(){
48028 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48031 confirmHandler : function(){
48032 if(!this.getSignature()){
48036 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48037 this.setValue(this.getSignature());
48038 this.isConfirmed = true;
48040 this.fireEvent('confirm', this);
48043 // Subclasses should provide the validation implementation by overriding this
48044 validateValue : function(value){
48045 if(this.allowBlank){
48049 if(this.isConfirmed){
48056 * Ext JS Library 1.1.1
48057 * Copyright(c) 2006-2007, Ext JS, LLC.
48059 * Originally Released Under LGPL - original licence link has changed is not relivant.
48062 * <script type="text/javascript">
48067 * @class Roo.form.ComboBox
48068 * @extends Roo.form.TriggerField
48069 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48071 * Create a new ComboBox.
48072 * @param {Object} config Configuration options
48074 Roo.form.Select = function(config){
48075 Roo.form.Select.superclass.constructor.call(this, config);
48079 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48081 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48084 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48085 * rendering into an Roo.Editor, defaults to false)
48088 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48089 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48092 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48095 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48096 * the dropdown list (defaults to undefined, with no header element)
48100 * @cfg {String/Roo.Template} tpl The template to use to render the output
48104 defaultAutoCreate : {tag: "select" },
48106 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48108 listWidth: undefined,
48110 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48111 * mode = 'remote' or 'text' if mode = 'local')
48113 displayField: undefined,
48115 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48116 * mode = 'remote' or 'value' if mode = 'local').
48117 * Note: use of a valueField requires the user make a selection
48118 * in order for a value to be mapped.
48120 valueField: undefined,
48124 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48125 * field's data value (defaults to the underlying DOM element's name)
48127 hiddenName: undefined,
48129 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48133 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48135 selectedClass: 'x-combo-selected',
48137 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48138 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48139 * which displays a downward arrow icon).
48141 triggerClass : 'x-form-arrow-trigger',
48143 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48147 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48148 * anchor positions (defaults to 'tl-bl')
48150 listAlign: 'tl-bl?',
48152 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48156 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48157 * query specified by the allQuery config option (defaults to 'query')
48159 triggerAction: 'query',
48161 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48162 * (defaults to 4, does not apply if editable = false)
48166 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48167 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48171 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48172 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48176 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48177 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48181 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48182 * when editable = true (defaults to false)
48184 selectOnFocus:false,
48186 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48188 queryParam: 'query',
48190 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48191 * when mode = 'remote' (defaults to 'Loading...')
48193 loadingText: 'Loading...',
48195 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48199 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48203 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48204 * traditional select (defaults to true)
48208 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48212 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48216 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48217 * listWidth has a higher value)
48221 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48222 * allow the user to set arbitrary text into the field (defaults to false)
48224 forceSelection:false,
48226 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48227 * if typeAhead = true (defaults to 250)
48229 typeAheadDelay : 250,
48231 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48232 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48234 valueNotFoundText : undefined,
48237 * @cfg {String} defaultValue The value displayed after loading the store.
48242 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48244 blockFocus : false,
48247 * @cfg {Boolean} disableClear Disable showing of clear button.
48249 disableClear : false,
48251 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48253 alwaysQuery : false,
48259 // element that contains real text value.. (when hidden is used..)
48262 onRender : function(ct, position){
48263 Roo.form.Field.prototype.onRender.call(this, ct, position);
48266 this.store.on('beforeload', this.onBeforeLoad, this);
48267 this.store.on('load', this.onLoad, this);
48268 this.store.on('loadexception', this.onLoadException, this);
48269 this.store.load({});
48277 initEvents : function(){
48278 //Roo.form.ComboBox.superclass.initEvents.call(this);
48282 onDestroy : function(){
48285 this.store.un('beforeload', this.onBeforeLoad, this);
48286 this.store.un('load', this.onLoad, this);
48287 this.store.un('loadexception', this.onLoadException, this);
48289 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48293 fireKey : function(e){
48294 if(e.isNavKeyPress() && !this.list.isVisible()){
48295 this.fireEvent("specialkey", this, e);
48300 onResize: function(w, h){
48308 * Allow or prevent the user from directly editing the field text. If false is passed,
48309 * the user will only be able to select from the items defined in the dropdown list. This method
48310 * is the runtime equivalent of setting the 'editable' config option at config time.
48311 * @param {Boolean} value True to allow the user to directly edit the field text
48313 setEditable : function(value){
48318 onBeforeLoad : function(){
48320 Roo.log("Select before load");
48323 this.innerList.update(this.loadingText ?
48324 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48325 //this.restrictHeight();
48326 this.selectedIndex = -1;
48330 onLoad : function(){
48333 var dom = this.el.dom;
48334 dom.innerHTML = '';
48335 var od = dom.ownerDocument;
48337 if (this.emptyText) {
48338 var op = od.createElement('option');
48339 op.setAttribute('value', '');
48340 op.innerHTML = String.format('{0}', this.emptyText);
48341 dom.appendChild(op);
48343 if(this.store.getCount() > 0){
48345 var vf = this.valueField;
48346 var df = this.displayField;
48347 this.store.data.each(function(r) {
48348 // which colmsn to use... testing - cdoe / title..
48349 var op = od.createElement('option');
48350 op.setAttribute('value', r.data[vf]);
48351 op.innerHTML = String.format('{0}', r.data[df]);
48352 dom.appendChild(op);
48354 if (typeof(this.defaultValue != 'undefined')) {
48355 this.setValue(this.defaultValue);
48360 //this.onEmptyResults();
48365 onLoadException : function()
48367 dom.innerHTML = '';
48369 Roo.log("Select on load exception");
48373 Roo.log(this.store.reader.jsonData);
48374 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48375 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48381 onTypeAhead : function(){
48386 onSelect : function(record, index){
48387 Roo.log('on select?');
48389 if(this.fireEvent('beforeselect', this, record, index) !== false){
48390 this.setFromData(index > -1 ? record.data : false);
48392 this.fireEvent('select', this, record, index);
48397 * Returns the currently selected field value or empty string if no value is set.
48398 * @return {String} value The selected value
48400 getValue : function(){
48401 var dom = this.el.dom;
48402 this.value = dom.options[dom.selectedIndex].value;
48408 * Clears any text/value currently set in the field
48410 clearValue : function(){
48412 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48417 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48418 * will be displayed in the field. If the value does not match the data value of an existing item,
48419 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48420 * Otherwise the field will be blank (although the value will still be set).
48421 * @param {String} value The value to match
48423 setValue : function(v){
48424 var d = this.el.dom;
48425 for (var i =0; i < d.options.length;i++) {
48426 if (v == d.options[i].value) {
48427 d.selectedIndex = i;
48435 * @property {Object} the last set data for the element
48440 * Sets the value of the field based on a object which is related to the record format for the store.
48441 * @param {Object} value the value to set as. or false on reset?
48443 setFromData : function(o){
48444 Roo.log('setfrom data?');
48450 reset : function(){
48454 findRecord : function(prop, value){
48459 if(this.store.getCount() > 0){
48460 this.store.each(function(r){
48461 if(r.data[prop] == value){
48471 getName: function()
48473 // returns hidden if it's set..
48474 if (!this.rendered) {return ''};
48475 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48483 onEmptyResults : function(){
48484 Roo.log('empty results');
48489 * Returns true if the dropdown list is expanded, else false.
48491 isExpanded : function(){
48496 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48497 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48498 * @param {String} value The data value of the item to select
48499 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48500 * selected item if it is not currently in view (defaults to true)
48501 * @return {Boolean} True if the value matched an item in the list, else false
48503 selectByValue : function(v, scrollIntoView){
48504 Roo.log('select By Value');
48507 if(v !== undefined && v !== null){
48508 var r = this.findRecord(this.valueField || this.displayField, v);
48510 this.select(this.store.indexOf(r), scrollIntoView);
48518 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48519 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48520 * @param {Number} index The zero-based index of the list item to select
48521 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48522 * selected item if it is not currently in view (defaults to true)
48524 select : function(index, scrollIntoView){
48525 Roo.log('select ');
48528 this.selectedIndex = index;
48529 this.view.select(index);
48530 if(scrollIntoView !== false){
48531 var el = this.view.getNode(index);
48533 this.innerList.scrollChildIntoView(el, false);
48541 validateBlur : function(){
48548 initQuery : function(){
48549 this.doQuery(this.getRawValue());
48553 doForce : function(){
48554 if(this.el.dom.value.length > 0){
48555 this.el.dom.value =
48556 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48562 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48563 * query allowing the query action to be canceled if needed.
48564 * @param {String} query The SQL query to execute
48565 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48566 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48567 * saved in the current store (defaults to false)
48569 doQuery : function(q, forceAll){
48571 Roo.log('doQuery?');
48572 if(q === undefined || q === null){
48577 forceAll: forceAll,
48581 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48585 forceAll = qe.forceAll;
48586 if(forceAll === true || (q.length >= this.minChars)){
48587 if(this.lastQuery != q || this.alwaysQuery){
48588 this.lastQuery = q;
48589 if(this.mode == 'local'){
48590 this.selectedIndex = -1;
48592 this.store.clearFilter();
48594 this.store.filter(this.displayField, q);
48598 this.store.baseParams[this.queryParam] = q;
48600 params: this.getParams(q)
48605 this.selectedIndex = -1;
48612 getParams : function(q){
48614 //p[this.queryParam] = q;
48617 p.limit = this.pageSize;
48623 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48625 collapse : function(){
48630 collapseIf : function(e){
48635 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48637 expand : function(){
48645 * @cfg {Boolean} grow
48649 * @cfg {Number} growMin
48653 * @cfg {Number} growMax
48661 setWidth : function()
48665 getResizeEl : function(){
48668 });//<script type="text/javasscript">
48672 * @class Roo.DDView
48673 * A DnD enabled version of Roo.View.
48674 * @param {Element/String} container The Element in which to create the View.
48675 * @param {String} tpl The template string used to create the markup for each element of the View
48676 * @param {Object} config The configuration properties. These include all the config options of
48677 * {@link Roo.View} plus some specific to this class.<br>
48679 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48680 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48682 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48683 .x-view-drag-insert-above {
48684 border-top:1px dotted #3366cc;
48686 .x-view-drag-insert-below {
48687 border-bottom:1px dotted #3366cc;
48693 Roo.DDView = function(container, tpl, config) {
48694 Roo.DDView.superclass.constructor.apply(this, arguments);
48695 this.getEl().setStyle("outline", "0px none");
48696 this.getEl().unselectable();
48697 if (this.dragGroup) {
48698 this.setDraggable(this.dragGroup.split(","));
48700 if (this.dropGroup) {
48701 this.setDroppable(this.dropGroup.split(","));
48703 if (this.deletable) {
48704 this.setDeletable();
48706 this.isDirtyFlag = false;
48712 Roo.extend(Roo.DDView, Roo.View, {
48713 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48714 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48715 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48716 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48720 reset: Roo.emptyFn,
48722 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48724 validate: function() {
48728 destroy: function() {
48729 this.purgeListeners();
48730 this.getEl.removeAllListeners();
48731 this.getEl().remove();
48732 if (this.dragZone) {
48733 if (this.dragZone.destroy) {
48734 this.dragZone.destroy();
48737 if (this.dropZone) {
48738 if (this.dropZone.destroy) {
48739 this.dropZone.destroy();
48744 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48745 getName: function() {
48749 /** Loads the View from a JSON string representing the Records to put into the Store. */
48750 setValue: function(v) {
48752 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48755 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48756 this.store.proxy = new Roo.data.MemoryProxy(data);
48760 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48761 getValue: function() {
48763 this.store.each(function(rec) {
48764 result += rec.id + ',';
48766 return result.substr(0, result.length - 1) + ')';
48769 getIds: function() {
48770 var i = 0, result = new Array(this.store.getCount());
48771 this.store.each(function(rec) {
48772 result[i++] = rec.id;
48777 isDirty: function() {
48778 return this.isDirtyFlag;
48782 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48783 * whole Element becomes the target, and this causes the drop gesture to append.
48785 getTargetFromEvent : function(e) {
48786 var target = e.getTarget();
48787 while ((target !== null) && (target.parentNode != this.el.dom)) {
48788 target = target.parentNode;
48791 target = this.el.dom.lastChild || this.el.dom;
48797 * Create the drag data which consists of an object which has the property "ddel" as
48798 * the drag proxy element.
48800 getDragData : function(e) {
48801 var target = this.findItemFromChild(e.getTarget());
48803 this.handleSelection(e);
48804 var selNodes = this.getSelectedNodes();
48807 copy: this.copy || (this.allowCopy && e.ctrlKey),
48811 var selectedIndices = this.getSelectedIndexes();
48812 for (var i = 0; i < selectedIndices.length; i++) {
48813 dragData.records.push(this.store.getAt(selectedIndices[i]));
48815 if (selNodes.length == 1) {
48816 dragData.ddel = target.cloneNode(true); // the div element
48818 var div = document.createElement('div'); // create the multi element drag "ghost"
48819 div.className = 'multi-proxy';
48820 for (var i = 0, len = selNodes.length; i < len; i++) {
48821 div.appendChild(selNodes[i].cloneNode(true));
48823 dragData.ddel = div;
48825 //console.log(dragData)
48826 //console.log(dragData.ddel.innerHTML)
48829 //console.log('nodragData')
48833 /** Specify to which ddGroup items in this DDView may be dragged. */
48834 setDraggable: function(ddGroup) {
48835 if (ddGroup instanceof Array) {
48836 Roo.each(ddGroup, this.setDraggable, this);
48839 if (this.dragZone) {
48840 this.dragZone.addToGroup(ddGroup);
48842 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48843 containerScroll: true,
48847 // Draggability implies selection. DragZone's mousedown selects the element.
48848 if (!this.multiSelect) { this.singleSelect = true; }
48850 // Wire the DragZone's handlers up to methods in *this*
48851 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48855 /** Specify from which ddGroup this DDView accepts drops. */
48856 setDroppable: function(ddGroup) {
48857 if (ddGroup instanceof Array) {
48858 Roo.each(ddGroup, this.setDroppable, this);
48861 if (this.dropZone) {
48862 this.dropZone.addToGroup(ddGroup);
48864 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48865 containerScroll: true,
48869 // Wire the DropZone's handlers up to methods in *this*
48870 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48871 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48872 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48873 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48874 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48878 /** Decide whether to drop above or below a View node. */
48879 getDropPoint : function(e, n, dd){
48880 if (n == this.el.dom) { return "above"; }
48881 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48882 var c = t + (b - t) / 2;
48883 var y = Roo.lib.Event.getPageY(e);
48891 onNodeEnter : function(n, dd, e, data){
48895 onNodeOver : function(n, dd, e, data){
48896 var pt = this.getDropPoint(e, n, dd);
48897 // set the insert point style on the target node
48898 var dragElClass = this.dropNotAllowed;
48901 if (pt == "above"){
48902 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48903 targetElClass = "x-view-drag-insert-above";
48905 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48906 targetElClass = "x-view-drag-insert-below";
48908 if (this.lastInsertClass != targetElClass){
48909 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48910 this.lastInsertClass = targetElClass;
48913 return dragElClass;
48916 onNodeOut : function(n, dd, e, data){
48917 this.removeDropIndicators(n);
48920 onNodeDrop : function(n, dd, e, data){
48921 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48924 var pt = this.getDropPoint(e, n, dd);
48925 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48926 if (pt == "below") { insertAt++; }
48927 for (var i = 0; i < data.records.length; i++) {
48928 var r = data.records[i];
48929 var dup = this.store.getById(r.id);
48930 if (dup && (dd != this.dragZone)) {
48931 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48934 this.store.insert(insertAt++, r.copy());
48936 data.source.isDirtyFlag = true;
48938 this.store.insert(insertAt++, r);
48940 this.isDirtyFlag = true;
48943 this.dragZone.cachedTarget = null;
48947 removeDropIndicators : function(n){
48949 Roo.fly(n).removeClass([
48950 "x-view-drag-insert-above",
48951 "x-view-drag-insert-below"]);
48952 this.lastInsertClass = "_noclass";
48957 * Utility method. Add a delete option to the DDView's context menu.
48958 * @param {String} imageUrl The URL of the "delete" icon image.
48960 setDeletable: function(imageUrl) {
48961 if (!this.singleSelect && !this.multiSelect) {
48962 this.singleSelect = true;
48964 var c = this.getContextMenu();
48965 this.contextMenu.on("itemclick", function(item) {
48968 this.remove(this.getSelectedIndexes());
48972 this.contextMenu.add({
48979 /** Return the context menu for this DDView. */
48980 getContextMenu: function() {
48981 if (!this.contextMenu) {
48982 // Create the View's context menu
48983 this.contextMenu = new Roo.menu.Menu({
48984 id: this.id + "-contextmenu"
48986 this.el.on("contextmenu", this.showContextMenu, this);
48988 return this.contextMenu;
48991 disableContextMenu: function() {
48992 if (this.contextMenu) {
48993 this.el.un("contextmenu", this.showContextMenu, this);
48997 showContextMenu: function(e, item) {
48998 item = this.findItemFromChild(e.getTarget());
49001 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
49002 this.contextMenu.showAt(e.getXY());
49007 * Remove {@link Roo.data.Record}s at the specified indices.
49008 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49010 remove: function(selectedIndices) {
49011 selectedIndices = [].concat(selectedIndices);
49012 for (var i = 0; i < selectedIndices.length; i++) {
49013 var rec = this.store.getAt(selectedIndices[i]);
49014 this.store.remove(rec);
49019 * Double click fires the event, but also, if this is draggable, and there is only one other
49020 * related DropZone, it transfers the selected node.
49022 onDblClick : function(e){
49023 var item = this.findItemFromChild(e.getTarget());
49025 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49028 if (this.dragGroup) {
49029 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49030 while (targets.indexOf(this.dropZone) > -1) {
49031 targets.remove(this.dropZone);
49033 if (targets.length == 1) {
49034 this.dragZone.cachedTarget = null;
49035 var el = Roo.get(targets[0].getEl());
49036 var box = el.getBox(true);
49037 targets[0].onNodeDrop(el.dom, {
49039 xy: [box.x, box.y + box.height - 1]
49040 }, null, this.getDragData(e));
49046 handleSelection: function(e) {
49047 this.dragZone.cachedTarget = null;
49048 var item = this.findItemFromChild(e.getTarget());
49050 this.clearSelections(true);
49053 if (item && (this.multiSelect || this.singleSelect)){
49054 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49055 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49056 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49057 this.unselect(item);
49059 this.select(item, this.multiSelect && e.ctrlKey);
49060 this.lastSelection = item;
49065 onItemClick : function(item, index, e){
49066 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49072 unselect : function(nodeInfo, suppressEvent){
49073 var node = this.getNode(nodeInfo);
49074 if(node && this.isSelected(node)){
49075 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49076 Roo.fly(node).removeClass(this.selectedClass);
49077 this.selections.remove(node);
49078 if(!suppressEvent){
49079 this.fireEvent("selectionchange", this, this.selections);
49087 * Ext JS Library 1.1.1
49088 * Copyright(c) 2006-2007, Ext JS, LLC.
49090 * Originally Released Under LGPL - original licence link has changed is not relivant.
49093 * <script type="text/javascript">
49097 * @class Roo.LayoutManager
49098 * @extends Roo.util.Observable
49099 * Base class for layout managers.
49101 Roo.LayoutManager = function(container, config){
49102 Roo.LayoutManager.superclass.constructor.call(this);
49103 this.el = Roo.get(container);
49104 // ie scrollbar fix
49105 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49106 document.body.scroll = "no";
49107 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49108 this.el.position('relative');
49110 this.id = this.el.id;
49111 this.el.addClass("x-layout-container");
49112 /** false to disable window resize monitoring @type Boolean */
49113 this.monitorWindowResize = true;
49118 * Fires when a layout is performed.
49119 * @param {Roo.LayoutManager} this
49123 * @event regionresized
49124 * Fires when the user resizes a region.
49125 * @param {Roo.LayoutRegion} region The resized region
49126 * @param {Number} newSize The new size (width for east/west, height for north/south)
49128 "regionresized" : true,
49130 * @event regioncollapsed
49131 * Fires when a region is collapsed.
49132 * @param {Roo.LayoutRegion} region The collapsed region
49134 "regioncollapsed" : true,
49136 * @event regionexpanded
49137 * Fires when a region is expanded.
49138 * @param {Roo.LayoutRegion} region The expanded region
49140 "regionexpanded" : true
49142 this.updating = false;
49143 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49146 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49148 * Returns true if this layout is currently being updated
49149 * @return {Boolean}
49151 isUpdating : function(){
49152 return this.updating;
49156 * Suspend the LayoutManager from doing auto-layouts while
49157 * making multiple add or remove calls
49159 beginUpdate : function(){
49160 this.updating = true;
49164 * Restore auto-layouts and optionally disable the manager from performing a layout
49165 * @param {Boolean} noLayout true to disable a layout update
49167 endUpdate : function(noLayout){
49168 this.updating = false;
49174 layout: function(){
49178 onRegionResized : function(region, newSize){
49179 this.fireEvent("regionresized", region, newSize);
49183 onRegionCollapsed : function(region){
49184 this.fireEvent("regioncollapsed", region);
49187 onRegionExpanded : function(region){
49188 this.fireEvent("regionexpanded", region);
49192 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49193 * performs box-model adjustments.
49194 * @return {Object} The size as an object {width: (the width), height: (the height)}
49196 getViewSize : function(){
49198 if(this.el.dom != document.body){
49199 size = this.el.getSize();
49201 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49203 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49204 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49209 * Returns the Element this layout is bound to.
49210 * @return {Roo.Element}
49212 getEl : function(){
49217 * Returns the specified region.
49218 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49219 * @return {Roo.LayoutRegion}
49221 getRegion : function(target){
49222 return this.regions[target.toLowerCase()];
49225 onWindowResize : function(){
49226 if(this.monitorWindowResize){
49232 * Ext JS Library 1.1.1
49233 * Copyright(c) 2006-2007, Ext JS, LLC.
49235 * Originally Released Under LGPL - original licence link has changed is not relivant.
49238 * <script type="text/javascript">
49241 * @class Roo.BorderLayout
49242 * @extends Roo.LayoutManager
49243 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49244 * please see: <br><br>
49245 * <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>
49246 * <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>
49249 var layout = new Roo.BorderLayout(document.body, {
49283 preferredTabWidth: 150
49288 var CP = Roo.ContentPanel;
49290 layout.beginUpdate();
49291 layout.add("north", new CP("north", "North"));
49292 layout.add("south", new CP("south", {title: "South", closable: true}));
49293 layout.add("west", new CP("west", {title: "West"}));
49294 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49295 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49296 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49297 layout.getRegion("center").showPanel("center1");
49298 layout.endUpdate();
49301 <b>The container the layout is rendered into can be either the body element or any other element.
49302 If it is not the body element, the container needs to either be an absolute positioned element,
49303 or you will need to add "position:relative" to the css of the container. You will also need to specify
49304 the container size if it is not the body element.</b>
49307 * Create a new BorderLayout
49308 * @param {String/HTMLElement/Element} container The container this layout is bound to
49309 * @param {Object} config Configuration options
49311 Roo.BorderLayout = function(container, config){
49312 config = config || {};
49313 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49314 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49315 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49316 var target = this.factory.validRegions[i];
49317 if(config[target]){
49318 this.addRegion(target, config[target]);
49323 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49325 * Creates and adds a new region if it doesn't already exist.
49326 * @param {String} target The target region key (north, south, east, west or center).
49327 * @param {Object} config The regions config object
49328 * @return {BorderLayoutRegion} The new region
49330 addRegion : function(target, config){
49331 if(!this.regions[target]){
49332 var r = this.factory.create(target, this, config);
49333 this.bindRegion(target, r);
49335 return this.regions[target];
49339 bindRegion : function(name, r){
49340 this.regions[name] = r;
49341 r.on("visibilitychange", this.layout, this);
49342 r.on("paneladded", this.layout, this);
49343 r.on("panelremoved", this.layout, this);
49344 r.on("invalidated", this.layout, this);
49345 r.on("resized", this.onRegionResized, this);
49346 r.on("collapsed", this.onRegionCollapsed, this);
49347 r.on("expanded", this.onRegionExpanded, this);
49351 * Performs a layout update.
49353 layout : function(){
49354 if(this.updating) return;
49355 var size = this.getViewSize();
49356 var w = size.width;
49357 var h = size.height;
49362 //var x = 0, y = 0;
49364 var rs = this.regions;
49365 var north = rs["north"];
49366 var south = rs["south"];
49367 var west = rs["west"];
49368 var east = rs["east"];
49369 var center = rs["center"];
49370 //if(this.hideOnLayout){ // not supported anymore
49371 //c.el.setStyle("display", "none");
49373 if(north && north.isVisible()){
49374 var b = north.getBox();
49375 var m = north.getMargins();
49376 b.width = w - (m.left+m.right);
49379 centerY = b.height + b.y + m.bottom;
49380 centerH -= centerY;
49381 north.updateBox(this.safeBox(b));
49383 if(south && south.isVisible()){
49384 var b = south.getBox();
49385 var m = south.getMargins();
49386 b.width = w - (m.left+m.right);
49388 var totalHeight = (b.height + m.top + m.bottom);
49389 b.y = h - totalHeight + m.top;
49390 centerH -= totalHeight;
49391 south.updateBox(this.safeBox(b));
49393 if(west && west.isVisible()){
49394 var b = west.getBox();
49395 var m = west.getMargins();
49396 b.height = centerH - (m.top+m.bottom);
49398 b.y = centerY + m.top;
49399 var totalWidth = (b.width + m.left + m.right);
49400 centerX += totalWidth;
49401 centerW -= totalWidth;
49402 west.updateBox(this.safeBox(b));
49404 if(east && east.isVisible()){
49405 var b = east.getBox();
49406 var m = east.getMargins();
49407 b.height = centerH - (m.top+m.bottom);
49408 var totalWidth = (b.width + m.left + m.right);
49409 b.x = w - totalWidth + m.left;
49410 b.y = centerY + m.top;
49411 centerW -= totalWidth;
49412 east.updateBox(this.safeBox(b));
49415 var m = center.getMargins();
49417 x: centerX + m.left,
49418 y: centerY + m.top,
49419 width: centerW - (m.left+m.right),
49420 height: centerH - (m.top+m.bottom)
49422 //if(this.hideOnLayout){
49423 //center.el.setStyle("display", "block");
49425 center.updateBox(this.safeBox(centerBox));
49428 this.fireEvent("layout", this);
49432 safeBox : function(box){
49433 box.width = Math.max(0, box.width);
49434 box.height = Math.max(0, box.height);
49439 * Adds a ContentPanel (or subclass) to this layout.
49440 * @param {String} target The target region key (north, south, east, west or center).
49441 * @param {Roo.ContentPanel} panel The panel to add
49442 * @return {Roo.ContentPanel} The added panel
49444 add : function(target, panel){
49446 target = target.toLowerCase();
49447 return this.regions[target].add(panel);
49451 * Remove a ContentPanel (or subclass) to this layout.
49452 * @param {String} target The target region key (north, south, east, west or center).
49453 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49454 * @return {Roo.ContentPanel} The removed panel
49456 remove : function(target, panel){
49457 target = target.toLowerCase();
49458 return this.regions[target].remove(panel);
49462 * Searches all regions for a panel with the specified id
49463 * @param {String} panelId
49464 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49466 findPanel : function(panelId){
49467 var rs = this.regions;
49468 for(var target in rs){
49469 if(typeof rs[target] != "function"){
49470 var p = rs[target].getPanel(panelId);
49480 * Searches all regions for a panel with the specified id and activates (shows) it.
49481 * @param {String/ContentPanel} panelId The panels id or the panel itself
49482 * @return {Roo.ContentPanel} The shown panel or null
49484 showPanel : function(panelId) {
49485 var rs = this.regions;
49486 for(var target in rs){
49487 var r = rs[target];
49488 if(typeof r != "function"){
49489 if(r.hasPanel(panelId)){
49490 return r.showPanel(panelId);
49498 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49499 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49501 restoreState : function(provider){
49503 provider = Roo.state.Manager;
49505 var sm = new Roo.LayoutStateManager();
49506 sm.init(this, provider);
49510 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49511 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49512 * a valid ContentPanel config object. Example:
49514 // Create the main layout
49515 var layout = new Roo.BorderLayout('main-ct', {
49526 // Create and add multiple ContentPanels at once via configs
49529 id: 'source-files',
49531 title:'Ext Source Files',
49544 * @param {Object} regions An object containing ContentPanel configs by region name
49546 batchAdd : function(regions){
49547 this.beginUpdate();
49548 for(var rname in regions){
49549 var lr = this.regions[rname];
49551 this.addTypedPanels(lr, regions[rname]);
49558 addTypedPanels : function(lr, ps){
49559 if(typeof ps == 'string'){
49560 lr.add(new Roo.ContentPanel(ps));
49562 else if(ps instanceof Array){
49563 for(var i =0, len = ps.length; i < len; i++){
49564 this.addTypedPanels(lr, ps[i]);
49567 else if(!ps.events){ // raw config?
49569 delete ps.el; // prevent conflict
49570 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49572 else { // panel object assumed!
49577 * Adds a xtype elements to the layout.
49581 xtype : 'ContentPanel',
49588 xtype : 'NestedLayoutPanel',
49594 items : [ ... list of content panels or nested layout panels.. ]
49598 * @param {Object} cfg Xtype definition of item to add.
49600 addxtype : function(cfg)
49602 // basically accepts a pannel...
49603 // can accept a layout region..!?!?
49604 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49606 if (!cfg.xtype.match(/Panel$/)) {
49611 if (typeof(cfg.region) == 'undefined') {
49612 Roo.log("Failed to add Panel, region was not set");
49616 var region = cfg.region;
49622 xitems = cfg.items;
49629 case 'ContentPanel': // ContentPanel (el, cfg)
49630 case 'ScrollPanel': // ContentPanel (el, cfg)
49632 if(cfg.autoCreate) {
49633 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49635 var el = this.el.createChild();
49636 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49639 this.add(region, ret);
49643 case 'TreePanel': // our new panel!
49644 cfg.el = this.el.createChild();
49645 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49646 this.add(region, ret);
49649 case 'NestedLayoutPanel':
49650 // create a new Layout (which is a Border Layout...
49651 var el = this.el.createChild();
49652 var clayout = cfg.layout;
49654 clayout.items = clayout.items || [];
49655 // replace this exitems with the clayout ones..
49656 xitems = clayout.items;
49659 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49660 cfg.background = false;
49662 var layout = new Roo.BorderLayout(el, clayout);
49664 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49665 //console.log('adding nested layout panel ' + cfg.toSource());
49666 this.add(region, ret);
49667 nb = {}; /// find first...
49672 // needs grid and region
49674 //var el = this.getRegion(region).el.createChild();
49675 var el = this.el.createChild();
49676 // create the grid first...
49678 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49680 if (region == 'center' && this.active ) {
49681 cfg.background = false;
49683 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49685 this.add(region, ret);
49686 if (cfg.background) {
49687 ret.on('activate', function(gp) {
49688 if (!gp.grid.rendered) {
49703 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49705 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49706 this.add(region, ret);
49709 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49713 // GridPanel (grid, cfg)
49716 this.beginUpdate();
49720 Roo.each(xitems, function(i) {
49721 region = nb && i.region ? i.region : false;
49723 var add = ret.addxtype(i);
49726 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49727 if (!i.background) {
49728 abn[region] = nb[region] ;
49735 // make the last non-background panel active..
49736 //if (nb) { Roo.log(abn); }
49739 for(var r in abn) {
49740 region = this.getRegion(r);
49742 // tried using nb[r], but it does not work..
49744 region.showPanel(abn[r]);
49755 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49756 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49757 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49758 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49761 var CP = Roo.ContentPanel;
49763 var layout = Roo.BorderLayout.create({
49767 panels: [new CP("north", "North")]
49776 panels: [new CP("west", {title: "West"})]
49785 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49794 panels: [new CP("south", {title: "South", closable: true})]
49801 preferredTabWidth: 150,
49803 new CP("center1", {title: "Close Me", closable: true}),
49804 new CP("center2", {title: "Center Panel", closable: false})
49809 layout.getRegion("center").showPanel("center1");
49814 Roo.BorderLayout.create = function(config, targetEl){
49815 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49816 layout.beginUpdate();
49817 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49818 for(var j = 0, jlen = regions.length; j < jlen; j++){
49819 var lr = regions[j];
49820 if(layout.regions[lr] && config[lr].panels){
49821 var r = layout.regions[lr];
49822 var ps = config[lr].panels;
49823 layout.addTypedPanels(r, ps);
49826 layout.endUpdate();
49831 Roo.BorderLayout.RegionFactory = {
49833 validRegions : ["north","south","east","west","center"],
49836 create : function(target, mgr, config){
49837 target = target.toLowerCase();
49838 if(config.lightweight || config.basic){
49839 return new Roo.BasicLayoutRegion(mgr, config, target);
49843 return new Roo.NorthLayoutRegion(mgr, config);
49845 return new Roo.SouthLayoutRegion(mgr, config);
49847 return new Roo.EastLayoutRegion(mgr, config);
49849 return new Roo.WestLayoutRegion(mgr, config);
49851 return new Roo.CenterLayoutRegion(mgr, config);
49853 throw 'Layout region "'+target+'" not supported.';
49857 * Ext JS Library 1.1.1
49858 * Copyright(c) 2006-2007, Ext JS, LLC.
49860 * Originally Released Under LGPL - original licence link has changed is not relivant.
49863 * <script type="text/javascript">
49867 * @class Roo.BasicLayoutRegion
49868 * @extends Roo.util.Observable
49869 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49870 * and does not have a titlebar, tabs or any other features. All it does is size and position
49871 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49873 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49875 this.position = pos;
49878 * @scope Roo.BasicLayoutRegion
49882 * @event beforeremove
49883 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49884 * @param {Roo.LayoutRegion} this
49885 * @param {Roo.ContentPanel} panel The panel
49886 * @param {Object} e The cancel event object
49888 "beforeremove" : true,
49890 * @event invalidated
49891 * Fires when the layout for this region is changed.
49892 * @param {Roo.LayoutRegion} this
49894 "invalidated" : true,
49896 * @event visibilitychange
49897 * Fires when this region is shown or hidden
49898 * @param {Roo.LayoutRegion} this
49899 * @param {Boolean} visibility true or false
49901 "visibilitychange" : true,
49903 * @event paneladded
49904 * Fires when a panel is added.
49905 * @param {Roo.LayoutRegion} this
49906 * @param {Roo.ContentPanel} panel The panel
49908 "paneladded" : true,
49910 * @event panelremoved
49911 * Fires when a panel is removed.
49912 * @param {Roo.LayoutRegion} this
49913 * @param {Roo.ContentPanel} panel The panel
49915 "panelremoved" : true,
49918 * Fires when this region is collapsed.
49919 * @param {Roo.LayoutRegion} this
49921 "collapsed" : true,
49924 * Fires when this region is expanded.
49925 * @param {Roo.LayoutRegion} this
49930 * Fires when this region is slid into view.
49931 * @param {Roo.LayoutRegion} this
49933 "slideshow" : true,
49936 * Fires when this region slides out of view.
49937 * @param {Roo.LayoutRegion} this
49939 "slidehide" : true,
49941 * @event panelactivated
49942 * Fires when a panel is activated.
49943 * @param {Roo.LayoutRegion} this
49944 * @param {Roo.ContentPanel} panel The activated panel
49946 "panelactivated" : true,
49949 * Fires when the user resizes this region.
49950 * @param {Roo.LayoutRegion} this
49951 * @param {Number} newSize The new size (width for east/west, height for north/south)
49955 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49956 this.panels = new Roo.util.MixedCollection();
49957 this.panels.getKey = this.getPanelId.createDelegate(this);
49959 this.activePanel = null;
49960 // ensure listeners are added...
49962 if (config.listeners || config.events) {
49963 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49964 listeners : config.listeners || {},
49965 events : config.events || {}
49969 if(skipConfig !== true){
49970 this.applyConfig(config);
49974 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49975 getPanelId : function(p){
49979 applyConfig : function(config){
49980 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49981 this.config = config;
49986 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49987 * the width, for horizontal (north, south) the height.
49988 * @param {Number} newSize The new width or height
49990 resizeTo : function(newSize){
49991 var el = this.el ? this.el :
49992 (this.activePanel ? this.activePanel.getEl() : null);
49994 switch(this.position){
49997 el.setWidth(newSize);
49998 this.fireEvent("resized", this, newSize);
50002 el.setHeight(newSize);
50003 this.fireEvent("resized", this, newSize);
50009 getBox : function(){
50010 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50013 getMargins : function(){
50014 return this.margins;
50017 updateBox : function(box){
50019 var el = this.activePanel.getEl();
50020 el.dom.style.left = box.x + "px";
50021 el.dom.style.top = box.y + "px";
50022 this.activePanel.setSize(box.width, box.height);
50026 * Returns the container element for this region.
50027 * @return {Roo.Element}
50029 getEl : function(){
50030 return this.activePanel;
50034 * Returns true if this region is currently visible.
50035 * @return {Boolean}
50037 isVisible : function(){
50038 return this.activePanel ? true : false;
50041 setActivePanel : function(panel){
50042 panel = this.getPanel(panel);
50043 if(this.activePanel && this.activePanel != panel){
50044 this.activePanel.setActiveState(false);
50045 this.activePanel.getEl().setLeftTop(-10000,-10000);
50047 this.activePanel = panel;
50048 panel.setActiveState(true);
50050 panel.setSize(this.box.width, this.box.height);
50052 this.fireEvent("panelactivated", this, panel);
50053 this.fireEvent("invalidated");
50057 * Show the specified panel.
50058 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50059 * @return {Roo.ContentPanel} The shown panel or null
50061 showPanel : function(panel){
50062 if(panel = this.getPanel(panel)){
50063 this.setActivePanel(panel);
50069 * Get the active panel for this region.
50070 * @return {Roo.ContentPanel} The active panel or null
50072 getActivePanel : function(){
50073 return this.activePanel;
50077 * Add the passed ContentPanel(s)
50078 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50079 * @return {Roo.ContentPanel} The panel added (if only one was added)
50081 add : function(panel){
50082 if(arguments.length > 1){
50083 for(var i = 0, len = arguments.length; i < len; i++) {
50084 this.add(arguments[i]);
50088 if(this.hasPanel(panel)){
50089 this.showPanel(panel);
50092 var el = panel.getEl();
50093 if(el.dom.parentNode != this.mgr.el.dom){
50094 this.mgr.el.dom.appendChild(el.dom);
50096 if(panel.setRegion){
50097 panel.setRegion(this);
50099 this.panels.add(panel);
50100 el.setStyle("position", "absolute");
50101 if(!panel.background){
50102 this.setActivePanel(panel);
50103 if(this.config.initialSize && this.panels.getCount()==1){
50104 this.resizeTo(this.config.initialSize);
50107 this.fireEvent("paneladded", this, panel);
50112 * Returns true if the panel is in this region.
50113 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50114 * @return {Boolean}
50116 hasPanel : function(panel){
50117 if(typeof panel == "object"){ // must be panel obj
50118 panel = panel.getId();
50120 return this.getPanel(panel) ? true : false;
50124 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50125 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50126 * @param {Boolean} preservePanel Overrides the config preservePanel option
50127 * @return {Roo.ContentPanel} The panel that was removed
50129 remove : function(panel, preservePanel){
50130 panel = this.getPanel(panel);
50135 this.fireEvent("beforeremove", this, panel, e);
50136 if(e.cancel === true){
50139 var panelId = panel.getId();
50140 this.panels.removeKey(panelId);
50145 * Returns the panel specified or null if it's not in this region.
50146 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50147 * @return {Roo.ContentPanel}
50149 getPanel : function(id){
50150 if(typeof id == "object"){ // must be panel obj
50153 return this.panels.get(id);
50157 * Returns this regions position (north/south/east/west/center).
50160 getPosition: function(){
50161 return this.position;
50165 * Ext JS Library 1.1.1
50166 * Copyright(c) 2006-2007, Ext JS, LLC.
50168 * Originally Released Under LGPL - original licence link has changed is not relivant.
50171 * <script type="text/javascript">
50175 * @class Roo.LayoutRegion
50176 * @extends Roo.BasicLayoutRegion
50177 * This class represents a region in a layout manager.
50178 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50179 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50180 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50181 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50182 * @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})
50183 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50184 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50185 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50186 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50187 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50188 * @cfg {String} title The title for the region (overrides panel titles)
50189 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50190 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50191 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50192 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50193 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50194 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50195 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50196 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50197 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50198 * @cfg {Boolean} showPin True to show a pin button
50199 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50200 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50201 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50202 * @cfg {Number} width For East/West panels
50203 * @cfg {Number} height For North/South panels
50204 * @cfg {Boolean} split To show the splitter
50205 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50207 Roo.LayoutRegion = function(mgr, config, pos){
50208 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50209 var dh = Roo.DomHelper;
50210 /** This region's container element
50211 * @type Roo.Element */
50212 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50213 /** This region's title element
50214 * @type Roo.Element */
50216 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50217 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50218 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50220 this.titleEl.enableDisplayMode();
50221 /** This region's title text element
50222 * @type HTMLElement */
50223 this.titleTextEl = this.titleEl.dom.firstChild;
50224 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50225 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50226 this.closeBtn.enableDisplayMode();
50227 this.closeBtn.on("click", this.closeClicked, this);
50228 this.closeBtn.hide();
50230 this.createBody(config);
50231 this.visible = true;
50232 this.collapsed = false;
50234 if(config.hideWhenEmpty){
50236 this.on("paneladded", this.validateVisibility, this);
50237 this.on("panelremoved", this.validateVisibility, this);
50239 this.applyConfig(config);
50242 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50244 createBody : function(){
50245 /** This region's body element
50246 * @type Roo.Element */
50247 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50250 applyConfig : function(c){
50251 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50252 var dh = Roo.DomHelper;
50253 if(c.titlebar !== false){
50254 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50255 this.collapseBtn.on("click", this.collapse, this);
50256 this.collapseBtn.enableDisplayMode();
50258 if(c.showPin === true || this.showPin){
50259 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50260 this.stickBtn.enableDisplayMode();
50261 this.stickBtn.on("click", this.expand, this);
50262 this.stickBtn.hide();
50265 /** This region's collapsed element
50266 * @type Roo.Element */
50267 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50268 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50270 if(c.floatable !== false){
50271 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50272 this.collapsedEl.on("click", this.collapseClick, this);
50275 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50276 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50277 id: "message", unselectable: "on", style:{"float":"left"}});
50278 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50280 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50281 this.expandBtn.on("click", this.expand, this);
50283 if(this.collapseBtn){
50284 this.collapseBtn.setVisible(c.collapsible == true);
50286 this.cmargins = c.cmargins || this.cmargins ||
50287 (this.position == "west" || this.position == "east" ?
50288 {top: 0, left: 2, right:2, bottom: 0} :
50289 {top: 2, left: 0, right:0, bottom: 2});
50290 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50291 this.bottomTabs = c.tabPosition != "top";
50292 this.autoScroll = c.autoScroll || false;
50293 if(this.autoScroll){
50294 this.bodyEl.setStyle("overflow", "auto");
50296 this.bodyEl.setStyle("overflow", "hidden");
50298 //if(c.titlebar !== false){
50299 if((!c.titlebar && !c.title) || c.titlebar === false){
50300 this.titleEl.hide();
50302 this.titleEl.show();
50304 this.titleTextEl.innerHTML = c.title;
50308 this.duration = c.duration || .30;
50309 this.slideDuration = c.slideDuration || .45;
50312 this.collapse(true);
50319 * Returns true if this region is currently visible.
50320 * @return {Boolean}
50322 isVisible : function(){
50323 return this.visible;
50327 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50328 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50330 setCollapsedTitle : function(title){
50331 title = title || " ";
50332 if(this.collapsedTitleTextEl){
50333 this.collapsedTitleTextEl.innerHTML = title;
50337 getBox : function(){
50339 if(!this.collapsed){
50340 b = this.el.getBox(false, true);
50342 b = this.collapsedEl.getBox(false, true);
50347 getMargins : function(){
50348 return this.collapsed ? this.cmargins : this.margins;
50351 highlight : function(){
50352 this.el.addClass("x-layout-panel-dragover");
50355 unhighlight : function(){
50356 this.el.removeClass("x-layout-panel-dragover");
50359 updateBox : function(box){
50361 if(!this.collapsed){
50362 this.el.dom.style.left = box.x + "px";
50363 this.el.dom.style.top = box.y + "px";
50364 this.updateBody(box.width, box.height);
50366 this.collapsedEl.dom.style.left = box.x + "px";
50367 this.collapsedEl.dom.style.top = box.y + "px";
50368 this.collapsedEl.setSize(box.width, box.height);
50371 this.tabs.autoSizeTabs();
50375 updateBody : function(w, h){
50377 this.el.setWidth(w);
50378 w -= this.el.getBorderWidth("rl");
50379 if(this.config.adjustments){
50380 w += this.config.adjustments[0];
50384 this.el.setHeight(h);
50385 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50386 h -= this.el.getBorderWidth("tb");
50387 if(this.config.adjustments){
50388 h += this.config.adjustments[1];
50390 this.bodyEl.setHeight(h);
50392 h = this.tabs.syncHeight(h);
50395 if(this.panelSize){
50396 w = w !== null ? w : this.panelSize.width;
50397 h = h !== null ? h : this.panelSize.height;
50399 if(this.activePanel){
50400 var el = this.activePanel.getEl();
50401 w = w !== null ? w : el.getWidth();
50402 h = h !== null ? h : el.getHeight();
50403 this.panelSize = {width: w, height: h};
50404 this.activePanel.setSize(w, h);
50406 if(Roo.isIE && this.tabs){
50407 this.tabs.el.repaint();
50412 * Returns the container element for this region.
50413 * @return {Roo.Element}
50415 getEl : function(){
50420 * Hides this region.
50423 if(!this.collapsed){
50424 this.el.dom.style.left = "-2000px";
50427 this.collapsedEl.dom.style.left = "-2000px";
50428 this.collapsedEl.hide();
50430 this.visible = false;
50431 this.fireEvent("visibilitychange", this, false);
50435 * Shows this region if it was previously hidden.
50438 if(!this.collapsed){
50441 this.collapsedEl.show();
50443 this.visible = true;
50444 this.fireEvent("visibilitychange", this, true);
50447 closeClicked : function(){
50448 if(this.activePanel){
50449 this.remove(this.activePanel);
50453 collapseClick : function(e){
50455 e.stopPropagation();
50458 e.stopPropagation();
50464 * Collapses this region.
50465 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50467 collapse : function(skipAnim){
50468 if(this.collapsed) return;
50469 this.collapsed = true;
50471 this.split.el.hide();
50473 if(this.config.animate && skipAnim !== true){
50474 this.fireEvent("invalidated", this);
50475 this.animateCollapse();
50477 this.el.setLocation(-20000,-20000);
50479 this.collapsedEl.show();
50480 this.fireEvent("collapsed", this);
50481 this.fireEvent("invalidated", this);
50485 animateCollapse : function(){
50490 * Expands this region if it was previously collapsed.
50491 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50492 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50494 expand : function(e, skipAnim){
50495 if(e) e.stopPropagation();
50496 if(!this.collapsed || this.el.hasActiveFx()) return;
50498 this.afterSlideIn();
50501 this.collapsed = false;
50502 if(this.config.animate && skipAnim !== true){
50503 this.animateExpand();
50507 this.split.el.show();
50509 this.collapsedEl.setLocation(-2000,-2000);
50510 this.collapsedEl.hide();
50511 this.fireEvent("invalidated", this);
50512 this.fireEvent("expanded", this);
50516 animateExpand : function(){
50520 initTabs : function()
50522 this.bodyEl.setStyle("overflow", "hidden");
50523 var ts = new Roo.TabPanel(
50526 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50527 disableTooltips: this.config.disableTabTips,
50528 toolbar : this.config.toolbar
50531 if(this.config.hideTabs){
50532 ts.stripWrap.setDisplayed(false);
50535 ts.resizeTabs = this.config.resizeTabs === true;
50536 ts.minTabWidth = this.config.minTabWidth || 40;
50537 ts.maxTabWidth = this.config.maxTabWidth || 250;
50538 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50539 ts.monitorResize = false;
50540 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50541 ts.bodyEl.addClass('x-layout-tabs-body');
50542 this.panels.each(this.initPanelAsTab, this);
50545 initPanelAsTab : function(panel){
50546 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50547 this.config.closeOnTab && panel.isClosable());
50548 if(panel.tabTip !== undefined){
50549 ti.setTooltip(panel.tabTip);
50551 ti.on("activate", function(){
50552 this.setActivePanel(panel);
50554 if(this.config.closeOnTab){
50555 ti.on("beforeclose", function(t, e){
50557 this.remove(panel);
50563 updatePanelTitle : function(panel, title){
50564 if(this.activePanel == panel){
50565 this.updateTitle(title);
50568 var ti = this.tabs.getTab(panel.getEl().id);
50570 if(panel.tabTip !== undefined){
50571 ti.setTooltip(panel.tabTip);
50576 updateTitle : function(title){
50577 if(this.titleTextEl && !this.config.title){
50578 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50582 setActivePanel : function(panel){
50583 panel = this.getPanel(panel);
50584 if(this.activePanel && this.activePanel != panel){
50585 this.activePanel.setActiveState(false);
50587 this.activePanel = panel;
50588 panel.setActiveState(true);
50589 if(this.panelSize){
50590 panel.setSize(this.panelSize.width, this.panelSize.height);
50593 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50595 this.updateTitle(panel.getTitle());
50597 this.fireEvent("invalidated", this);
50599 this.fireEvent("panelactivated", this, panel);
50603 * Shows the specified panel.
50604 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50605 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50607 showPanel : function(panel)
50609 panel = this.getPanel(panel);
50612 var tab = this.tabs.getTab(panel.getEl().id);
50613 if(tab.isHidden()){
50614 this.tabs.unhideTab(tab.id);
50618 this.setActivePanel(panel);
50625 * Get the active panel for this region.
50626 * @return {Roo.ContentPanel} The active panel or null
50628 getActivePanel : function(){
50629 return this.activePanel;
50632 validateVisibility : function(){
50633 if(this.panels.getCount() < 1){
50634 this.updateTitle(" ");
50635 this.closeBtn.hide();
50638 if(!this.isVisible()){
50645 * Adds the passed ContentPanel(s) to this region.
50646 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50647 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50649 add : function(panel){
50650 if(arguments.length > 1){
50651 for(var i = 0, len = arguments.length; i < len; i++) {
50652 this.add(arguments[i]);
50656 if(this.hasPanel(panel)){
50657 this.showPanel(panel);
50660 panel.setRegion(this);
50661 this.panels.add(panel);
50662 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50663 this.bodyEl.dom.appendChild(panel.getEl().dom);
50664 if(panel.background !== true){
50665 this.setActivePanel(panel);
50667 this.fireEvent("paneladded", this, panel);
50673 this.initPanelAsTab(panel);
50675 if(panel.background !== true){
50676 this.tabs.activate(panel.getEl().id);
50678 this.fireEvent("paneladded", this, panel);
50683 * Hides the tab for the specified panel.
50684 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50686 hidePanel : function(panel){
50687 if(this.tabs && (panel = this.getPanel(panel))){
50688 this.tabs.hideTab(panel.getEl().id);
50693 * Unhides the tab for a previously hidden panel.
50694 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50696 unhidePanel : function(panel){
50697 if(this.tabs && (panel = this.getPanel(panel))){
50698 this.tabs.unhideTab(panel.getEl().id);
50702 clearPanels : function(){
50703 while(this.panels.getCount() > 0){
50704 this.remove(this.panels.first());
50709 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50710 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50711 * @param {Boolean} preservePanel Overrides the config preservePanel option
50712 * @return {Roo.ContentPanel} The panel that was removed
50714 remove : function(panel, preservePanel){
50715 panel = this.getPanel(panel);
50720 this.fireEvent("beforeremove", this, panel, e);
50721 if(e.cancel === true){
50724 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50725 var panelId = panel.getId();
50726 this.panels.removeKey(panelId);
50728 document.body.appendChild(panel.getEl().dom);
50731 this.tabs.removeTab(panel.getEl().id);
50732 }else if (!preservePanel){
50733 this.bodyEl.dom.removeChild(panel.getEl().dom);
50735 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50736 var p = this.panels.first();
50737 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50738 tempEl.appendChild(p.getEl().dom);
50739 this.bodyEl.update("");
50740 this.bodyEl.dom.appendChild(p.getEl().dom);
50742 this.updateTitle(p.getTitle());
50744 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50745 this.setActivePanel(p);
50747 panel.setRegion(null);
50748 if(this.activePanel == panel){
50749 this.activePanel = null;
50751 if(this.config.autoDestroy !== false && preservePanel !== true){
50752 try{panel.destroy();}catch(e){}
50754 this.fireEvent("panelremoved", this, panel);
50759 * Returns the TabPanel component used by this region
50760 * @return {Roo.TabPanel}
50762 getTabs : function(){
50766 createTool : function(parentEl, className){
50767 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50768 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50769 btn.addClassOnOver("x-layout-tools-button-over");
50774 * Ext JS Library 1.1.1
50775 * Copyright(c) 2006-2007, Ext JS, LLC.
50777 * Originally Released Under LGPL - original licence link has changed is not relivant.
50780 * <script type="text/javascript">
50786 * @class Roo.SplitLayoutRegion
50787 * @extends Roo.LayoutRegion
50788 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50790 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50791 this.cursor = cursor;
50792 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50795 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50796 splitTip : "Drag to resize.",
50797 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50798 useSplitTips : false,
50800 applyConfig : function(config){
50801 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50804 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50805 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50806 /** The SplitBar for this region
50807 * @type Roo.SplitBar */
50808 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50809 this.split.on("moved", this.onSplitMove, this);
50810 this.split.useShim = config.useShim === true;
50811 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50812 if(this.useSplitTips){
50813 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50815 if(config.collapsible){
50816 this.split.el.on("dblclick", this.collapse, this);
50819 if(typeof config.minSize != "undefined"){
50820 this.split.minSize = config.minSize;
50822 if(typeof config.maxSize != "undefined"){
50823 this.split.maxSize = config.maxSize;
50825 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50826 this.hideSplitter();
50831 getHMaxSize : function(){
50832 var cmax = this.config.maxSize || 10000;
50833 var center = this.mgr.getRegion("center");
50834 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50837 getVMaxSize : function(){
50838 var cmax = this.config.maxSize || 10000;
50839 var center = this.mgr.getRegion("center");
50840 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50843 onSplitMove : function(split, newSize){
50844 this.fireEvent("resized", this, newSize);
50848 * Returns the {@link Roo.SplitBar} for this region.
50849 * @return {Roo.SplitBar}
50851 getSplitBar : function(){
50856 this.hideSplitter();
50857 Roo.SplitLayoutRegion.superclass.hide.call(this);
50860 hideSplitter : function(){
50862 this.split.el.setLocation(-2000,-2000);
50863 this.split.el.hide();
50869 this.split.el.show();
50871 Roo.SplitLayoutRegion.superclass.show.call(this);
50874 beforeSlide: function(){
50875 if(Roo.isGecko){// firefox overflow auto bug workaround
50876 this.bodyEl.clip();
50877 if(this.tabs) this.tabs.bodyEl.clip();
50878 if(this.activePanel){
50879 this.activePanel.getEl().clip();
50881 if(this.activePanel.beforeSlide){
50882 this.activePanel.beforeSlide();
50888 afterSlide : function(){
50889 if(Roo.isGecko){// firefox overflow auto bug workaround
50890 this.bodyEl.unclip();
50891 if(this.tabs) this.tabs.bodyEl.unclip();
50892 if(this.activePanel){
50893 this.activePanel.getEl().unclip();
50894 if(this.activePanel.afterSlide){
50895 this.activePanel.afterSlide();
50901 initAutoHide : function(){
50902 if(this.autoHide !== false){
50903 if(!this.autoHideHd){
50904 var st = new Roo.util.DelayedTask(this.slideIn, this);
50905 this.autoHideHd = {
50906 "mouseout": function(e){
50907 if(!e.within(this.el, true)){
50911 "mouseover" : function(e){
50917 this.el.on(this.autoHideHd);
50921 clearAutoHide : function(){
50922 if(this.autoHide !== false){
50923 this.el.un("mouseout", this.autoHideHd.mouseout);
50924 this.el.un("mouseover", this.autoHideHd.mouseover);
50928 clearMonitor : function(){
50929 Roo.get(document).un("click", this.slideInIf, this);
50932 // these names are backwards but not changed for compat
50933 slideOut : function(){
50934 if(this.isSlid || this.el.hasActiveFx()){
50937 this.isSlid = true;
50938 if(this.collapseBtn){
50939 this.collapseBtn.hide();
50941 this.closeBtnState = this.closeBtn.getStyle('display');
50942 this.closeBtn.hide();
50944 this.stickBtn.show();
50947 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50948 this.beforeSlide();
50949 this.el.setStyle("z-index", 10001);
50950 this.el.slideIn(this.getSlideAnchor(), {
50951 callback: function(){
50953 this.initAutoHide();
50954 Roo.get(document).on("click", this.slideInIf, this);
50955 this.fireEvent("slideshow", this);
50962 afterSlideIn : function(){
50963 this.clearAutoHide();
50964 this.isSlid = false;
50965 this.clearMonitor();
50966 this.el.setStyle("z-index", "");
50967 if(this.collapseBtn){
50968 this.collapseBtn.show();
50970 this.closeBtn.setStyle('display', this.closeBtnState);
50972 this.stickBtn.hide();
50974 this.fireEvent("slidehide", this);
50977 slideIn : function(cb){
50978 if(!this.isSlid || this.el.hasActiveFx()){
50982 this.isSlid = false;
50983 this.beforeSlide();
50984 this.el.slideOut(this.getSlideAnchor(), {
50985 callback: function(){
50986 this.el.setLeftTop(-10000, -10000);
50988 this.afterSlideIn();
50996 slideInIf : function(e){
50997 if(!e.within(this.el)){
51002 animateCollapse : function(){
51003 this.beforeSlide();
51004 this.el.setStyle("z-index", 20000);
51005 var anchor = this.getSlideAnchor();
51006 this.el.slideOut(anchor, {
51007 callback : function(){
51008 this.el.setStyle("z-index", "");
51009 this.collapsedEl.slideIn(anchor, {duration:.3});
51011 this.el.setLocation(-10000,-10000);
51013 this.fireEvent("collapsed", this);
51020 animateExpand : function(){
51021 this.beforeSlide();
51022 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51023 this.el.setStyle("z-index", 20000);
51024 this.collapsedEl.hide({
51027 this.el.slideIn(this.getSlideAnchor(), {
51028 callback : function(){
51029 this.el.setStyle("z-index", "");
51032 this.split.el.show();
51034 this.fireEvent("invalidated", this);
51035 this.fireEvent("expanded", this);
51063 getAnchor : function(){
51064 return this.anchors[this.position];
51067 getCollapseAnchor : function(){
51068 return this.canchors[this.position];
51071 getSlideAnchor : function(){
51072 return this.sanchors[this.position];
51075 getAlignAdj : function(){
51076 var cm = this.cmargins;
51077 switch(this.position){
51093 getExpandAdj : function(){
51094 var c = this.collapsedEl, cm = this.cmargins;
51095 switch(this.position){
51097 return [-(cm.right+c.getWidth()+cm.left), 0];
51100 return [cm.right+c.getWidth()+cm.left, 0];
51103 return [0, -(cm.top+cm.bottom+c.getHeight())];
51106 return [0, cm.top+cm.bottom+c.getHeight()];
51112 * Ext JS Library 1.1.1
51113 * Copyright(c) 2006-2007, Ext JS, LLC.
51115 * Originally Released Under LGPL - original licence link has changed is not relivant.
51118 * <script type="text/javascript">
51121 * These classes are private internal classes
51123 Roo.CenterLayoutRegion = function(mgr, config){
51124 Roo.LayoutRegion.call(this, mgr, config, "center");
51125 this.visible = true;
51126 this.minWidth = config.minWidth || 20;
51127 this.minHeight = config.minHeight || 20;
51130 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51132 // center panel can't be hidden
51136 // center panel can't be hidden
51139 getMinWidth: function(){
51140 return this.minWidth;
51143 getMinHeight: function(){
51144 return this.minHeight;
51149 Roo.NorthLayoutRegion = function(mgr, config){
51150 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51152 this.split.placement = Roo.SplitBar.TOP;
51153 this.split.orientation = Roo.SplitBar.VERTICAL;
51154 this.split.el.addClass("x-layout-split-v");
51156 var size = config.initialSize || config.height;
51157 if(typeof size != "undefined"){
51158 this.el.setHeight(size);
51161 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51162 orientation: Roo.SplitBar.VERTICAL,
51163 getBox : function(){
51164 if(this.collapsed){
51165 return this.collapsedEl.getBox();
51167 var box = this.el.getBox();
51169 box.height += this.split.el.getHeight();
51174 updateBox : function(box){
51175 if(this.split && !this.collapsed){
51176 box.height -= this.split.el.getHeight();
51177 this.split.el.setLeft(box.x);
51178 this.split.el.setTop(box.y+box.height);
51179 this.split.el.setWidth(box.width);
51181 if(this.collapsed){
51182 this.updateBody(box.width, null);
51184 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51188 Roo.SouthLayoutRegion = function(mgr, config){
51189 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51191 this.split.placement = Roo.SplitBar.BOTTOM;
51192 this.split.orientation = Roo.SplitBar.VERTICAL;
51193 this.split.el.addClass("x-layout-split-v");
51195 var size = config.initialSize || config.height;
51196 if(typeof size != "undefined"){
51197 this.el.setHeight(size);
51200 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51201 orientation: Roo.SplitBar.VERTICAL,
51202 getBox : function(){
51203 if(this.collapsed){
51204 return this.collapsedEl.getBox();
51206 var box = this.el.getBox();
51208 var sh = this.split.el.getHeight();
51215 updateBox : function(box){
51216 if(this.split && !this.collapsed){
51217 var sh = this.split.el.getHeight();
51220 this.split.el.setLeft(box.x);
51221 this.split.el.setTop(box.y-sh);
51222 this.split.el.setWidth(box.width);
51224 if(this.collapsed){
51225 this.updateBody(box.width, null);
51227 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51231 Roo.EastLayoutRegion = function(mgr, config){
51232 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51234 this.split.placement = Roo.SplitBar.RIGHT;
51235 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51236 this.split.el.addClass("x-layout-split-h");
51238 var size = config.initialSize || config.width;
51239 if(typeof size != "undefined"){
51240 this.el.setWidth(size);
51243 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51244 orientation: Roo.SplitBar.HORIZONTAL,
51245 getBox : function(){
51246 if(this.collapsed){
51247 return this.collapsedEl.getBox();
51249 var box = this.el.getBox();
51251 var sw = this.split.el.getWidth();
51258 updateBox : function(box){
51259 if(this.split && !this.collapsed){
51260 var sw = this.split.el.getWidth();
51262 this.split.el.setLeft(box.x);
51263 this.split.el.setTop(box.y);
51264 this.split.el.setHeight(box.height);
51267 if(this.collapsed){
51268 this.updateBody(null, box.height);
51270 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51274 Roo.WestLayoutRegion = function(mgr, config){
51275 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51277 this.split.placement = Roo.SplitBar.LEFT;
51278 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51279 this.split.el.addClass("x-layout-split-h");
51281 var size = config.initialSize || config.width;
51282 if(typeof size != "undefined"){
51283 this.el.setWidth(size);
51286 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51287 orientation: Roo.SplitBar.HORIZONTAL,
51288 getBox : function(){
51289 if(this.collapsed){
51290 return this.collapsedEl.getBox();
51292 var box = this.el.getBox();
51294 box.width += this.split.el.getWidth();
51299 updateBox : function(box){
51300 if(this.split && !this.collapsed){
51301 var sw = this.split.el.getWidth();
51303 this.split.el.setLeft(box.x+box.width);
51304 this.split.el.setTop(box.y);
51305 this.split.el.setHeight(box.height);
51307 if(this.collapsed){
51308 this.updateBody(null, box.height);
51310 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51315 * Ext JS Library 1.1.1
51316 * Copyright(c) 2006-2007, Ext JS, LLC.
51318 * Originally Released Under LGPL - original licence link has changed is not relivant.
51321 * <script type="text/javascript">
51326 * Private internal class for reading and applying state
51328 Roo.LayoutStateManager = function(layout){
51329 // default empty state
51338 Roo.LayoutStateManager.prototype = {
51339 init : function(layout, provider){
51340 this.provider = provider;
51341 var state = provider.get(layout.id+"-layout-state");
51343 var wasUpdating = layout.isUpdating();
51345 layout.beginUpdate();
51347 for(var key in state){
51348 if(typeof state[key] != "function"){
51349 var rstate = state[key];
51350 var r = layout.getRegion(key);
51353 r.resizeTo(rstate.size);
51355 if(rstate.collapsed == true){
51358 r.expand(null, true);
51364 layout.endUpdate();
51366 this.state = state;
51368 this.layout = layout;
51369 layout.on("regionresized", this.onRegionResized, this);
51370 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51371 layout.on("regionexpanded", this.onRegionExpanded, this);
51374 storeState : function(){
51375 this.provider.set(this.layout.id+"-layout-state", this.state);
51378 onRegionResized : function(region, newSize){
51379 this.state[region.getPosition()].size = newSize;
51383 onRegionCollapsed : function(region){
51384 this.state[region.getPosition()].collapsed = true;
51388 onRegionExpanded : function(region){
51389 this.state[region.getPosition()].collapsed = false;
51394 * Ext JS Library 1.1.1
51395 * Copyright(c) 2006-2007, Ext JS, LLC.
51397 * Originally Released Under LGPL - original licence link has changed is not relivant.
51400 * <script type="text/javascript">
51403 * @class Roo.ContentPanel
51404 * @extends Roo.util.Observable
51405 * A basic ContentPanel element.
51406 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51407 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51408 * @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
51409 * @cfg {Boolean} closable True if the panel can be closed/removed
51410 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51411 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51412 * @cfg {Toolbar} toolbar A toolbar for this panel
51413 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51414 * @cfg {String} title The title for this panel
51415 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51416 * @cfg {String} url Calls {@link #setUrl} with this value
51417 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51418 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51419 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51420 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51423 * Create a new ContentPanel.
51424 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51425 * @param {String/Object} config A string to set only the title or a config object
51426 * @param {String} content (optional) Set the HTML content for this panel
51427 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51429 Roo.ContentPanel = function(el, config, content){
51433 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51437 if (config && config.parentLayout) {
51438 el = config.parentLayout.el.createChild();
51441 if(el.autoCreate){ // xtype is available if this is called from factory
51445 this.el = Roo.get(el);
51446 if(!this.el && config && config.autoCreate){
51447 if(typeof config.autoCreate == "object"){
51448 if(!config.autoCreate.id){
51449 config.autoCreate.id = config.id||el;
51451 this.el = Roo.DomHelper.append(document.body,
51452 config.autoCreate, true);
51454 this.el = Roo.DomHelper.append(document.body,
51455 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51458 this.closable = false;
51459 this.loaded = false;
51460 this.active = false;
51461 if(typeof config == "string"){
51462 this.title = config;
51464 Roo.apply(this, config);
51467 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51468 this.wrapEl = this.el.wrap();
51469 this.toolbar.container = this.el.insertSibling(false, 'before');
51470 this.toolbar = new Roo.Toolbar(this.toolbar);
51473 // xtype created footer. - not sure if will work as we normally have to render first..
51474 if (this.footer && !this.footer.el && this.footer.xtype) {
51475 if (!this.wrapEl) {
51476 this.wrapEl = this.el.wrap();
51479 this.footer.container = this.wrapEl.createChild();
51481 this.footer = Roo.factory(this.footer, Roo);
51486 this.resizeEl = Roo.get(this.resizeEl, true);
51488 this.resizeEl = this.el;
51490 // handle view.xtype
51498 * Fires when this panel is activated.
51499 * @param {Roo.ContentPanel} this
51503 * @event deactivate
51504 * Fires when this panel is activated.
51505 * @param {Roo.ContentPanel} this
51507 "deactivate" : true,
51511 * Fires when this panel is resized if fitToFrame is true.
51512 * @param {Roo.ContentPanel} this
51513 * @param {Number} width The width after any component adjustments
51514 * @param {Number} height The height after any component adjustments
51520 * Fires when this tab is created
51521 * @param {Roo.ContentPanel} this
51532 if(this.autoScroll){
51533 this.resizeEl.setStyle("overflow", "auto");
51535 // fix randome scrolling
51536 this.el.on('scroll', function() {
51537 Roo.log('fix random scolling');
51538 this.scrollTo('top',0);
51541 content = content || this.content;
51543 this.setContent(content);
51545 if(config && config.url){
51546 this.setUrl(this.url, this.params, this.loadOnce);
51551 Roo.ContentPanel.superclass.constructor.call(this);
51553 if (this.view && typeof(this.view.xtype) != 'undefined') {
51554 this.view.el = this.el.appendChild(document.createElement("div"));
51555 this.view = Roo.factory(this.view);
51556 this.view.render && this.view.render(false, '');
51560 this.fireEvent('render', this);
51563 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51565 setRegion : function(region){
51566 this.region = region;
51568 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51570 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51575 * Returns the toolbar for this Panel if one was configured.
51576 * @return {Roo.Toolbar}
51578 getToolbar : function(){
51579 return this.toolbar;
51582 setActiveState : function(active){
51583 this.active = active;
51585 this.fireEvent("deactivate", this);
51587 this.fireEvent("activate", this);
51591 * Updates this panel's element
51592 * @param {String} content The new content
51593 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51595 setContent : function(content, loadScripts){
51596 this.el.update(content, loadScripts);
51599 ignoreResize : function(w, h){
51600 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51603 this.lastSize = {width: w, height: h};
51608 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51609 * @return {Roo.UpdateManager} The UpdateManager
51611 getUpdateManager : function(){
51612 return this.el.getUpdateManager();
51615 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51616 * @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:
51619 url: "your-url.php",
51620 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51621 callback: yourFunction,
51622 scope: yourObject, //(optional scope)
51625 text: "Loading...",
51630 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51631 * 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.
51632 * @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}
51633 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51634 * @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.
51635 * @return {Roo.ContentPanel} this
51638 var um = this.el.getUpdateManager();
51639 um.update.apply(um, arguments);
51645 * 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.
51646 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51647 * @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)
51648 * @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)
51649 * @return {Roo.UpdateManager} The UpdateManager
51651 setUrl : function(url, params, loadOnce){
51652 if(this.refreshDelegate){
51653 this.removeListener("activate", this.refreshDelegate);
51655 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51656 this.on("activate", this.refreshDelegate);
51657 return this.el.getUpdateManager();
51660 _handleRefresh : function(url, params, loadOnce){
51661 if(!loadOnce || !this.loaded){
51662 var updater = this.el.getUpdateManager();
51663 updater.update(url, params, this._setLoaded.createDelegate(this));
51667 _setLoaded : function(){
51668 this.loaded = true;
51672 * Returns this panel's id
51675 getId : function(){
51680 * Returns this panel's element - used by regiosn to add.
51681 * @return {Roo.Element}
51683 getEl : function(){
51684 return this.wrapEl || this.el;
51687 adjustForComponents : function(width, height)
51689 //Roo.log('adjustForComponents ');
51690 if(this.resizeEl != this.el){
51691 width -= this.el.getFrameWidth('lr');
51692 height -= this.el.getFrameWidth('tb');
51695 var te = this.toolbar.getEl();
51696 height -= te.getHeight();
51697 te.setWidth(width);
51700 var te = this.footer.getEl();
51701 Roo.log("footer:" + te.getHeight());
51703 height -= te.getHeight();
51704 te.setWidth(width);
51708 if(this.adjustments){
51709 width += this.adjustments[0];
51710 height += this.adjustments[1];
51712 return {"width": width, "height": height};
51715 setSize : function(width, height){
51716 if(this.fitToFrame && !this.ignoreResize(width, height)){
51717 if(this.fitContainer && this.resizeEl != this.el){
51718 this.el.setSize(width, height);
51720 var size = this.adjustForComponents(width, height);
51721 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51722 this.fireEvent('resize', this, size.width, size.height);
51727 * Returns this panel's title
51730 getTitle : function(){
51735 * Set this panel's title
51736 * @param {String} title
51738 setTitle : function(title){
51739 this.title = title;
51741 this.region.updatePanelTitle(this, title);
51746 * Returns true is this panel was configured to be closable
51747 * @return {Boolean}
51749 isClosable : function(){
51750 return this.closable;
51753 beforeSlide : function(){
51755 this.resizeEl.clip();
51758 afterSlide : function(){
51760 this.resizeEl.unclip();
51764 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51765 * Will fail silently if the {@link #setUrl} method has not been called.
51766 * This does not activate the panel, just updates its content.
51768 refresh : function(){
51769 if(this.refreshDelegate){
51770 this.loaded = false;
51771 this.refreshDelegate();
51776 * Destroys this panel
51778 destroy : function(){
51779 this.el.removeAllListeners();
51780 var tempEl = document.createElement("span");
51781 tempEl.appendChild(this.el.dom);
51782 tempEl.innerHTML = "";
51788 * form - if the content panel contains a form - this is a reference to it.
51789 * @type {Roo.form.Form}
51793 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51794 * This contains a reference to it.
51800 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51810 * @param {Object} cfg Xtype definition of item to add.
51813 addxtype : function(cfg) {
51815 if (cfg.xtype.match(/^Form$/)) {
51818 //if (this.footer) {
51819 // el = this.footer.container.insertSibling(false, 'before');
51821 el = this.el.createChild();
51824 this.form = new Roo.form.Form(cfg);
51827 if ( this.form.allItems.length) this.form.render(el.dom);
51830 // should only have one of theses..
51831 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51832 // views.. should not be just added - used named prop 'view''
51834 cfg.el = this.el.appendChild(document.createElement("div"));
51837 var ret = new Roo.factory(cfg);
51839 ret.render && ret.render(false, ''); // render blank..
51848 * @class Roo.GridPanel
51849 * @extends Roo.ContentPanel
51851 * Create a new GridPanel.
51852 * @param {Roo.grid.Grid} grid The grid for this panel
51853 * @param {String/Object} config A string to set only the panel's title, or a config object
51855 Roo.GridPanel = function(grid, config){
51858 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51859 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51861 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51863 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51866 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51868 // xtype created footer. - not sure if will work as we normally have to render first..
51869 if (this.footer && !this.footer.el && this.footer.xtype) {
51871 this.footer.container = this.grid.getView().getFooterPanel(true);
51872 this.footer.dataSource = this.grid.dataSource;
51873 this.footer = Roo.factory(this.footer, Roo);
51877 grid.monitorWindowResize = false; // turn off autosizing
51878 grid.autoHeight = false;
51879 grid.autoWidth = false;
51881 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51884 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51885 getId : function(){
51886 return this.grid.id;
51890 * Returns the grid for this panel
51891 * @return {Roo.grid.Grid}
51893 getGrid : function(){
51897 setSize : function(width, height){
51898 if(!this.ignoreResize(width, height)){
51899 var grid = this.grid;
51900 var size = this.adjustForComponents(width, height);
51901 grid.getGridEl().setSize(size.width, size.height);
51906 beforeSlide : function(){
51907 this.grid.getView().scroller.clip();
51910 afterSlide : function(){
51911 this.grid.getView().scroller.unclip();
51914 destroy : function(){
51915 this.grid.destroy();
51917 Roo.GridPanel.superclass.destroy.call(this);
51923 * @class Roo.NestedLayoutPanel
51924 * @extends Roo.ContentPanel
51926 * Create a new NestedLayoutPanel.
51929 * @param {Roo.BorderLayout} layout The layout for this panel
51930 * @param {String/Object} config A string to set only the title or a config object
51932 Roo.NestedLayoutPanel = function(layout, config)
51934 // construct with only one argument..
51935 /* FIXME - implement nicer consturctors
51936 if (layout.layout) {
51938 layout = config.layout;
51939 delete config.layout;
51941 if (layout.xtype && !layout.getEl) {
51942 // then layout needs constructing..
51943 layout = Roo.factory(layout, Roo);
51948 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51950 layout.monitorWindowResize = false; // turn off autosizing
51951 this.layout = layout;
51952 this.layout.getEl().addClass("x-layout-nested-layout");
51959 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51961 setSize : function(width, height){
51962 if(!this.ignoreResize(width, height)){
51963 var size = this.adjustForComponents(width, height);
51964 var el = this.layout.getEl();
51965 el.setSize(size.width, size.height);
51966 var touch = el.dom.offsetWidth;
51967 this.layout.layout();
51968 // ie requires a double layout on the first pass
51969 if(Roo.isIE && !this.initialized){
51970 this.initialized = true;
51971 this.layout.layout();
51976 // activate all subpanels if not currently active..
51978 setActiveState : function(active){
51979 this.active = active;
51981 this.fireEvent("deactivate", this);
51985 this.fireEvent("activate", this);
51986 // not sure if this should happen before or after..
51987 if (!this.layout) {
51988 return; // should not happen..
51991 for (var r in this.layout.regions) {
51992 reg = this.layout.getRegion(r);
51993 if (reg.getActivePanel()) {
51994 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51995 reg.setActivePanel(reg.getActivePanel());
51998 if (!reg.panels.length) {
52001 reg.showPanel(reg.getPanel(0));
52010 * Returns the nested BorderLayout for this panel
52011 * @return {Roo.BorderLayout}
52013 getLayout : function(){
52014 return this.layout;
52018 * Adds a xtype elements to the layout of the nested panel
52022 xtype : 'ContentPanel',
52029 xtype : 'NestedLayoutPanel',
52035 items : [ ... list of content panels or nested layout panels.. ]
52039 * @param {Object} cfg Xtype definition of item to add.
52041 addxtype : function(cfg) {
52042 return this.layout.addxtype(cfg);
52047 Roo.ScrollPanel = function(el, config, content){
52048 config = config || {};
52049 config.fitToFrame = true;
52050 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52052 this.el.dom.style.overflow = "hidden";
52053 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52054 this.el.removeClass("x-layout-inactive-content");
52055 this.el.on("mousewheel", this.onWheel, this);
52057 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52058 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52059 up.unselectable(); down.unselectable();
52060 up.on("click", this.scrollUp, this);
52061 down.on("click", this.scrollDown, this);
52062 up.addClassOnOver("x-scroller-btn-over");
52063 down.addClassOnOver("x-scroller-btn-over");
52064 up.addClassOnClick("x-scroller-btn-click");
52065 down.addClassOnClick("x-scroller-btn-click");
52066 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52068 this.resizeEl = this.el;
52069 this.el = wrap; this.up = up; this.down = down;
52072 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52074 wheelIncrement : 5,
52075 scrollUp : function(){
52076 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52079 scrollDown : function(){
52080 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52083 afterScroll : function(){
52084 var el = this.resizeEl;
52085 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52086 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52087 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52090 setSize : function(){
52091 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52092 this.afterScroll();
52095 onWheel : function(e){
52096 var d = e.getWheelDelta();
52097 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52098 this.afterScroll();
52102 setContent : function(content, loadScripts){
52103 this.resizeEl.update(content, loadScripts);
52117 * @class Roo.TreePanel
52118 * @extends Roo.ContentPanel
52120 * Create a new TreePanel. - defaults to fit/scoll contents.
52121 * @param {String/Object} config A string to set only the panel's title, or a config object
52122 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52124 Roo.TreePanel = function(config){
52125 var el = config.el;
52126 var tree = config.tree;
52127 delete config.tree;
52128 delete config.el; // hopefull!
52130 // wrapper for IE7 strict & safari scroll issue
52132 var treeEl = el.createChild();
52133 config.resizeEl = treeEl;
52137 Roo.TreePanel.superclass.constructor.call(this, el, config);
52140 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52141 //console.log(tree);
52142 this.on('activate', function()
52144 if (this.tree.rendered) {
52147 //console.log('render tree');
52148 this.tree.render();
52150 // this should not be needed.. - it's actually the 'el' that resizes?
52151 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52153 //this.on('resize', function (cp, w, h) {
52154 // this.tree.innerCt.setWidth(w);
52155 // this.tree.innerCt.setHeight(h);
52156 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52163 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52180 * Ext JS Library 1.1.1
52181 * Copyright(c) 2006-2007, Ext JS, LLC.
52183 * Originally Released Under LGPL - original licence link has changed is not relivant.
52186 * <script type="text/javascript">
52191 * @class Roo.ReaderLayout
52192 * @extends Roo.BorderLayout
52193 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52194 * center region containing two nested regions (a top one for a list view and one for item preview below),
52195 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52196 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52197 * expedites the setup of the overall layout and regions for this common application style.
52200 var reader = new Roo.ReaderLayout();
52201 var CP = Roo.ContentPanel; // shortcut for adding
52203 reader.beginUpdate();
52204 reader.add("north", new CP("north", "North"));
52205 reader.add("west", new CP("west", {title: "West"}));
52206 reader.add("east", new CP("east", {title: "East"}));
52208 reader.regions.listView.add(new CP("listView", "List"));
52209 reader.regions.preview.add(new CP("preview", "Preview"));
52210 reader.endUpdate();
52213 * Create a new ReaderLayout
52214 * @param {Object} config Configuration options
52215 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52216 * document.body if omitted)
52218 Roo.ReaderLayout = function(config, renderTo){
52219 var c = config || {size:{}};
52220 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52221 north: c.north !== false ? Roo.apply({
52225 }, c.north) : false,
52226 west: c.west !== false ? Roo.apply({
52234 margins:{left:5,right:0,bottom:5,top:5},
52235 cmargins:{left:5,right:5,bottom:5,top:5}
52236 }, c.west) : false,
52237 east: c.east !== false ? Roo.apply({
52245 margins:{left:0,right:5,bottom:5,top:5},
52246 cmargins:{left:5,right:5,bottom:5,top:5}
52247 }, c.east) : false,
52248 center: Roo.apply({
52249 tabPosition: 'top',
52253 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52257 this.el.addClass('x-reader');
52259 this.beginUpdate();
52261 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52262 south: c.preview !== false ? Roo.apply({
52269 cmargins:{top:5,left:0, right:0, bottom:0}
52270 }, c.preview) : false,
52271 center: Roo.apply({
52277 this.add('center', new Roo.NestedLayoutPanel(inner,
52278 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52282 this.regions.preview = inner.getRegion('south');
52283 this.regions.listView = inner.getRegion('center');
52286 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52288 * Ext JS Library 1.1.1
52289 * Copyright(c) 2006-2007, Ext JS, LLC.
52291 * Originally Released Under LGPL - original licence link has changed is not relivant.
52294 * <script type="text/javascript">
52298 * @class Roo.grid.Grid
52299 * @extends Roo.util.Observable
52300 * This class represents the primary interface of a component based grid control.
52301 * <br><br>Usage:<pre><code>
52302 var grid = new Roo.grid.Grid("my-container-id", {
52305 selModel: mySelectionModel,
52306 autoSizeColumns: true,
52307 monitorWindowResize: false,
52308 trackMouseOver: true
52313 * <b>Common Problems:</b><br/>
52314 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52315 * element will correct this<br/>
52316 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52317 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52318 * are unpredictable.<br/>
52319 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52320 * grid to calculate dimensions/offsets.<br/>
52322 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52323 * The container MUST have some type of size defined for the grid to fill. The container will be
52324 * automatically set to position relative if it isn't already.
52325 * @param {Object} config A config object that sets properties on this grid.
52327 Roo.grid.Grid = function(container, config){
52328 // initialize the container
52329 this.container = Roo.get(container);
52330 this.container.update("");
52331 this.container.setStyle("overflow", "hidden");
52332 this.container.addClass('x-grid-container');
52334 this.id = this.container.id;
52336 Roo.apply(this, config);
52337 // check and correct shorthanded configs
52339 this.dataSource = this.ds;
52343 this.colModel = this.cm;
52347 this.selModel = this.sm;
52351 if (this.selModel) {
52352 this.selModel = Roo.factory(this.selModel, Roo.grid);
52353 this.sm = this.selModel;
52354 this.sm.xmodule = this.xmodule || false;
52356 if (typeof(this.colModel.config) == 'undefined') {
52357 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52358 this.cm = this.colModel;
52359 this.cm.xmodule = this.xmodule || false;
52361 if (this.dataSource) {
52362 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52363 this.ds = this.dataSource;
52364 this.ds.xmodule = this.xmodule || false;
52371 this.container.setWidth(this.width);
52375 this.container.setHeight(this.height);
52382 * The raw click event for the entire grid.
52383 * @param {Roo.EventObject} e
52388 * The raw dblclick event for the entire grid.
52389 * @param {Roo.EventObject} e
52393 * @event contextmenu
52394 * The raw contextmenu event for the entire grid.
52395 * @param {Roo.EventObject} e
52397 "contextmenu" : true,
52400 * The raw mousedown event for the entire grid.
52401 * @param {Roo.EventObject} e
52403 "mousedown" : true,
52406 * The raw mouseup event for the entire grid.
52407 * @param {Roo.EventObject} e
52412 * The raw mouseover event for the entire grid.
52413 * @param {Roo.EventObject} e
52415 "mouseover" : true,
52418 * The raw mouseout event for the entire grid.
52419 * @param {Roo.EventObject} e
52424 * The raw keypress event for the entire grid.
52425 * @param {Roo.EventObject} e
52430 * The raw keydown event for the entire grid.
52431 * @param {Roo.EventObject} e
52439 * Fires when a cell is clicked
52440 * @param {Grid} this
52441 * @param {Number} rowIndex
52442 * @param {Number} columnIndex
52443 * @param {Roo.EventObject} e
52445 "cellclick" : true,
52447 * @event celldblclick
52448 * Fires when a cell is double clicked
52449 * @param {Grid} this
52450 * @param {Number} rowIndex
52451 * @param {Number} columnIndex
52452 * @param {Roo.EventObject} e
52454 "celldblclick" : true,
52457 * Fires when a row is clicked
52458 * @param {Grid} this
52459 * @param {Number} rowIndex
52460 * @param {Roo.EventObject} e
52464 * @event rowdblclick
52465 * Fires when a row is double clicked
52466 * @param {Grid} this
52467 * @param {Number} rowIndex
52468 * @param {Roo.EventObject} e
52470 "rowdblclick" : true,
52472 * @event headerclick
52473 * Fires when a header is clicked
52474 * @param {Grid} this
52475 * @param {Number} columnIndex
52476 * @param {Roo.EventObject} e
52478 "headerclick" : true,
52480 * @event headerdblclick
52481 * Fires when a header cell is double clicked
52482 * @param {Grid} this
52483 * @param {Number} columnIndex
52484 * @param {Roo.EventObject} e
52486 "headerdblclick" : true,
52488 * @event rowcontextmenu
52489 * Fires when a row is right clicked
52490 * @param {Grid} this
52491 * @param {Number} rowIndex
52492 * @param {Roo.EventObject} e
52494 "rowcontextmenu" : true,
52496 * @event cellcontextmenu
52497 * Fires when a cell is right clicked
52498 * @param {Grid} this
52499 * @param {Number} rowIndex
52500 * @param {Number} cellIndex
52501 * @param {Roo.EventObject} e
52503 "cellcontextmenu" : true,
52505 * @event headercontextmenu
52506 * Fires when a header is right clicked
52507 * @param {Grid} this
52508 * @param {Number} columnIndex
52509 * @param {Roo.EventObject} e
52511 "headercontextmenu" : true,
52513 * @event bodyscroll
52514 * Fires when the body element is scrolled
52515 * @param {Number} scrollLeft
52516 * @param {Number} scrollTop
52518 "bodyscroll" : true,
52520 * @event columnresize
52521 * Fires when the user resizes a column
52522 * @param {Number} columnIndex
52523 * @param {Number} newSize
52525 "columnresize" : true,
52527 * @event columnmove
52528 * Fires when the user moves a column
52529 * @param {Number} oldIndex
52530 * @param {Number} newIndex
52532 "columnmove" : true,
52535 * Fires when row(s) start being dragged
52536 * @param {Grid} this
52537 * @param {Roo.GridDD} dd The drag drop object
52538 * @param {event} e The raw browser event
52540 "startdrag" : true,
52543 * Fires when a drag operation is complete
52544 * @param {Grid} this
52545 * @param {Roo.GridDD} dd The drag drop object
52546 * @param {event} e The raw browser event
52551 * Fires when dragged row(s) are dropped on a valid DD target
52552 * @param {Grid} this
52553 * @param {Roo.GridDD} dd The drag drop object
52554 * @param {String} targetId The target drag drop object
52555 * @param {event} e The raw browser event
52560 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52561 * @param {Grid} this
52562 * @param {Roo.GridDD} dd The drag drop object
52563 * @param {String} targetId The target drag drop object
52564 * @param {event} e The raw browser event
52569 * Fires when the dragged row(s) first cross another DD target while being dragged
52570 * @param {Grid} this
52571 * @param {Roo.GridDD} dd The drag drop object
52572 * @param {String} targetId The target drag drop object
52573 * @param {event} e The raw browser event
52575 "dragenter" : true,
52578 * Fires when the dragged row(s) leave another DD target while being dragged
52579 * @param {Grid} this
52580 * @param {Roo.GridDD} dd The drag drop object
52581 * @param {String} targetId The target drag drop object
52582 * @param {event} e The raw browser event
52587 * Fires when a row is rendered, so you can change add a style to it.
52588 * @param {GridView} gridview The grid view
52589 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52595 * Fires when the grid is rendered
52596 * @param {Grid} grid
52601 Roo.grid.Grid.superclass.constructor.call(this);
52603 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52606 * @cfg {String} ddGroup - drag drop group.
52610 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52612 minColumnWidth : 25,
52615 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52616 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52617 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52619 autoSizeColumns : false,
52622 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52624 autoSizeHeaders : true,
52627 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52629 monitorWindowResize : true,
52632 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52633 * rows measured to get a columns size. Default is 0 (all rows).
52635 maxRowsToMeasure : 0,
52638 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52640 trackMouseOver : true,
52643 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52647 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52649 enableDragDrop : false,
52652 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52654 enableColumnMove : true,
52657 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52659 enableColumnHide : true,
52662 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52664 enableRowHeightSync : false,
52667 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52672 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52674 autoHeight : false,
52677 * @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.
52679 autoExpandColumn : false,
52682 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52685 autoExpandMin : 50,
52688 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52690 autoExpandMax : 1000,
52693 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52698 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52702 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52712 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52713 * of a fixed width. Default is false.
52716 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52719 * Called once after all setup has been completed and the grid is ready to be rendered.
52720 * @return {Roo.grid.Grid} this
52722 render : function()
52724 var c = this.container;
52725 // try to detect autoHeight/width mode
52726 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52727 this.autoHeight = true;
52729 var view = this.getView();
52732 c.on("click", this.onClick, this);
52733 c.on("dblclick", this.onDblClick, this);
52734 c.on("contextmenu", this.onContextMenu, this);
52735 c.on("keydown", this.onKeyDown, this);
52737 c.on("touchstart", this.onTouchStart, this);
52740 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52742 this.getSelectionModel().init(this);
52747 this.loadMask = new Roo.LoadMask(this.container,
52748 Roo.apply({store:this.dataSource}, this.loadMask));
52752 if (this.toolbar && this.toolbar.xtype) {
52753 this.toolbar.container = this.getView().getHeaderPanel(true);
52754 this.toolbar = new Roo.Toolbar(this.toolbar);
52756 if (this.footer && this.footer.xtype) {
52757 this.footer.dataSource = this.getDataSource();
52758 this.footer.container = this.getView().getFooterPanel(true);
52759 this.footer = Roo.factory(this.footer, Roo);
52761 if (this.dropTarget && this.dropTarget.xtype) {
52762 delete this.dropTarget.xtype;
52763 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52767 this.rendered = true;
52768 this.fireEvent('render', this);
52773 * Reconfigures the grid to use a different Store and Column Model.
52774 * The View will be bound to the new objects and refreshed.
52775 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52776 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52778 reconfigure : function(dataSource, colModel){
52780 this.loadMask.destroy();
52781 this.loadMask = new Roo.LoadMask(this.container,
52782 Roo.apply({store:dataSource}, this.loadMask));
52784 this.view.bind(dataSource, colModel);
52785 this.dataSource = dataSource;
52786 this.colModel = colModel;
52787 this.view.refresh(true);
52791 onKeyDown : function(e){
52792 this.fireEvent("keydown", e);
52796 * Destroy this grid.
52797 * @param {Boolean} removeEl True to remove the element
52799 destroy : function(removeEl, keepListeners){
52801 this.loadMask.destroy();
52803 var c = this.container;
52804 c.removeAllListeners();
52805 this.view.destroy();
52806 this.colModel.purgeListeners();
52807 if(!keepListeners){
52808 this.purgeListeners();
52811 if(removeEl === true){
52817 processEvent : function(name, e){
52818 // does this fire select???
52819 //Roo.log('grid:processEvent ' + name);
52821 if (name != 'touchstart' ) {
52822 this.fireEvent(name, e);
52825 var t = e.getTarget();
52827 var header = v.findHeaderIndex(t);
52828 if(header !== false){
52829 var ename = name == 'touchstart' ? 'click' : name;
52831 this.fireEvent("header" + ename, this, header, e);
52833 var row = v.findRowIndex(t);
52834 var cell = v.findCellIndex(t);
52835 if (name == 'touchstart') {
52836 // first touch is always a click.
52837 // hopefull this happens after selection is updated.?
52840 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52841 var cs = this.selModel.getSelectedCell();
52842 if (row == cs[0] && cell == cs[1]){
52846 if (typeof(this.selModel.getSelections) != 'undefined') {
52847 var cs = this.selModel.getSelections();
52848 var ds = this.dataSource;
52849 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52860 this.fireEvent("row" + name, this, row, e);
52861 if(cell !== false){
52862 this.fireEvent("cell" + name, this, row, cell, e);
52869 onClick : function(e){
52870 this.processEvent("click", e);
52873 onTouchStart : function(e){
52874 this.processEvent("touchstart", e);
52878 onContextMenu : function(e, t){
52879 this.processEvent("contextmenu", e);
52883 onDblClick : function(e){
52884 this.processEvent("dblclick", e);
52888 walkCells : function(row, col, step, fn, scope){
52889 var cm = this.colModel, clen = cm.getColumnCount();
52890 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52902 if(fn.call(scope || this, row, col, cm) === true){
52920 if(fn.call(scope || this, row, col, cm) === true){
52932 getSelections : function(){
52933 return this.selModel.getSelections();
52937 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52938 * but if manual update is required this method will initiate it.
52940 autoSize : function(){
52942 this.view.layout();
52943 if(this.view.adjustForScroll){
52944 this.view.adjustForScroll();
52950 * Returns the grid's underlying element.
52951 * @return {Element} The element
52953 getGridEl : function(){
52954 return this.container;
52957 // private for compatibility, overridden by editor grid
52958 stopEditing : function(){},
52961 * Returns the grid's SelectionModel.
52962 * @return {SelectionModel}
52964 getSelectionModel : function(){
52965 if(!this.selModel){
52966 this.selModel = new Roo.grid.RowSelectionModel();
52968 return this.selModel;
52972 * Returns the grid's DataSource.
52973 * @return {DataSource}
52975 getDataSource : function(){
52976 return this.dataSource;
52980 * Returns the grid's ColumnModel.
52981 * @return {ColumnModel}
52983 getColumnModel : function(){
52984 return this.colModel;
52988 * Returns the grid's GridView object.
52989 * @return {GridView}
52991 getView : function(){
52993 this.view = new Roo.grid.GridView(this.viewConfig);
52998 * Called to get grid's drag proxy text, by default returns this.ddText.
53001 getDragDropText : function(){
53002 var count = this.selModel.getCount();
53003 return String.format(this.ddText, count, count == 1 ? '' : 's');
53007 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53008 * %0 is replaced with the number of selected rows.
53011 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53013 * Ext JS Library 1.1.1
53014 * Copyright(c) 2006-2007, Ext JS, LLC.
53016 * Originally Released Under LGPL - original licence link has changed is not relivant.
53019 * <script type="text/javascript">
53022 Roo.grid.AbstractGridView = function(){
53026 "beforerowremoved" : true,
53027 "beforerowsinserted" : true,
53028 "beforerefresh" : true,
53029 "rowremoved" : true,
53030 "rowsinserted" : true,
53031 "rowupdated" : true,
53034 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53037 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53038 rowClass : "x-grid-row",
53039 cellClass : "x-grid-cell",
53040 tdClass : "x-grid-td",
53041 hdClass : "x-grid-hd",
53042 splitClass : "x-grid-hd-split",
53044 init: function(grid){
53046 var cid = this.grid.getGridEl().id;
53047 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53048 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53049 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53050 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53053 getColumnRenderers : function(){
53054 var renderers = [];
53055 var cm = this.grid.colModel;
53056 var colCount = cm.getColumnCount();
53057 for(var i = 0; i < colCount; i++){
53058 renderers[i] = cm.getRenderer(i);
53063 getColumnIds : function(){
53065 var cm = this.grid.colModel;
53066 var colCount = cm.getColumnCount();
53067 for(var i = 0; i < colCount; i++){
53068 ids[i] = cm.getColumnId(i);
53073 getDataIndexes : function(){
53074 if(!this.indexMap){
53075 this.indexMap = this.buildIndexMap();
53077 return this.indexMap.colToData;
53080 getColumnIndexByDataIndex : function(dataIndex){
53081 if(!this.indexMap){
53082 this.indexMap = this.buildIndexMap();
53084 return this.indexMap.dataToCol[dataIndex];
53088 * Set a css style for a column dynamically.
53089 * @param {Number} colIndex The index of the column
53090 * @param {String} name The css property name
53091 * @param {String} value The css value
53093 setCSSStyle : function(colIndex, name, value){
53094 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53095 Roo.util.CSS.updateRule(selector, name, value);
53098 generateRules : function(cm){
53099 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53100 Roo.util.CSS.removeStyleSheet(rulesId);
53101 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53102 var cid = cm.getColumnId(i);
53103 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53104 this.tdSelector, cid, " {\n}\n",
53105 this.hdSelector, cid, " {\n}\n",
53106 this.splitSelector, cid, " {\n}\n");
53108 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53112 * Ext JS Library 1.1.1
53113 * Copyright(c) 2006-2007, Ext JS, LLC.
53115 * Originally Released Under LGPL - original licence link has changed is not relivant.
53118 * <script type="text/javascript">
53122 // This is a support class used internally by the Grid components
53123 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53125 this.view = grid.getView();
53126 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53127 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53129 this.setHandleElId(Roo.id(hd));
53130 this.setOuterHandleElId(Roo.id(hd2));
53132 this.scroll = false;
53134 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53136 getDragData : function(e){
53137 var t = Roo.lib.Event.getTarget(e);
53138 var h = this.view.findHeaderCell(t);
53140 return {ddel: h.firstChild, header:h};
53145 onInitDrag : function(e){
53146 this.view.headersDisabled = true;
53147 var clone = this.dragData.ddel.cloneNode(true);
53148 clone.id = Roo.id();
53149 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53150 this.proxy.update(clone);
53154 afterValidDrop : function(){
53156 setTimeout(function(){
53157 v.headersDisabled = false;
53161 afterInvalidDrop : function(){
53163 setTimeout(function(){
53164 v.headersDisabled = false;
53170 * Ext JS Library 1.1.1
53171 * Copyright(c) 2006-2007, Ext JS, LLC.
53173 * Originally Released Under LGPL - original licence link has changed is not relivant.
53176 * <script type="text/javascript">
53179 // This is a support class used internally by the Grid components
53180 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53182 this.view = grid.getView();
53183 // split the proxies so they don't interfere with mouse events
53184 this.proxyTop = Roo.DomHelper.append(document.body, {
53185 cls:"col-move-top", html:" "
53187 this.proxyBottom = Roo.DomHelper.append(document.body, {
53188 cls:"col-move-bottom", html:" "
53190 this.proxyTop.hide = this.proxyBottom.hide = function(){
53191 this.setLeftTop(-100,-100);
53192 this.setStyle("visibility", "hidden");
53194 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53195 // temporarily disabled
53196 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53197 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53199 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53200 proxyOffsets : [-4, -9],
53201 fly: Roo.Element.fly,
53203 getTargetFromEvent : function(e){
53204 var t = Roo.lib.Event.getTarget(e);
53205 var cindex = this.view.findCellIndex(t);
53206 if(cindex !== false){
53207 return this.view.getHeaderCell(cindex);
53212 nextVisible : function(h){
53213 var v = this.view, cm = this.grid.colModel;
53216 if(!cm.isHidden(v.getCellIndex(h))){
53224 prevVisible : function(h){
53225 var v = this.view, cm = this.grid.colModel;
53228 if(!cm.isHidden(v.getCellIndex(h))){
53236 positionIndicator : function(h, n, e){
53237 var x = Roo.lib.Event.getPageX(e);
53238 var r = Roo.lib.Dom.getRegion(n.firstChild);
53239 var px, pt, py = r.top + this.proxyOffsets[1];
53240 if((r.right - x) <= (r.right-r.left)/2){
53241 px = r.right+this.view.borderWidth;
53247 var oldIndex = this.view.getCellIndex(h);
53248 var newIndex = this.view.getCellIndex(n);
53250 if(this.grid.colModel.isFixed(newIndex)){
53254 var locked = this.grid.colModel.isLocked(newIndex);
53259 if(oldIndex < newIndex){
53262 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53265 px += this.proxyOffsets[0];
53266 this.proxyTop.setLeftTop(px, py);
53267 this.proxyTop.show();
53268 if(!this.bottomOffset){
53269 this.bottomOffset = this.view.mainHd.getHeight();
53271 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53272 this.proxyBottom.show();
53276 onNodeEnter : function(n, dd, e, data){
53277 if(data.header != n){
53278 this.positionIndicator(data.header, n, e);
53282 onNodeOver : function(n, dd, e, data){
53283 var result = false;
53284 if(data.header != n){
53285 result = this.positionIndicator(data.header, n, e);
53288 this.proxyTop.hide();
53289 this.proxyBottom.hide();
53291 return result ? this.dropAllowed : this.dropNotAllowed;
53294 onNodeOut : function(n, dd, e, data){
53295 this.proxyTop.hide();
53296 this.proxyBottom.hide();
53299 onNodeDrop : function(n, dd, e, data){
53300 var h = data.header;
53302 var cm = this.grid.colModel;
53303 var x = Roo.lib.Event.getPageX(e);
53304 var r = Roo.lib.Dom.getRegion(n.firstChild);
53305 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53306 var oldIndex = this.view.getCellIndex(h);
53307 var newIndex = this.view.getCellIndex(n);
53308 var locked = cm.isLocked(newIndex);
53312 if(oldIndex < newIndex){
53315 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53318 cm.setLocked(oldIndex, locked, true);
53319 cm.moveColumn(oldIndex, newIndex);
53320 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53328 * Ext JS Library 1.1.1
53329 * Copyright(c) 2006-2007, Ext JS, LLC.
53331 * Originally Released Under LGPL - original licence link has changed is not relivant.
53334 * <script type="text/javascript">
53338 * @class Roo.grid.GridView
53339 * @extends Roo.util.Observable
53342 * @param {Object} config
53344 Roo.grid.GridView = function(config){
53345 Roo.grid.GridView.superclass.constructor.call(this);
53348 Roo.apply(this, config);
53351 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53353 unselectable : 'unselectable="on"',
53354 unselectableCls : 'x-unselectable',
53357 rowClass : "x-grid-row",
53359 cellClass : "x-grid-col",
53361 tdClass : "x-grid-td",
53363 hdClass : "x-grid-hd",
53365 splitClass : "x-grid-split",
53367 sortClasses : ["sort-asc", "sort-desc"],
53369 enableMoveAnim : false,
53373 dh : Roo.DomHelper,
53375 fly : Roo.Element.fly,
53377 css : Roo.util.CSS,
53383 scrollIncrement : 22,
53385 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53387 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53389 bind : function(ds, cm){
53391 this.ds.un("load", this.onLoad, this);
53392 this.ds.un("datachanged", this.onDataChange, this);
53393 this.ds.un("add", this.onAdd, this);
53394 this.ds.un("remove", this.onRemove, this);
53395 this.ds.un("update", this.onUpdate, this);
53396 this.ds.un("clear", this.onClear, this);
53399 ds.on("load", this.onLoad, this);
53400 ds.on("datachanged", this.onDataChange, this);
53401 ds.on("add", this.onAdd, this);
53402 ds.on("remove", this.onRemove, this);
53403 ds.on("update", this.onUpdate, this);
53404 ds.on("clear", this.onClear, this);
53409 this.cm.un("widthchange", this.onColWidthChange, this);
53410 this.cm.un("headerchange", this.onHeaderChange, this);
53411 this.cm.un("hiddenchange", this.onHiddenChange, this);
53412 this.cm.un("columnmoved", this.onColumnMove, this);
53413 this.cm.un("columnlockchange", this.onColumnLock, this);
53416 this.generateRules(cm);
53417 cm.on("widthchange", this.onColWidthChange, this);
53418 cm.on("headerchange", this.onHeaderChange, this);
53419 cm.on("hiddenchange", this.onHiddenChange, this);
53420 cm.on("columnmoved", this.onColumnMove, this);
53421 cm.on("columnlockchange", this.onColumnLock, this);
53426 init: function(grid){
53427 Roo.grid.GridView.superclass.init.call(this, grid);
53429 this.bind(grid.dataSource, grid.colModel);
53431 grid.on("headerclick", this.handleHeaderClick, this);
53433 if(grid.trackMouseOver){
53434 grid.on("mouseover", this.onRowOver, this);
53435 grid.on("mouseout", this.onRowOut, this);
53437 grid.cancelTextSelection = function(){};
53438 this.gridId = grid.id;
53440 var tpls = this.templates || {};
53443 tpls.master = new Roo.Template(
53444 '<div class="x-grid" hidefocus="true">',
53445 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53446 '<div class="x-grid-topbar"></div>',
53447 '<div class="x-grid-scroller"><div></div></div>',
53448 '<div class="x-grid-locked">',
53449 '<div class="x-grid-header">{lockedHeader}</div>',
53450 '<div class="x-grid-body">{lockedBody}</div>',
53452 '<div class="x-grid-viewport">',
53453 '<div class="x-grid-header">{header}</div>',
53454 '<div class="x-grid-body">{body}</div>',
53456 '<div class="x-grid-bottombar"></div>',
53458 '<div class="x-grid-resize-proxy"> </div>',
53461 tpls.master.disableformats = true;
53465 tpls.header = new Roo.Template(
53466 '<table border="0" cellspacing="0" cellpadding="0">',
53467 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53470 tpls.header.disableformats = true;
53472 tpls.header.compile();
53475 tpls.hcell = new Roo.Template(
53476 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53477 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53480 tpls.hcell.disableFormats = true;
53482 tpls.hcell.compile();
53485 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53486 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53487 tpls.hsplit.disableFormats = true;
53489 tpls.hsplit.compile();
53492 tpls.body = new Roo.Template(
53493 '<table border="0" cellspacing="0" cellpadding="0">',
53494 "<tbody>{rows}</tbody>",
53497 tpls.body.disableFormats = true;
53499 tpls.body.compile();
53502 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53503 tpls.row.disableFormats = true;
53505 tpls.row.compile();
53508 tpls.cell = new Roo.Template(
53509 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53510 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53511 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53514 tpls.cell.disableFormats = true;
53516 tpls.cell.compile();
53518 this.templates = tpls;
53521 // remap these for backwards compat
53522 onColWidthChange : function(){
53523 this.updateColumns.apply(this, arguments);
53525 onHeaderChange : function(){
53526 this.updateHeaders.apply(this, arguments);
53528 onHiddenChange : function(){
53529 this.handleHiddenChange.apply(this, arguments);
53531 onColumnMove : function(){
53532 this.handleColumnMove.apply(this, arguments);
53534 onColumnLock : function(){
53535 this.handleLockChange.apply(this, arguments);
53538 onDataChange : function(){
53540 this.updateHeaderSortState();
53543 onClear : function(){
53547 onUpdate : function(ds, record){
53548 this.refreshRow(record);
53551 refreshRow : function(record){
53552 var ds = this.ds, index;
53553 if(typeof record == 'number'){
53555 record = ds.getAt(index);
53557 index = ds.indexOf(record);
53559 this.insertRows(ds, index, index, true);
53560 this.onRemove(ds, record, index+1, true);
53561 this.syncRowHeights(index, index);
53563 this.fireEvent("rowupdated", this, index, record);
53566 onAdd : function(ds, records, index){
53567 this.insertRows(ds, index, index + (records.length-1));
53570 onRemove : function(ds, record, index, isUpdate){
53571 if(isUpdate !== true){
53572 this.fireEvent("beforerowremoved", this, index, record);
53574 var bt = this.getBodyTable(), lt = this.getLockedTable();
53575 if(bt.rows[index]){
53576 bt.firstChild.removeChild(bt.rows[index]);
53578 if(lt.rows[index]){
53579 lt.firstChild.removeChild(lt.rows[index]);
53581 if(isUpdate !== true){
53582 this.stripeRows(index);
53583 this.syncRowHeights(index, index);
53585 this.fireEvent("rowremoved", this, index, record);
53589 onLoad : function(){
53590 this.scrollToTop();
53594 * Scrolls the grid to the top
53596 scrollToTop : function(){
53598 this.scroller.dom.scrollTop = 0;
53604 * Gets a panel in the header of the grid that can be used for toolbars etc.
53605 * After modifying the contents of this panel a call to grid.autoSize() may be
53606 * required to register any changes in size.
53607 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53608 * @return Roo.Element
53610 getHeaderPanel : function(doShow){
53612 this.headerPanel.show();
53614 return this.headerPanel;
53618 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53619 * After modifying the contents of this panel a call to grid.autoSize() may be
53620 * required to register any changes in size.
53621 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53622 * @return Roo.Element
53624 getFooterPanel : function(doShow){
53626 this.footerPanel.show();
53628 return this.footerPanel;
53631 initElements : function(){
53632 var E = Roo.Element;
53633 var el = this.grid.getGridEl().dom.firstChild;
53634 var cs = el.childNodes;
53636 this.el = new E(el);
53638 this.focusEl = new E(el.firstChild);
53639 this.focusEl.swallowEvent("click", true);
53641 this.headerPanel = new E(cs[1]);
53642 this.headerPanel.enableDisplayMode("block");
53644 this.scroller = new E(cs[2]);
53645 this.scrollSizer = new E(this.scroller.dom.firstChild);
53647 this.lockedWrap = new E(cs[3]);
53648 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53649 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53651 this.mainWrap = new E(cs[4]);
53652 this.mainHd = new E(this.mainWrap.dom.firstChild);
53653 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53655 this.footerPanel = new E(cs[5]);
53656 this.footerPanel.enableDisplayMode("block");
53658 this.resizeProxy = new E(cs[6]);
53660 this.headerSelector = String.format(
53661 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53662 this.lockedHd.id, this.mainHd.id
53665 this.splitterSelector = String.format(
53666 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53667 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53670 idToCssName : function(s)
53672 return s.replace(/[^a-z0-9]+/ig, '-');
53675 getHeaderCell : function(index){
53676 return Roo.DomQuery.select(this.headerSelector)[index];
53679 getHeaderCellMeasure : function(index){
53680 return this.getHeaderCell(index).firstChild;
53683 getHeaderCellText : function(index){
53684 return this.getHeaderCell(index).firstChild.firstChild;
53687 getLockedTable : function(){
53688 return this.lockedBody.dom.firstChild;
53691 getBodyTable : function(){
53692 return this.mainBody.dom.firstChild;
53695 getLockedRow : function(index){
53696 return this.getLockedTable().rows[index];
53699 getRow : function(index){
53700 return this.getBodyTable().rows[index];
53703 getRowComposite : function(index){
53705 this.rowEl = new Roo.CompositeElementLite();
53707 var els = [], lrow, mrow;
53708 if(lrow = this.getLockedRow(index)){
53711 if(mrow = this.getRow(index)){
53714 this.rowEl.elements = els;
53718 * Gets the 'td' of the cell
53720 * @param {Integer} rowIndex row to select
53721 * @param {Integer} colIndex column to select
53725 getCell : function(rowIndex, colIndex){
53726 var locked = this.cm.getLockedCount();
53728 if(colIndex < locked){
53729 source = this.lockedBody.dom.firstChild;
53731 source = this.mainBody.dom.firstChild;
53732 colIndex -= locked;
53734 return source.rows[rowIndex].childNodes[colIndex];
53737 getCellText : function(rowIndex, colIndex){
53738 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53741 getCellBox : function(cell){
53742 var b = this.fly(cell).getBox();
53743 if(Roo.isOpera){ // opera fails to report the Y
53744 b.y = cell.offsetTop + this.mainBody.getY();
53749 getCellIndex : function(cell){
53750 var id = String(cell.className).match(this.cellRE);
53752 return parseInt(id[1], 10);
53757 findHeaderIndex : function(n){
53758 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53759 return r ? this.getCellIndex(r) : false;
53762 findHeaderCell : function(n){
53763 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53764 return r ? r : false;
53767 findRowIndex : function(n){
53771 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53772 return r ? r.rowIndex : false;
53775 findCellIndex : function(node){
53776 var stop = this.el.dom;
53777 while(node && node != stop){
53778 if(this.findRE.test(node.className)){
53779 return this.getCellIndex(node);
53781 node = node.parentNode;
53786 getColumnId : function(index){
53787 return this.cm.getColumnId(index);
53790 getSplitters : function()
53792 if(this.splitterSelector){
53793 return Roo.DomQuery.select(this.splitterSelector);
53799 getSplitter : function(index){
53800 return this.getSplitters()[index];
53803 onRowOver : function(e, t){
53805 if((row = this.findRowIndex(t)) !== false){
53806 this.getRowComposite(row).addClass("x-grid-row-over");
53810 onRowOut : function(e, t){
53812 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53813 this.getRowComposite(row).removeClass("x-grid-row-over");
53817 renderHeaders : function(){
53819 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53820 var cb = [], lb = [], sb = [], lsb = [], p = {};
53821 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53822 p.cellId = "x-grid-hd-0-" + i;
53823 p.splitId = "x-grid-csplit-0-" + i;
53824 p.id = cm.getColumnId(i);
53825 p.title = cm.getColumnTooltip(i) || "";
53826 p.value = cm.getColumnHeader(i) || "";
53827 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53828 if(!cm.isLocked(i)){
53829 cb[cb.length] = ct.apply(p);
53830 sb[sb.length] = st.apply(p);
53832 lb[lb.length] = ct.apply(p);
53833 lsb[lsb.length] = st.apply(p);
53836 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53837 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53840 updateHeaders : function(){
53841 var html = this.renderHeaders();
53842 this.lockedHd.update(html[0]);
53843 this.mainHd.update(html[1]);
53847 * Focuses the specified row.
53848 * @param {Number} row The row index
53850 focusRow : function(row)
53852 //Roo.log('GridView.focusRow');
53853 var x = this.scroller.dom.scrollLeft;
53854 this.focusCell(row, 0, false);
53855 this.scroller.dom.scrollLeft = x;
53859 * Focuses the specified cell.
53860 * @param {Number} row The row index
53861 * @param {Number} col The column index
53862 * @param {Boolean} hscroll false to disable horizontal scrolling
53864 focusCell : function(row, col, hscroll)
53866 //Roo.log('GridView.focusCell');
53867 var el = this.ensureVisible(row, col, hscroll);
53868 this.focusEl.alignTo(el, "tl-tl");
53870 this.focusEl.focus();
53872 this.focusEl.focus.defer(1, this.focusEl);
53877 * Scrolls the specified cell into view
53878 * @param {Number} row The row index
53879 * @param {Number} col The column index
53880 * @param {Boolean} hscroll false to disable horizontal scrolling
53882 ensureVisible : function(row, col, hscroll)
53884 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53885 //return null; //disable for testing.
53886 if(typeof row != "number"){
53887 row = row.rowIndex;
53889 if(row < 0 && row >= this.ds.getCount()){
53892 col = (col !== undefined ? col : 0);
53893 var cm = this.grid.colModel;
53894 while(cm.isHidden(col)){
53898 var el = this.getCell(row, col);
53902 var c = this.scroller.dom;
53904 var ctop = parseInt(el.offsetTop, 10);
53905 var cleft = parseInt(el.offsetLeft, 10);
53906 var cbot = ctop + el.offsetHeight;
53907 var cright = cleft + el.offsetWidth;
53909 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53910 var stop = parseInt(c.scrollTop, 10);
53911 var sleft = parseInt(c.scrollLeft, 10);
53912 var sbot = stop + ch;
53913 var sright = sleft + c.clientWidth;
53915 Roo.log('GridView.ensureVisible:' +
53917 ' c.clientHeight:' + c.clientHeight +
53918 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53926 c.scrollTop = ctop;
53927 //Roo.log("set scrolltop to ctop DISABLE?");
53928 }else if(cbot > sbot){
53929 //Roo.log("set scrolltop to cbot-ch");
53930 c.scrollTop = cbot-ch;
53933 if(hscroll !== false){
53935 c.scrollLeft = cleft;
53936 }else if(cright > sright){
53937 c.scrollLeft = cright-c.clientWidth;
53944 updateColumns : function(){
53945 this.grid.stopEditing();
53946 var cm = this.grid.colModel, colIds = this.getColumnIds();
53947 //var totalWidth = cm.getTotalWidth();
53949 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53950 //if(cm.isHidden(i)) continue;
53951 var w = cm.getColumnWidth(i);
53952 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53953 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53955 this.updateSplitters();
53958 generateRules : function(cm){
53959 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53960 Roo.util.CSS.removeStyleSheet(rulesId);
53961 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53962 var cid = cm.getColumnId(i);
53964 if(cm.config[i].align){
53965 align = 'text-align:'+cm.config[i].align+';';
53968 if(cm.isHidden(i)){
53969 hidden = 'display:none;';
53971 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53973 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53974 this.hdSelector, cid, " {\n", align, width, "}\n",
53975 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53976 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53978 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53981 updateSplitters : function(){
53982 var cm = this.cm, s = this.getSplitters();
53983 if(s){ // splitters not created yet
53984 var pos = 0, locked = true;
53985 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53986 if(cm.isHidden(i)) continue;
53987 var w = cm.getColumnWidth(i); // make sure it's a number
53988 if(!cm.isLocked(i) && locked){
53993 s[i].style.left = (pos-this.splitOffset) + "px";
53998 handleHiddenChange : function(colModel, colIndex, hidden){
54000 this.hideColumn(colIndex);
54002 this.unhideColumn(colIndex);
54006 hideColumn : function(colIndex){
54007 var cid = this.getColumnId(colIndex);
54008 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54009 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54011 this.updateHeaders();
54013 this.updateSplitters();
54017 unhideColumn : function(colIndex){
54018 var cid = this.getColumnId(colIndex);
54019 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54020 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54023 this.updateHeaders();
54025 this.updateSplitters();
54029 insertRows : function(dm, firstRow, lastRow, isUpdate){
54030 if(firstRow == 0 && lastRow == dm.getCount()-1){
54034 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54036 var s = this.getScrollState();
54037 var markup = this.renderRows(firstRow, lastRow);
54038 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54039 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54040 this.restoreScroll(s);
54042 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54043 this.syncRowHeights(firstRow, lastRow);
54044 this.stripeRows(firstRow);
54050 bufferRows : function(markup, target, index){
54051 var before = null, trows = target.rows, tbody = target.tBodies[0];
54052 if(index < trows.length){
54053 before = trows[index];
54055 var b = document.createElement("div");
54056 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54057 var rows = b.firstChild.rows;
54058 for(var i = 0, len = rows.length; i < len; i++){
54060 tbody.insertBefore(rows[0], before);
54062 tbody.appendChild(rows[0]);
54069 deleteRows : function(dm, firstRow, lastRow){
54070 if(dm.getRowCount()<1){
54071 this.fireEvent("beforerefresh", this);
54072 this.mainBody.update("");
54073 this.lockedBody.update("");
54074 this.fireEvent("refresh", this);
54076 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54077 var bt = this.getBodyTable();
54078 var tbody = bt.firstChild;
54079 var rows = bt.rows;
54080 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54081 tbody.removeChild(rows[firstRow]);
54083 this.stripeRows(firstRow);
54084 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54088 updateRows : function(dataSource, firstRow, lastRow){
54089 var s = this.getScrollState();
54091 this.restoreScroll(s);
54094 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54098 this.updateHeaderSortState();
54101 getScrollState : function(){
54103 var sb = this.scroller.dom;
54104 return {left: sb.scrollLeft, top: sb.scrollTop};
54107 stripeRows : function(startRow){
54108 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54111 startRow = startRow || 0;
54112 var rows = this.getBodyTable().rows;
54113 var lrows = this.getLockedTable().rows;
54114 var cls = ' x-grid-row-alt ';
54115 for(var i = startRow, len = rows.length; i < len; i++){
54116 var row = rows[i], lrow = lrows[i];
54117 var isAlt = ((i+1) % 2 == 0);
54118 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54119 if(isAlt == hasAlt){
54123 row.className += " x-grid-row-alt";
54125 row.className = row.className.replace("x-grid-row-alt", "");
54128 lrow.className = row.className;
54133 restoreScroll : function(state){
54134 //Roo.log('GridView.restoreScroll');
54135 var sb = this.scroller.dom;
54136 sb.scrollLeft = state.left;
54137 sb.scrollTop = state.top;
54141 syncScroll : function(){
54142 //Roo.log('GridView.syncScroll');
54143 var sb = this.scroller.dom;
54144 var sh = this.mainHd.dom;
54145 var bs = this.mainBody.dom;
54146 var lv = this.lockedBody.dom;
54147 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54148 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54151 handleScroll : function(e){
54153 var sb = this.scroller.dom;
54154 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54158 handleWheel : function(e){
54159 var d = e.getWheelDelta();
54160 this.scroller.dom.scrollTop -= d*22;
54161 // set this here to prevent jumpy scrolling on large tables
54162 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54166 renderRows : function(startRow, endRow){
54167 // pull in all the crap needed to render rows
54168 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54169 var colCount = cm.getColumnCount();
54171 if(ds.getCount() < 1){
54175 // build a map for all the columns
54177 for(var i = 0; i < colCount; i++){
54178 var name = cm.getDataIndex(i);
54180 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54181 renderer : cm.getRenderer(i),
54182 id : cm.getColumnId(i),
54183 locked : cm.isLocked(i)
54187 startRow = startRow || 0;
54188 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54190 // records to render
54191 var rs = ds.getRange(startRow, endRow);
54193 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54196 // As much as I hate to duplicate code, this was branched because FireFox really hates
54197 // [].join("") on strings. The performance difference was substantial enough to
54198 // branch this function
54199 doRender : Roo.isGecko ?
54200 function(cs, rs, ds, startRow, colCount, stripe){
54201 var ts = this.templates, ct = ts.cell, rt = ts.row;
54203 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54205 var hasListener = this.grid.hasListener('rowclass');
54207 for(var j = 0, len = rs.length; j < len; j++){
54208 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54209 for(var i = 0; i < colCount; i++){
54211 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54213 p.css = p.attr = "";
54214 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54215 if(p.value == undefined || p.value === "") p.value = " ";
54216 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54217 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54219 var markup = ct.apply(p);
54227 if(stripe && ((rowIndex+1) % 2 == 0)){
54228 alt.push("x-grid-row-alt")
54231 alt.push( " x-grid-dirty-row");
54234 if(this.getRowClass){
54235 alt.push(this.getRowClass(r, rowIndex));
54241 rowIndex : rowIndex,
54244 this.grid.fireEvent('rowclass', this, rowcfg);
54245 alt.push(rowcfg.rowClass);
54247 rp.alt = alt.join(" ");
54248 lbuf+= rt.apply(rp);
54250 buf+= rt.apply(rp);
54252 return [lbuf, buf];
54254 function(cs, rs, ds, startRow, colCount, stripe){
54255 var ts = this.templates, ct = ts.cell, rt = ts.row;
54257 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54258 var hasListener = this.grid.hasListener('rowclass');
54261 for(var j = 0, len = rs.length; j < len; j++){
54262 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54263 for(var i = 0; i < colCount; i++){
54265 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54267 p.css = p.attr = "";
54268 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54269 if(p.value == undefined || p.value === "") p.value = " ";
54270 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54271 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54274 var markup = ct.apply(p);
54276 cb[cb.length] = markup;
54278 lcb[lcb.length] = markup;
54282 if(stripe && ((rowIndex+1) % 2 == 0)){
54283 alt.push( "x-grid-row-alt");
54286 alt.push(" x-grid-dirty-row");
54289 if(this.getRowClass){
54290 alt.push( this.getRowClass(r, rowIndex));
54296 rowIndex : rowIndex,
54299 this.grid.fireEvent('rowclass', this, rowcfg);
54300 alt.push(rowcfg.rowClass);
54302 rp.alt = alt.join(" ");
54303 rp.cells = lcb.join("");
54304 lbuf[lbuf.length] = rt.apply(rp);
54305 rp.cells = cb.join("");
54306 buf[buf.length] = rt.apply(rp);
54308 return [lbuf.join(""), buf.join("")];
54311 renderBody : function(){
54312 var markup = this.renderRows();
54313 var bt = this.templates.body;
54314 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54318 * Refreshes the grid
54319 * @param {Boolean} headersToo
54321 refresh : function(headersToo){
54322 this.fireEvent("beforerefresh", this);
54323 this.grid.stopEditing();
54324 var result = this.renderBody();
54325 this.lockedBody.update(result[0]);
54326 this.mainBody.update(result[1]);
54327 if(headersToo === true){
54328 this.updateHeaders();
54329 this.updateColumns();
54330 this.updateSplitters();
54331 this.updateHeaderSortState();
54333 this.syncRowHeights();
54335 this.fireEvent("refresh", this);
54338 handleColumnMove : function(cm, oldIndex, newIndex){
54339 this.indexMap = null;
54340 var s = this.getScrollState();
54341 this.refresh(true);
54342 this.restoreScroll(s);
54343 this.afterMove(newIndex);
54346 afterMove : function(colIndex){
54347 if(this.enableMoveAnim && Roo.enableFx){
54348 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54350 // if multisort - fix sortOrder, and reload..
54351 if (this.grid.dataSource.multiSort) {
54352 // the we can call sort again..
54353 var dm = this.grid.dataSource;
54354 var cm = this.grid.colModel;
54356 for(var i = 0; i < cm.config.length; i++ ) {
54358 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54359 continue; // dont' bother, it's not in sort list or being set.
54362 so.push(cm.config[i].dataIndex);
54365 dm.load(dm.lastOptions);
54372 updateCell : function(dm, rowIndex, dataIndex){
54373 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54374 if(typeof colIndex == "undefined"){ // not present in grid
54377 var cm = this.grid.colModel;
54378 var cell = this.getCell(rowIndex, colIndex);
54379 var cellText = this.getCellText(rowIndex, colIndex);
54382 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54383 id : cm.getColumnId(colIndex),
54384 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54386 var renderer = cm.getRenderer(colIndex);
54387 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54388 if(typeof val == "undefined" || val === "") val = " ";
54389 cellText.innerHTML = val;
54390 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54391 this.syncRowHeights(rowIndex, rowIndex);
54394 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54396 if(this.grid.autoSizeHeaders){
54397 var h = this.getHeaderCellMeasure(colIndex);
54398 maxWidth = Math.max(maxWidth, h.scrollWidth);
54401 if(this.cm.isLocked(colIndex)){
54402 tb = this.getLockedTable();
54405 tb = this.getBodyTable();
54406 index = colIndex - this.cm.getLockedCount();
54409 var rows = tb.rows;
54410 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54411 for(var i = 0; i < stopIndex; i++){
54412 var cell = rows[i].childNodes[index].firstChild;
54413 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54416 return maxWidth + /*margin for error in IE*/ 5;
54419 * Autofit a column to its content.
54420 * @param {Number} colIndex
54421 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54423 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54424 if(this.cm.isHidden(colIndex)){
54425 return; // can't calc a hidden column
54428 var cid = this.cm.getColumnId(colIndex);
54429 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54430 if(this.grid.autoSizeHeaders){
54431 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54434 var newWidth = this.calcColumnWidth(colIndex);
54435 this.cm.setColumnWidth(colIndex,
54436 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54437 if(!suppressEvent){
54438 this.grid.fireEvent("columnresize", colIndex, newWidth);
54443 * Autofits all columns to their content and then expands to fit any extra space in the grid
54445 autoSizeColumns : function(){
54446 var cm = this.grid.colModel;
54447 var colCount = cm.getColumnCount();
54448 for(var i = 0; i < colCount; i++){
54449 this.autoSizeColumn(i, true, true);
54451 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54454 this.updateColumns();
54460 * Autofits all columns to the grid's width proportionate with their current size
54461 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54463 fitColumns : function(reserveScrollSpace){
54464 var cm = this.grid.colModel;
54465 var colCount = cm.getColumnCount();
54469 for (i = 0; i < colCount; i++){
54470 if(!cm.isHidden(i) && !cm.isFixed(i)){
54471 w = cm.getColumnWidth(i);
54477 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54478 if(reserveScrollSpace){
54481 var frac = (avail - cm.getTotalWidth())/width;
54482 while (cols.length){
54485 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54487 this.updateColumns();
54491 onRowSelect : function(rowIndex){
54492 var row = this.getRowComposite(rowIndex);
54493 row.addClass("x-grid-row-selected");
54496 onRowDeselect : function(rowIndex){
54497 var row = this.getRowComposite(rowIndex);
54498 row.removeClass("x-grid-row-selected");
54501 onCellSelect : function(row, col){
54502 var cell = this.getCell(row, col);
54504 Roo.fly(cell).addClass("x-grid-cell-selected");
54508 onCellDeselect : function(row, col){
54509 var cell = this.getCell(row, col);
54511 Roo.fly(cell).removeClass("x-grid-cell-selected");
54515 updateHeaderSortState : function(){
54517 // sort state can be single { field: xxx, direction : yyy}
54518 // or { xxx=>ASC , yyy : DESC ..... }
54521 if (!this.ds.multiSort) {
54522 var state = this.ds.getSortState();
54526 mstate[state.field] = state.direction;
54527 // FIXME... - this is not used here.. but might be elsewhere..
54528 this.sortState = state;
54531 mstate = this.ds.sortToggle;
54533 //remove existing sort classes..
54535 var sc = this.sortClasses;
54536 var hds = this.el.select(this.headerSelector).removeClass(sc);
54538 for(var f in mstate) {
54540 var sortColumn = this.cm.findColumnIndex(f);
54542 if(sortColumn != -1){
54543 var sortDir = mstate[f];
54544 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54553 handleHeaderClick : function(g, index,e){
54555 Roo.log("header click");
54558 // touch events on header are handled by context
54559 this.handleHdCtx(g,index,e);
54564 if(this.headersDisabled){
54567 var dm = g.dataSource, cm = g.colModel;
54568 if(!cm.isSortable(index)){
54573 if (dm.multiSort) {
54574 // update the sortOrder
54576 for(var i = 0; i < cm.config.length; i++ ) {
54578 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54579 continue; // dont' bother, it's not in sort list or being set.
54582 so.push(cm.config[i].dataIndex);
54588 dm.sort(cm.getDataIndex(index));
54592 destroy : function(){
54594 this.colMenu.removeAll();
54595 Roo.menu.MenuMgr.unregister(this.colMenu);
54596 this.colMenu.getEl().remove();
54597 delete this.colMenu;
54600 this.hmenu.removeAll();
54601 Roo.menu.MenuMgr.unregister(this.hmenu);
54602 this.hmenu.getEl().remove();
54605 if(this.grid.enableColumnMove){
54606 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54608 for(var dd in dds){
54609 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54610 var elid = dds[dd].dragElId;
54612 Roo.get(elid).remove();
54613 } else if(dds[dd].config.isTarget){
54614 dds[dd].proxyTop.remove();
54615 dds[dd].proxyBottom.remove();
54618 if(Roo.dd.DDM.locationCache[dd]){
54619 delete Roo.dd.DDM.locationCache[dd];
54622 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54625 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54626 this.bind(null, null);
54627 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54630 handleLockChange : function(){
54631 this.refresh(true);
54634 onDenyColumnLock : function(){
54638 onDenyColumnHide : function(){
54642 handleHdMenuClick : function(item){
54643 var index = this.hdCtxIndex;
54644 var cm = this.cm, ds = this.ds;
54647 ds.sort(cm.getDataIndex(index), "ASC");
54650 ds.sort(cm.getDataIndex(index), "DESC");
54653 var lc = cm.getLockedCount();
54654 if(cm.getColumnCount(true) <= lc+1){
54655 this.onDenyColumnLock();
54659 cm.setLocked(index, true, true);
54660 cm.moveColumn(index, lc);
54661 this.grid.fireEvent("columnmove", index, lc);
54663 cm.setLocked(index, true);
54667 var lc = cm.getLockedCount();
54668 if((lc-1) != index){
54669 cm.setLocked(index, false, true);
54670 cm.moveColumn(index, lc-1);
54671 this.grid.fireEvent("columnmove", index, lc-1);
54673 cm.setLocked(index, false);
54676 case 'wider': // used to expand cols on touch..
54678 var cw = cm.getColumnWidth(index);
54679 cw += (item.id == 'wider' ? 1 : -1) * 50;
54680 cw = Math.max(0, cw);
54681 cw = Math.min(cw,4000);
54682 cm.setColumnWidth(index, cw);
54686 index = cm.getIndexById(item.id.substr(4));
54688 if(item.checked && cm.getColumnCount(true) <= 1){
54689 this.onDenyColumnHide();
54692 cm.setHidden(index, item.checked);
54698 beforeColMenuShow : function(){
54699 var cm = this.cm, colCount = cm.getColumnCount();
54700 this.colMenu.removeAll();
54701 for(var i = 0; i < colCount; i++){
54702 this.colMenu.add(new Roo.menu.CheckItem({
54703 id: "col-"+cm.getColumnId(i),
54704 text: cm.getColumnHeader(i),
54705 checked: !cm.isHidden(i),
54711 handleHdCtx : function(g, index, e){
54713 var hd = this.getHeaderCell(index);
54714 this.hdCtxIndex = index;
54715 var ms = this.hmenu.items, cm = this.cm;
54716 ms.get("asc").setDisabled(!cm.isSortable(index));
54717 ms.get("desc").setDisabled(!cm.isSortable(index));
54718 if(this.grid.enableColLock !== false){
54719 ms.get("lock").setDisabled(cm.isLocked(index));
54720 ms.get("unlock").setDisabled(!cm.isLocked(index));
54722 this.hmenu.show(hd, "tl-bl");
54725 handleHdOver : function(e){
54726 var hd = this.findHeaderCell(e.getTarget());
54727 if(hd && !this.headersDisabled){
54728 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54729 this.fly(hd).addClass("x-grid-hd-over");
54734 handleHdOut : function(e){
54735 var hd = this.findHeaderCell(e.getTarget());
54737 this.fly(hd).removeClass("x-grid-hd-over");
54741 handleSplitDblClick : function(e, t){
54742 var i = this.getCellIndex(t);
54743 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54744 this.autoSizeColumn(i, true);
54749 render : function(){
54752 var colCount = cm.getColumnCount();
54754 if(this.grid.monitorWindowResize === true){
54755 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54757 var header = this.renderHeaders();
54758 var body = this.templates.body.apply({rows:""});
54759 var html = this.templates.master.apply({
54762 lockedHeader: header[0],
54766 //this.updateColumns();
54768 this.grid.getGridEl().dom.innerHTML = html;
54770 this.initElements();
54772 // a kludge to fix the random scolling effect in webkit
54773 this.el.on("scroll", function() {
54774 this.el.dom.scrollTop=0; // hopefully not recursive..
54777 this.scroller.on("scroll", this.handleScroll, this);
54778 this.lockedBody.on("mousewheel", this.handleWheel, this);
54779 this.mainBody.on("mousewheel", this.handleWheel, this);
54781 this.mainHd.on("mouseover", this.handleHdOver, this);
54782 this.mainHd.on("mouseout", this.handleHdOut, this);
54783 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54784 {delegate: "."+this.splitClass});
54786 this.lockedHd.on("mouseover", this.handleHdOver, this);
54787 this.lockedHd.on("mouseout", this.handleHdOut, this);
54788 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54789 {delegate: "."+this.splitClass});
54791 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54792 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54795 this.updateSplitters();
54797 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54798 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54799 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54802 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54803 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54805 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54806 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54808 if(this.grid.enableColLock !== false){
54809 this.hmenu.add('-',
54810 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54811 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54815 this.hmenu.add('-',
54816 {id:"wider", text: this.columnsWiderText},
54817 {id:"narrow", text: this.columnsNarrowText }
54823 if(this.grid.enableColumnHide !== false){
54825 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54826 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54827 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54829 this.hmenu.add('-',
54830 {id:"columns", text: this.columnsText, menu: this.colMenu}
54833 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54835 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54838 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54839 this.dd = new Roo.grid.GridDragZone(this.grid, {
54840 ddGroup : this.grid.ddGroup || 'GridDD'
54846 for(var i = 0; i < colCount; i++){
54847 if(cm.isHidden(i)){
54848 this.hideColumn(i);
54850 if(cm.config[i].align){
54851 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54852 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54856 this.updateHeaderSortState();
54858 this.beforeInitialResize();
54861 // two part rendering gives faster view to the user
54862 this.renderPhase2.defer(1, this);
54865 renderPhase2 : function(){
54866 // render the rows now
54868 if(this.grid.autoSizeColumns){
54869 this.autoSizeColumns();
54873 beforeInitialResize : function(){
54877 onColumnSplitterMoved : function(i, w){
54878 this.userResized = true;
54879 var cm = this.grid.colModel;
54880 cm.setColumnWidth(i, w, true);
54881 var cid = cm.getColumnId(i);
54882 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54883 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54884 this.updateSplitters();
54886 this.grid.fireEvent("columnresize", i, w);
54889 syncRowHeights : function(startIndex, endIndex){
54890 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54891 startIndex = startIndex || 0;
54892 var mrows = this.getBodyTable().rows;
54893 var lrows = this.getLockedTable().rows;
54894 var len = mrows.length-1;
54895 endIndex = Math.min(endIndex || len, len);
54896 for(var i = startIndex; i <= endIndex; i++){
54897 var m = mrows[i], l = lrows[i];
54898 var h = Math.max(m.offsetHeight, l.offsetHeight);
54899 m.style.height = l.style.height = h + "px";
54904 layout : function(initialRender, is2ndPass){
54906 var auto = g.autoHeight;
54907 var scrollOffset = 16;
54908 var c = g.getGridEl(), cm = this.cm,
54909 expandCol = g.autoExpandColumn,
54911 //c.beginMeasure();
54913 if(!c.dom.offsetWidth){ // display:none?
54915 this.lockedWrap.show();
54916 this.mainWrap.show();
54921 var hasLock = this.cm.isLocked(0);
54923 var tbh = this.headerPanel.getHeight();
54924 var bbh = this.footerPanel.getHeight();
54927 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54928 var newHeight = ch + c.getBorderWidth("tb");
54930 newHeight = Math.min(g.maxHeight, newHeight);
54932 c.setHeight(newHeight);
54936 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54939 var s = this.scroller;
54941 var csize = c.getSize(true);
54943 this.el.setSize(csize.width, csize.height);
54945 this.headerPanel.setWidth(csize.width);
54946 this.footerPanel.setWidth(csize.width);
54948 var hdHeight = this.mainHd.getHeight();
54949 var vw = csize.width;
54950 var vh = csize.height - (tbh + bbh);
54954 var bt = this.getBodyTable();
54955 var ltWidth = hasLock ?
54956 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54958 var scrollHeight = bt.offsetHeight;
54959 var scrollWidth = ltWidth + bt.offsetWidth;
54960 var vscroll = false, hscroll = false;
54962 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54964 var lw = this.lockedWrap, mw = this.mainWrap;
54965 var lb = this.lockedBody, mb = this.mainBody;
54967 setTimeout(function(){
54968 var t = s.dom.offsetTop;
54969 var w = s.dom.clientWidth,
54970 h = s.dom.clientHeight;
54973 lw.setSize(ltWidth, h);
54975 mw.setLeftTop(ltWidth, t);
54976 mw.setSize(w-ltWidth, h);
54978 lb.setHeight(h-hdHeight);
54979 mb.setHeight(h-hdHeight);
54981 if(is2ndPass !== true && !gv.userResized && expandCol){
54982 // high speed resize without full column calculation
54984 var ci = cm.getIndexById(expandCol);
54986 ci = cm.findColumnIndex(expandCol);
54988 ci = Math.max(0, ci); // make sure it's got at least the first col.
54989 var expandId = cm.getColumnId(ci);
54990 var tw = cm.getTotalWidth(false);
54991 var currentWidth = cm.getColumnWidth(ci);
54992 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54993 if(currentWidth != cw){
54994 cm.setColumnWidth(ci, cw, true);
54995 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54996 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54997 gv.updateSplitters();
54998 gv.layout(false, true);
55010 onWindowResize : function(){
55011 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55017 appendFooter : function(parentEl){
55021 sortAscText : "Sort Ascending",
55022 sortDescText : "Sort Descending",
55023 lockText : "Lock Column",
55024 unlockText : "Unlock Column",
55025 columnsText : "Columns",
55027 columnsWiderText : "Wider",
55028 columnsNarrowText : "Thinner"
55032 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55033 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55034 this.proxy.el.addClass('x-grid3-col-dd');
55037 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55038 handleMouseDown : function(e){
55042 callHandleMouseDown : function(e){
55043 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55048 * Ext JS Library 1.1.1
55049 * Copyright(c) 2006-2007, Ext JS, LLC.
55051 * Originally Released Under LGPL - original licence link has changed is not relivant.
55054 * <script type="text/javascript">
55058 // This is a support class used internally by the Grid components
55059 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55061 this.view = grid.getView();
55062 this.proxy = this.view.resizeProxy;
55063 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55064 "gridSplitters" + this.grid.getGridEl().id, {
55065 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55067 this.setHandleElId(Roo.id(hd));
55068 this.setOuterHandleElId(Roo.id(hd2));
55069 this.scroll = false;
55071 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55072 fly: Roo.Element.fly,
55074 b4StartDrag : function(x, y){
55075 this.view.headersDisabled = true;
55076 this.proxy.setHeight(this.view.mainWrap.getHeight());
55077 var w = this.cm.getColumnWidth(this.cellIndex);
55078 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55079 this.resetConstraints();
55080 this.setXConstraint(minw, 1000);
55081 this.setYConstraint(0, 0);
55082 this.minX = x - minw;
55083 this.maxX = x + 1000;
55085 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55089 handleMouseDown : function(e){
55090 ev = Roo.EventObject.setEvent(e);
55091 var t = this.fly(ev.getTarget());
55092 if(t.hasClass("x-grid-split")){
55093 this.cellIndex = this.view.getCellIndex(t.dom);
55094 this.split = t.dom;
55095 this.cm = this.grid.colModel;
55096 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55097 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55102 endDrag : function(e){
55103 this.view.headersDisabled = false;
55104 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55105 var diff = endX - this.startPos;
55106 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55109 autoOffset : function(){
55110 this.setDelta(0,0);
55114 * Ext JS Library 1.1.1
55115 * Copyright(c) 2006-2007, Ext JS, LLC.
55117 * Originally Released Under LGPL - original licence link has changed is not relivant.
55120 * <script type="text/javascript">
55124 // This is a support class used internally by the Grid components
55125 Roo.grid.GridDragZone = function(grid, config){
55126 this.view = grid.getView();
55127 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55128 if(this.view.lockedBody){
55129 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55130 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55132 this.scroll = false;
55134 this.ddel = document.createElement('div');
55135 this.ddel.className = 'x-grid-dd-wrap';
55138 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55139 ddGroup : "GridDD",
55141 getDragData : function(e){
55142 var t = Roo.lib.Event.getTarget(e);
55143 var rowIndex = this.view.findRowIndex(t);
55144 var sm = this.grid.selModel;
55146 //Roo.log(rowIndex);
55148 if (sm.getSelectedCell) {
55149 // cell selection..
55150 if (!sm.getSelectedCell()) {
55153 if (rowIndex != sm.getSelectedCell()[0]) {
55159 if(rowIndex !== false){
55164 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55166 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55169 if (e.hasModifier()){
55170 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55173 Roo.log("getDragData");
55178 rowIndex: rowIndex,
55179 selections:sm.getSelections ? sm.getSelections() : (
55180 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55187 onInitDrag : function(e){
55188 var data = this.dragData;
55189 this.ddel.innerHTML = this.grid.getDragDropText();
55190 this.proxy.update(this.ddel);
55191 // fire start drag?
55194 afterRepair : function(){
55195 this.dragging = false;
55198 getRepairXY : function(e, data){
55202 onEndDrag : function(data, e){
55206 onValidDrop : function(dd, e, id){
55211 beforeInvalidDrop : function(e, id){
55216 * Ext JS Library 1.1.1
55217 * Copyright(c) 2006-2007, Ext JS, LLC.
55219 * Originally Released Under LGPL - original licence link has changed is not relivant.
55222 * <script type="text/javascript">
55227 * @class Roo.grid.ColumnModel
55228 * @extends Roo.util.Observable
55229 * This is the default implementation of a ColumnModel used by the Grid. It defines
55230 * the columns in the grid.
55233 var colModel = new Roo.grid.ColumnModel([
55234 {header: "Ticker", width: 60, sortable: true, locked: true},
55235 {header: "Company Name", width: 150, sortable: true},
55236 {header: "Market Cap.", width: 100, sortable: true},
55237 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55238 {header: "Employees", width: 100, sortable: true, resizable: false}
55243 * The config options listed for this class are options which may appear in each
55244 * individual column definition.
55245 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55247 * @param {Object} config An Array of column config objects. See this class's
55248 * config objects for details.
55250 Roo.grid.ColumnModel = function(config){
55252 * The config passed into the constructor
55254 this.config = config;
55257 // if no id, create one
55258 // if the column does not have a dataIndex mapping,
55259 // map it to the order it is in the config
55260 for(var i = 0, len = config.length; i < len; i++){
55262 if(typeof c.dataIndex == "undefined"){
55265 if(typeof c.renderer == "string"){
55266 c.renderer = Roo.util.Format[c.renderer];
55268 if(typeof c.id == "undefined"){
55271 if(c.editor && c.editor.xtype){
55272 c.editor = Roo.factory(c.editor, Roo.grid);
55274 if(c.editor && c.editor.isFormField){
55275 c.editor = new Roo.grid.GridEditor(c.editor);
55277 this.lookup[c.id] = c;
55281 * The width of columns which have no width specified (defaults to 100)
55284 this.defaultWidth = 100;
55287 * Default sortable of columns which have no sortable specified (defaults to false)
55290 this.defaultSortable = false;
55294 * @event widthchange
55295 * Fires when the width of a column changes.
55296 * @param {ColumnModel} this
55297 * @param {Number} columnIndex The column index
55298 * @param {Number} newWidth The new width
55300 "widthchange": true,
55302 * @event headerchange
55303 * Fires when the text of a header changes.
55304 * @param {ColumnModel} this
55305 * @param {Number} columnIndex The column index
55306 * @param {Number} newText The new header text
55308 "headerchange": true,
55310 * @event hiddenchange
55311 * Fires when a column is hidden or "unhidden".
55312 * @param {ColumnModel} this
55313 * @param {Number} columnIndex The column index
55314 * @param {Boolean} hidden true if hidden, false otherwise
55316 "hiddenchange": true,
55318 * @event columnmoved
55319 * Fires when a column is moved.
55320 * @param {ColumnModel} this
55321 * @param {Number} oldIndex
55322 * @param {Number} newIndex
55324 "columnmoved" : true,
55326 * @event columlockchange
55327 * Fires when a column's locked state is changed
55328 * @param {ColumnModel} this
55329 * @param {Number} colIndex
55330 * @param {Boolean} locked true if locked
55332 "columnlockchange" : true
55334 Roo.grid.ColumnModel.superclass.constructor.call(this);
55336 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55338 * @cfg {String} header The header text to display in the Grid view.
55341 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55342 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55343 * specified, the column's index is used as an index into the Record's data Array.
55346 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55347 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55350 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55351 * Defaults to the value of the {@link #defaultSortable} property.
55352 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55355 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55358 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55361 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55364 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55367 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55368 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55369 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55370 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55373 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55376 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55379 * @cfg {String} cursor (Optional)
55382 * @cfg {String} tooltip (Optional)
55385 * Returns the id of the column at the specified index.
55386 * @param {Number} index The column index
55387 * @return {String} the id
55389 getColumnId : function(index){
55390 return this.config[index].id;
55394 * Returns the column for a specified id.
55395 * @param {String} id The column id
55396 * @return {Object} the column
55398 getColumnById : function(id){
55399 return this.lookup[id];
55404 * Returns the column for a specified dataIndex.
55405 * @param {String} dataIndex The column dataIndex
55406 * @return {Object|Boolean} the column or false if not found
55408 getColumnByDataIndex: function(dataIndex){
55409 var index = this.findColumnIndex(dataIndex);
55410 return index > -1 ? this.config[index] : false;
55414 * Returns the index for a specified column id.
55415 * @param {String} id The column id
55416 * @return {Number} the index, or -1 if not found
55418 getIndexById : function(id){
55419 for(var i = 0, len = this.config.length; i < len; i++){
55420 if(this.config[i].id == id){
55428 * Returns the index for a specified column dataIndex.
55429 * @param {String} dataIndex The column dataIndex
55430 * @return {Number} the index, or -1 if not found
55433 findColumnIndex : function(dataIndex){
55434 for(var i = 0, len = this.config.length; i < len; i++){
55435 if(this.config[i].dataIndex == dataIndex){
55443 moveColumn : function(oldIndex, newIndex){
55444 var c = this.config[oldIndex];
55445 this.config.splice(oldIndex, 1);
55446 this.config.splice(newIndex, 0, c);
55447 this.dataMap = null;
55448 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55451 isLocked : function(colIndex){
55452 return this.config[colIndex].locked === true;
55455 setLocked : function(colIndex, value, suppressEvent){
55456 if(this.isLocked(colIndex) == value){
55459 this.config[colIndex].locked = value;
55460 if(!suppressEvent){
55461 this.fireEvent("columnlockchange", this, colIndex, value);
55465 getTotalLockedWidth : function(){
55466 var totalWidth = 0;
55467 for(var i = 0; i < this.config.length; i++){
55468 if(this.isLocked(i) && !this.isHidden(i)){
55469 this.totalWidth += this.getColumnWidth(i);
55475 getLockedCount : function(){
55476 for(var i = 0, len = this.config.length; i < len; i++){
55477 if(!this.isLocked(i)){
55484 * Returns the number of columns.
55487 getColumnCount : function(visibleOnly){
55488 if(visibleOnly === true){
55490 for(var i = 0, len = this.config.length; i < len; i++){
55491 if(!this.isHidden(i)){
55497 return this.config.length;
55501 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55502 * @param {Function} fn
55503 * @param {Object} scope (optional)
55504 * @return {Array} result
55506 getColumnsBy : function(fn, scope){
55508 for(var i = 0, len = this.config.length; i < len; i++){
55509 var c = this.config[i];
55510 if(fn.call(scope||this, c, i) === true){
55518 * Returns true if the specified column is sortable.
55519 * @param {Number} col The column index
55520 * @return {Boolean}
55522 isSortable : function(col){
55523 if(typeof this.config[col].sortable == "undefined"){
55524 return this.defaultSortable;
55526 return this.config[col].sortable;
55530 * Returns the rendering (formatting) function defined for the column.
55531 * @param {Number} col The column index.
55532 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55534 getRenderer : function(col){
55535 if(!this.config[col].renderer){
55536 return Roo.grid.ColumnModel.defaultRenderer;
55538 return this.config[col].renderer;
55542 * Sets the rendering (formatting) function for a column.
55543 * @param {Number} col The column index
55544 * @param {Function} fn The function to use to process the cell's raw data
55545 * to return HTML markup for the grid view. The render function is called with
55546 * the following parameters:<ul>
55547 * <li>Data value.</li>
55548 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55549 * <li>css A CSS style string to apply to the table cell.</li>
55550 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55551 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55552 * <li>Row index</li>
55553 * <li>Column index</li>
55554 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55556 setRenderer : function(col, fn){
55557 this.config[col].renderer = fn;
55561 * Returns the width for the specified column.
55562 * @param {Number} col The column index
55565 getColumnWidth : function(col){
55566 return this.config[col].width * 1 || this.defaultWidth;
55570 * Sets the width for a column.
55571 * @param {Number} col The column index
55572 * @param {Number} width The new width
55574 setColumnWidth : function(col, width, suppressEvent){
55575 this.config[col].width = width;
55576 this.totalWidth = null;
55577 if(!suppressEvent){
55578 this.fireEvent("widthchange", this, col, width);
55583 * Returns the total width of all columns.
55584 * @param {Boolean} includeHidden True to include hidden column widths
55587 getTotalWidth : function(includeHidden){
55588 if(!this.totalWidth){
55589 this.totalWidth = 0;
55590 for(var i = 0, len = this.config.length; i < len; i++){
55591 if(includeHidden || !this.isHidden(i)){
55592 this.totalWidth += this.getColumnWidth(i);
55596 return this.totalWidth;
55600 * Returns the header for the specified column.
55601 * @param {Number} col The column index
55604 getColumnHeader : function(col){
55605 return this.config[col].header;
55609 * Sets the header for a column.
55610 * @param {Number} col The column index
55611 * @param {String} header The new header
55613 setColumnHeader : function(col, header){
55614 this.config[col].header = header;
55615 this.fireEvent("headerchange", this, col, header);
55619 * Returns the tooltip for the specified column.
55620 * @param {Number} col The column index
55623 getColumnTooltip : function(col){
55624 return this.config[col].tooltip;
55627 * Sets the tooltip for a column.
55628 * @param {Number} col The column index
55629 * @param {String} tooltip The new tooltip
55631 setColumnTooltip : function(col, tooltip){
55632 this.config[col].tooltip = tooltip;
55636 * Returns the dataIndex for the specified column.
55637 * @param {Number} col The column index
55640 getDataIndex : function(col){
55641 return this.config[col].dataIndex;
55645 * Sets the dataIndex for a column.
55646 * @param {Number} col The column index
55647 * @param {Number} dataIndex The new dataIndex
55649 setDataIndex : function(col, dataIndex){
55650 this.config[col].dataIndex = dataIndex;
55656 * Returns true if the cell is editable.
55657 * @param {Number} colIndex The column index
55658 * @param {Number} rowIndex The row index
55659 * @return {Boolean}
55661 isCellEditable : function(colIndex, rowIndex){
55662 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55666 * Returns the editor defined for the cell/column.
55667 * return false or null to disable editing.
55668 * @param {Number} colIndex The column index
55669 * @param {Number} rowIndex The row index
55672 getCellEditor : function(colIndex, rowIndex){
55673 return this.config[colIndex].editor;
55677 * Sets if a column is editable.
55678 * @param {Number} col The column index
55679 * @param {Boolean} editable True if the column is editable
55681 setEditable : function(col, editable){
55682 this.config[col].editable = editable;
55687 * Returns true if the column is hidden.
55688 * @param {Number} colIndex The column index
55689 * @return {Boolean}
55691 isHidden : function(colIndex){
55692 return this.config[colIndex].hidden;
55697 * Returns true if the column width cannot be changed
55699 isFixed : function(colIndex){
55700 return this.config[colIndex].fixed;
55704 * Returns true if the column can be resized
55705 * @return {Boolean}
55707 isResizable : function(colIndex){
55708 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55711 * Sets if a column is hidden.
55712 * @param {Number} colIndex The column index
55713 * @param {Boolean} hidden True if the column is hidden
55715 setHidden : function(colIndex, hidden){
55716 this.config[colIndex].hidden = hidden;
55717 this.totalWidth = null;
55718 this.fireEvent("hiddenchange", this, colIndex, hidden);
55722 * Sets the editor for a column.
55723 * @param {Number} col The column index
55724 * @param {Object} editor The editor object
55726 setEditor : function(col, editor){
55727 this.config[col].editor = editor;
55731 Roo.grid.ColumnModel.defaultRenderer = function(value){
55732 if(typeof value == "string" && value.length < 1){
55738 // Alias for backwards compatibility
55739 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55742 * Ext JS Library 1.1.1
55743 * Copyright(c) 2006-2007, Ext JS, LLC.
55745 * Originally Released Under LGPL - original licence link has changed is not relivant.
55748 * <script type="text/javascript">
55752 * @class Roo.grid.AbstractSelectionModel
55753 * @extends Roo.util.Observable
55754 * Abstract base class for grid SelectionModels. It provides the interface that should be
55755 * implemented by descendant classes. This class should not be directly instantiated.
55758 Roo.grid.AbstractSelectionModel = function(){
55759 this.locked = false;
55760 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55763 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55764 /** @ignore Called by the grid automatically. Do not call directly. */
55765 init : function(grid){
55771 * Locks the selections.
55774 this.locked = true;
55778 * Unlocks the selections.
55780 unlock : function(){
55781 this.locked = false;
55785 * Returns true if the selections are locked.
55786 * @return {Boolean}
55788 isLocked : function(){
55789 return this.locked;
55793 * Ext JS Library 1.1.1
55794 * Copyright(c) 2006-2007, Ext JS, LLC.
55796 * Originally Released Under LGPL - original licence link has changed is not relivant.
55799 * <script type="text/javascript">
55802 * @extends Roo.grid.AbstractSelectionModel
55803 * @class Roo.grid.RowSelectionModel
55804 * The default SelectionModel used by {@link Roo.grid.Grid}.
55805 * It supports multiple selections and keyboard selection/navigation.
55807 * @param {Object} config
55809 Roo.grid.RowSelectionModel = function(config){
55810 Roo.apply(this, config);
55811 this.selections = new Roo.util.MixedCollection(false, function(o){
55816 this.lastActive = false;
55820 * @event selectionchange
55821 * Fires when the selection changes
55822 * @param {SelectionModel} this
55824 "selectionchange" : true,
55826 * @event afterselectionchange
55827 * Fires after the selection changes (eg. by key press or clicking)
55828 * @param {SelectionModel} this
55830 "afterselectionchange" : true,
55832 * @event beforerowselect
55833 * Fires when a row is selected being selected, return false to cancel.
55834 * @param {SelectionModel} this
55835 * @param {Number} rowIndex The selected index
55836 * @param {Boolean} keepExisting False if other selections will be cleared
55838 "beforerowselect" : true,
55841 * Fires when a row is selected.
55842 * @param {SelectionModel} this
55843 * @param {Number} rowIndex The selected index
55844 * @param {Roo.data.Record} r The record
55846 "rowselect" : true,
55848 * @event rowdeselect
55849 * Fires when a row is deselected.
55850 * @param {SelectionModel} this
55851 * @param {Number} rowIndex The selected index
55853 "rowdeselect" : true
55855 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55856 this.locked = false;
55859 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55861 * @cfg {Boolean} singleSelect
55862 * True to allow selection of only one row at a time (defaults to false)
55864 singleSelect : false,
55867 initEvents : function(){
55869 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55870 this.grid.on("mousedown", this.handleMouseDown, this);
55871 }else{ // allow click to work like normal
55872 this.grid.on("rowclick", this.handleDragableRowClick, this);
55875 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55876 "up" : function(e){
55878 this.selectPrevious(e.shiftKey);
55879 }else if(this.last !== false && this.lastActive !== false){
55880 var last = this.last;
55881 this.selectRange(this.last, this.lastActive-1);
55882 this.grid.getView().focusRow(this.lastActive);
55883 if(last !== false){
55887 this.selectFirstRow();
55889 this.fireEvent("afterselectionchange", this);
55891 "down" : function(e){
55893 this.selectNext(e.shiftKey);
55894 }else if(this.last !== false && this.lastActive !== false){
55895 var last = this.last;
55896 this.selectRange(this.last, this.lastActive+1);
55897 this.grid.getView().focusRow(this.lastActive);
55898 if(last !== false){
55902 this.selectFirstRow();
55904 this.fireEvent("afterselectionchange", this);
55909 var view = this.grid.view;
55910 view.on("refresh", this.onRefresh, this);
55911 view.on("rowupdated", this.onRowUpdated, this);
55912 view.on("rowremoved", this.onRemove, this);
55916 onRefresh : function(){
55917 var ds = this.grid.dataSource, i, v = this.grid.view;
55918 var s = this.selections;
55919 s.each(function(r){
55920 if((i = ds.indexOfId(r.id)) != -1){
55929 onRemove : function(v, index, r){
55930 this.selections.remove(r);
55934 onRowUpdated : function(v, index, r){
55935 if(this.isSelected(r)){
55936 v.onRowSelect(index);
55942 * @param {Array} records The records to select
55943 * @param {Boolean} keepExisting (optional) True to keep existing selections
55945 selectRecords : function(records, keepExisting){
55947 this.clearSelections();
55949 var ds = this.grid.dataSource;
55950 for(var i = 0, len = records.length; i < len; i++){
55951 this.selectRow(ds.indexOf(records[i]), true);
55956 * Gets the number of selected rows.
55959 getCount : function(){
55960 return this.selections.length;
55964 * Selects the first row in the grid.
55966 selectFirstRow : function(){
55971 * Select the last row.
55972 * @param {Boolean} keepExisting (optional) True to keep existing selections
55974 selectLastRow : function(keepExisting){
55975 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55979 * Selects the row immediately following the last selected row.
55980 * @param {Boolean} keepExisting (optional) True to keep existing selections
55982 selectNext : function(keepExisting){
55983 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55984 this.selectRow(this.last+1, keepExisting);
55985 this.grid.getView().focusRow(this.last);
55990 * Selects the row that precedes the last selected row.
55991 * @param {Boolean} keepExisting (optional) True to keep existing selections
55993 selectPrevious : function(keepExisting){
55995 this.selectRow(this.last-1, keepExisting);
55996 this.grid.getView().focusRow(this.last);
56001 * Returns the selected records
56002 * @return {Array} Array of selected records
56004 getSelections : function(){
56005 return [].concat(this.selections.items);
56009 * Returns the first selected record.
56012 getSelected : function(){
56013 return this.selections.itemAt(0);
56018 * Clears all selections.
56020 clearSelections : function(fast){
56021 if(this.locked) return;
56023 var ds = this.grid.dataSource;
56024 var s = this.selections;
56025 s.each(function(r){
56026 this.deselectRow(ds.indexOfId(r.id));
56030 this.selections.clear();
56037 * Selects all rows.
56039 selectAll : function(){
56040 if(this.locked) return;
56041 this.selections.clear();
56042 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56043 this.selectRow(i, true);
56048 * Returns True if there is a selection.
56049 * @return {Boolean}
56051 hasSelection : function(){
56052 return this.selections.length > 0;
56056 * Returns True if the specified row is selected.
56057 * @param {Number/Record} record The record or index of the record to check
56058 * @return {Boolean}
56060 isSelected : function(index){
56061 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56062 return (r && this.selections.key(r.id) ? true : false);
56066 * Returns True if the specified record id is selected.
56067 * @param {String} id The id of record to check
56068 * @return {Boolean}
56070 isIdSelected : function(id){
56071 return (this.selections.key(id) ? true : false);
56075 handleMouseDown : function(e, t){
56076 var view = this.grid.getView(), rowIndex;
56077 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56080 if(e.shiftKey && this.last !== false){
56081 var last = this.last;
56082 this.selectRange(last, rowIndex, e.ctrlKey);
56083 this.last = last; // reset the last
56084 view.focusRow(rowIndex);
56086 var isSelected = this.isSelected(rowIndex);
56087 if(e.button !== 0 && isSelected){
56088 view.focusRow(rowIndex);
56089 }else if(e.ctrlKey && isSelected){
56090 this.deselectRow(rowIndex);
56091 }else if(!isSelected){
56092 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56093 view.focusRow(rowIndex);
56096 this.fireEvent("afterselectionchange", this);
56099 handleDragableRowClick : function(grid, rowIndex, e)
56101 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56102 this.selectRow(rowIndex, false);
56103 grid.view.focusRow(rowIndex);
56104 this.fireEvent("afterselectionchange", this);
56109 * Selects multiple rows.
56110 * @param {Array} rows Array of the indexes of the row to select
56111 * @param {Boolean} keepExisting (optional) True to keep existing selections
56113 selectRows : function(rows, keepExisting){
56115 this.clearSelections();
56117 for(var i = 0, len = rows.length; i < len; i++){
56118 this.selectRow(rows[i], true);
56123 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56124 * @param {Number} startRow The index of the first row in the range
56125 * @param {Number} endRow The index of the last row in the range
56126 * @param {Boolean} keepExisting (optional) True to retain existing selections
56128 selectRange : function(startRow, endRow, keepExisting){
56129 if(this.locked) return;
56131 this.clearSelections();
56133 if(startRow <= endRow){
56134 for(var i = startRow; i <= endRow; i++){
56135 this.selectRow(i, true);
56138 for(var i = startRow; i >= endRow; i--){
56139 this.selectRow(i, true);
56145 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56146 * @param {Number} startRow The index of the first row in the range
56147 * @param {Number} endRow The index of the last row in the range
56149 deselectRange : function(startRow, endRow, preventViewNotify){
56150 if(this.locked) return;
56151 for(var i = startRow; i <= endRow; i++){
56152 this.deselectRow(i, preventViewNotify);
56158 * @param {Number} row The index of the row to select
56159 * @param {Boolean} keepExisting (optional) True to keep existing selections
56161 selectRow : function(index, keepExisting, preventViewNotify){
56162 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56163 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56164 if(!keepExisting || this.singleSelect){
56165 this.clearSelections();
56167 var r = this.grid.dataSource.getAt(index);
56168 this.selections.add(r);
56169 this.last = this.lastActive = index;
56170 if(!preventViewNotify){
56171 this.grid.getView().onRowSelect(index);
56173 this.fireEvent("rowselect", this, index, r);
56174 this.fireEvent("selectionchange", this);
56180 * @param {Number} row The index of the row to deselect
56182 deselectRow : function(index, preventViewNotify){
56183 if(this.locked) return;
56184 if(this.last == index){
56187 if(this.lastActive == index){
56188 this.lastActive = false;
56190 var r = this.grid.dataSource.getAt(index);
56191 this.selections.remove(r);
56192 if(!preventViewNotify){
56193 this.grid.getView().onRowDeselect(index);
56195 this.fireEvent("rowdeselect", this, index);
56196 this.fireEvent("selectionchange", this);
56200 restoreLast : function(){
56202 this.last = this._last;
56207 acceptsNav : function(row, col, cm){
56208 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56212 onEditorKey : function(field, e){
56213 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56218 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56220 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56222 }else if(k == e.ENTER && !e.ctrlKey){
56226 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56228 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56230 }else if(k == e.ESC){
56234 g.startEditing(newCell[0], newCell[1]);
56239 * Ext JS Library 1.1.1
56240 * Copyright(c) 2006-2007, Ext JS, LLC.
56242 * Originally Released Under LGPL - original licence link has changed is not relivant.
56245 * <script type="text/javascript">
56248 * @class Roo.grid.CellSelectionModel
56249 * @extends Roo.grid.AbstractSelectionModel
56250 * This class provides the basic implementation for cell selection in a grid.
56252 * @param {Object} config The object containing the configuration of this model.
56253 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56255 Roo.grid.CellSelectionModel = function(config){
56256 Roo.apply(this, config);
56258 this.selection = null;
56262 * @event beforerowselect
56263 * Fires before a cell is selected.
56264 * @param {SelectionModel} this
56265 * @param {Number} rowIndex The selected row index
56266 * @param {Number} colIndex The selected cell index
56268 "beforecellselect" : true,
56270 * @event cellselect
56271 * Fires when a cell is selected.
56272 * @param {SelectionModel} this
56273 * @param {Number} rowIndex The selected row index
56274 * @param {Number} colIndex The selected cell index
56276 "cellselect" : true,
56278 * @event selectionchange
56279 * Fires when the active selection changes.
56280 * @param {SelectionModel} this
56281 * @param {Object} selection null for no selection or an object (o) with two properties
56283 <li>o.record: the record object for the row the selection is in</li>
56284 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56287 "selectionchange" : true,
56290 * Fires when the tab (or enter) was pressed on the last editable cell
56291 * You can use this to trigger add new row.
56292 * @param {SelectionModel} this
56296 * @event beforeeditnext
56297 * Fires before the next editable sell is made active
56298 * You can use this to skip to another cell or fire the tabend
56299 * if you set cell to false
56300 * @param {Object} eventdata object : { cell : [ row, col ] }
56302 "beforeeditnext" : true
56304 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56307 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56309 enter_is_tab: false,
56312 initEvents : function(){
56313 this.grid.on("mousedown", this.handleMouseDown, this);
56314 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56315 var view = this.grid.view;
56316 view.on("refresh", this.onViewChange, this);
56317 view.on("rowupdated", this.onRowUpdated, this);
56318 view.on("beforerowremoved", this.clearSelections, this);
56319 view.on("beforerowsinserted", this.clearSelections, this);
56320 if(this.grid.isEditor){
56321 this.grid.on("beforeedit", this.beforeEdit, this);
56326 beforeEdit : function(e){
56327 this.select(e.row, e.column, false, true, e.record);
56331 onRowUpdated : function(v, index, r){
56332 if(this.selection && this.selection.record == r){
56333 v.onCellSelect(index, this.selection.cell[1]);
56338 onViewChange : function(){
56339 this.clearSelections(true);
56343 * Returns the currently selected cell,.
56344 * @return {Array} The selected cell (row, column) or null if none selected.
56346 getSelectedCell : function(){
56347 return this.selection ? this.selection.cell : null;
56351 * Clears all selections.
56352 * @param {Boolean} true to prevent the gridview from being notified about the change.
56354 clearSelections : function(preventNotify){
56355 var s = this.selection;
56357 if(preventNotify !== true){
56358 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56360 this.selection = null;
56361 this.fireEvent("selectionchange", this, null);
56366 * Returns true if there is a selection.
56367 * @return {Boolean}
56369 hasSelection : function(){
56370 return this.selection ? true : false;
56374 handleMouseDown : function(e, t){
56375 var v = this.grid.getView();
56376 if(this.isLocked()){
56379 var row = v.findRowIndex(t);
56380 var cell = v.findCellIndex(t);
56381 if(row !== false && cell !== false){
56382 this.select(row, cell);
56388 * @param {Number} rowIndex
56389 * @param {Number} collIndex
56391 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56392 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56393 this.clearSelections();
56394 r = r || this.grid.dataSource.getAt(rowIndex);
56397 cell : [rowIndex, colIndex]
56399 if(!preventViewNotify){
56400 var v = this.grid.getView();
56401 v.onCellSelect(rowIndex, colIndex);
56402 if(preventFocus !== true){
56403 v.focusCell(rowIndex, colIndex);
56406 this.fireEvent("cellselect", this, rowIndex, colIndex);
56407 this.fireEvent("selectionchange", this, this.selection);
56412 isSelectable : function(rowIndex, colIndex, cm){
56413 return !cm.isHidden(colIndex);
56417 handleKeyDown : function(e){
56418 //Roo.log('Cell Sel Model handleKeyDown');
56419 if(!e.isNavKeyPress()){
56422 var g = this.grid, s = this.selection;
56425 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56427 this.select(cell[0], cell[1]);
56432 var walk = function(row, col, step){
56433 return g.walkCells(row, col, step, sm.isSelectable, sm);
56435 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56442 // handled by onEditorKey
56443 if (g.isEditor && g.editing) {
56447 newCell = walk(r, c-1, -1);
56449 newCell = walk(r, c+1, 1);
56454 newCell = walk(r+1, c, 1);
56458 newCell = walk(r-1, c, -1);
56462 newCell = walk(r, c+1, 1);
56466 newCell = walk(r, c-1, -1);
56471 if(g.isEditor && !g.editing){
56472 g.startEditing(r, c);
56481 this.select(newCell[0], newCell[1]);
56487 acceptsNav : function(row, col, cm){
56488 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56492 * @param {Number} field (not used) - as it's normally used as a listener
56493 * @param {Number} e - event - fake it by using
56495 * var e = Roo.EventObjectImpl.prototype;
56496 * e.keyCode = e.TAB
56500 onEditorKey : function(field, e){
56502 var k = e.getKey(),
56505 ed = g.activeEditor,
56507 ///Roo.log('onEditorKey' + k);
56510 if (this.enter_is_tab && k == e.ENTER) {
56516 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56518 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56524 } else if(k == e.ENTER && !e.ctrlKey){
56527 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56529 } else if(k == e.ESC){
56534 var ecall = { cell : newCell, forward : forward };
56535 this.fireEvent('beforeeditnext', ecall );
56536 newCell = ecall.cell;
56537 forward = ecall.forward;
56541 //Roo.log('next cell after edit');
56542 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56543 } else if (forward) {
56544 // tabbed past last
56545 this.fireEvent.defer(100, this, ['tabend',this]);
56550 * Ext JS Library 1.1.1
56551 * Copyright(c) 2006-2007, Ext JS, LLC.
56553 * Originally Released Under LGPL - original licence link has changed is not relivant.
56556 * <script type="text/javascript">
56560 * @class Roo.grid.EditorGrid
56561 * @extends Roo.grid.Grid
56562 * Class for creating and editable grid.
56563 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56564 * The container MUST have some type of size defined for the grid to fill. The container will be
56565 * automatically set to position relative if it isn't already.
56566 * @param {Object} dataSource The data model to bind to
56567 * @param {Object} colModel The column model with info about this grid's columns
56569 Roo.grid.EditorGrid = function(container, config){
56570 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56571 this.getGridEl().addClass("xedit-grid");
56573 if(!this.selModel){
56574 this.selModel = new Roo.grid.CellSelectionModel();
56577 this.activeEditor = null;
56581 * @event beforeedit
56582 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56583 * <ul style="padding:5px;padding-left:16px;">
56584 * <li>grid - This grid</li>
56585 * <li>record - The record being edited</li>
56586 * <li>field - The field name being edited</li>
56587 * <li>value - The value for the field being edited.</li>
56588 * <li>row - The grid row index</li>
56589 * <li>column - The grid column index</li>
56590 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56592 * @param {Object} e An edit event (see above for description)
56594 "beforeedit" : true,
56597 * Fires after a cell is edited. <br />
56598 * <ul style="padding:5px;padding-left:16px;">
56599 * <li>grid - This grid</li>
56600 * <li>record - The record being edited</li>
56601 * <li>field - The field name being edited</li>
56602 * <li>value - The value being set</li>
56603 * <li>originalValue - The original value for the field, before the edit.</li>
56604 * <li>row - The grid row index</li>
56605 * <li>column - The grid column index</li>
56607 * @param {Object} e An edit event (see above for description)
56609 "afteredit" : true,
56611 * @event validateedit
56612 * Fires after a cell is edited, but before the value is set in the record.
56613 * You can use this to modify the value being set in the field, Return false
56614 * to cancel the change. The edit event object has the following properties <br />
56615 * <ul style="padding:5px;padding-left:16px;">
56616 * <li>editor - This editor</li>
56617 * <li>grid - This grid</li>
56618 * <li>record - The record being edited</li>
56619 * <li>field - The field name being edited</li>
56620 * <li>value - The value being set</li>
56621 * <li>originalValue - The original value for the field, before the edit.</li>
56622 * <li>row - The grid row index</li>
56623 * <li>column - The grid column index</li>
56624 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56626 * @param {Object} e An edit event (see above for description)
56628 "validateedit" : true
56630 this.on("bodyscroll", this.stopEditing, this);
56631 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56634 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56636 * @cfg {Number} clicksToEdit
56637 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56644 trackMouseOver: false, // causes very odd FF errors
56646 onCellDblClick : function(g, row, col){
56647 this.startEditing(row, col);
56650 onEditComplete : function(ed, value, startValue){
56651 this.editing = false;
56652 this.activeEditor = null;
56653 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56655 var field = this.colModel.getDataIndex(ed.col);
56660 originalValue: startValue,
56667 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56670 if(String(value) !== String(startValue)){
56672 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56673 r.set(field, e.value);
56674 // if we are dealing with a combo box..
56675 // then we also set the 'name' colum to be the displayField
56676 if (ed.field.displayField && ed.field.name) {
56677 r.set(ed.field.name, ed.field.el.dom.value);
56680 delete e.cancel; //?? why!!!
56681 this.fireEvent("afteredit", e);
56684 this.fireEvent("afteredit", e); // always fire it!
56686 this.view.focusCell(ed.row, ed.col);
56690 * Starts editing the specified for the specified row/column
56691 * @param {Number} rowIndex
56692 * @param {Number} colIndex
56694 startEditing : function(row, col){
56695 this.stopEditing();
56696 if(this.colModel.isCellEditable(col, row)){
56697 this.view.ensureVisible(row, col, true);
56699 var r = this.dataSource.getAt(row);
56700 var field = this.colModel.getDataIndex(col);
56701 var cell = Roo.get(this.view.getCell(row,col));
56706 value: r.data[field],
56711 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56712 this.editing = true;
56713 var ed = this.colModel.getCellEditor(col, row);
56719 ed.render(ed.parentEl || document.body);
56725 (function(){ // complex but required for focus issues in safari, ie and opera
56729 ed.on("complete", this.onEditComplete, this, {single: true});
56730 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56731 this.activeEditor = ed;
56732 var v = r.data[field];
56733 ed.startEdit(this.view.getCell(row, col), v);
56734 // combo's with 'displayField and name set
56735 if (ed.field.displayField && ed.field.name) {
56736 ed.field.el.dom.value = r.data[ed.field.name];
56740 }).defer(50, this);
56746 * Stops any active editing
56748 stopEditing : function(){
56749 if(this.activeEditor){
56750 this.activeEditor.completeEdit();
56752 this.activeEditor = null;
56756 * Called to get grid's drag proxy text, by default returns this.ddText.
56759 getDragDropText : function(){
56760 var count = this.selModel.getSelectedCell() ? 1 : 0;
56761 return String.format(this.ddText, count, count == 1 ? '' : 's');
56766 * Ext JS Library 1.1.1
56767 * Copyright(c) 2006-2007, Ext JS, LLC.
56769 * Originally Released Under LGPL - original licence link has changed is not relivant.
56772 * <script type="text/javascript">
56775 // private - not really -- you end up using it !
56776 // This is a support class used internally by the Grid components
56779 * @class Roo.grid.GridEditor
56780 * @extends Roo.Editor
56781 * Class for creating and editable grid elements.
56782 * @param {Object} config any settings (must include field)
56784 Roo.grid.GridEditor = function(field, config){
56785 if (!config && field.field) {
56787 field = Roo.factory(config.field, Roo.form);
56789 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56790 field.monitorTab = false;
56793 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56796 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56799 alignment: "tl-tl",
56802 cls: "x-small-editor x-grid-editor",
56807 * Ext JS Library 1.1.1
56808 * Copyright(c) 2006-2007, Ext JS, LLC.
56810 * Originally Released Under LGPL - original licence link has changed is not relivant.
56813 * <script type="text/javascript">
56818 Roo.grid.PropertyRecord = Roo.data.Record.create([
56819 {name:'name',type:'string'}, 'value'
56823 Roo.grid.PropertyStore = function(grid, source){
56825 this.store = new Roo.data.Store({
56826 recordType : Roo.grid.PropertyRecord
56828 this.store.on('update', this.onUpdate, this);
56830 this.setSource(source);
56832 Roo.grid.PropertyStore.superclass.constructor.call(this);
56837 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56838 setSource : function(o){
56840 this.store.removeAll();
56843 if(this.isEditableValue(o[k])){
56844 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56847 this.store.loadRecords({records: data}, {}, true);
56850 onUpdate : function(ds, record, type){
56851 if(type == Roo.data.Record.EDIT){
56852 var v = record.data['value'];
56853 var oldValue = record.modified['value'];
56854 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56855 this.source[record.id] = v;
56857 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56864 getProperty : function(row){
56865 return this.store.getAt(row);
56868 isEditableValue: function(val){
56869 if(val && val instanceof Date){
56871 }else if(typeof val == 'object' || typeof val == 'function'){
56877 setValue : function(prop, value){
56878 this.source[prop] = value;
56879 this.store.getById(prop).set('value', value);
56882 getSource : function(){
56883 return this.source;
56887 Roo.grid.PropertyColumnModel = function(grid, store){
56890 g.PropertyColumnModel.superclass.constructor.call(this, [
56891 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56892 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56894 this.store = store;
56895 this.bselect = Roo.DomHelper.append(document.body, {
56896 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56897 {tag: 'option', value: 'true', html: 'true'},
56898 {tag: 'option', value: 'false', html: 'false'}
56901 Roo.id(this.bselect);
56904 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56905 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56906 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56907 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56908 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56910 this.renderCellDelegate = this.renderCell.createDelegate(this);
56911 this.renderPropDelegate = this.renderProp.createDelegate(this);
56914 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56918 valueText : 'Value',
56920 dateFormat : 'm/j/Y',
56923 renderDate : function(dateVal){
56924 return dateVal.dateFormat(this.dateFormat);
56927 renderBool : function(bVal){
56928 return bVal ? 'true' : 'false';
56931 isCellEditable : function(colIndex, rowIndex){
56932 return colIndex == 1;
56935 getRenderer : function(col){
56937 this.renderCellDelegate : this.renderPropDelegate;
56940 renderProp : function(v){
56941 return this.getPropertyName(v);
56944 renderCell : function(val){
56946 if(val instanceof Date){
56947 rv = this.renderDate(val);
56948 }else if(typeof val == 'boolean'){
56949 rv = this.renderBool(val);
56951 return Roo.util.Format.htmlEncode(rv);
56954 getPropertyName : function(name){
56955 var pn = this.grid.propertyNames;
56956 return pn && pn[name] ? pn[name] : name;
56959 getCellEditor : function(colIndex, rowIndex){
56960 var p = this.store.getProperty(rowIndex);
56961 var n = p.data['name'], val = p.data['value'];
56963 if(typeof(this.grid.customEditors[n]) == 'string'){
56964 return this.editors[this.grid.customEditors[n]];
56966 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56967 return this.grid.customEditors[n];
56969 if(val instanceof Date){
56970 return this.editors['date'];
56971 }else if(typeof val == 'number'){
56972 return this.editors['number'];
56973 }else if(typeof val == 'boolean'){
56974 return this.editors['boolean'];
56976 return this.editors['string'];
56982 * @class Roo.grid.PropertyGrid
56983 * @extends Roo.grid.EditorGrid
56984 * This class represents the interface of a component based property grid control.
56985 * <br><br>Usage:<pre><code>
56986 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56994 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56995 * The container MUST have some type of size defined for the grid to fill. The container will be
56996 * automatically set to position relative if it isn't already.
56997 * @param {Object} config A config object that sets properties on this grid.
56999 Roo.grid.PropertyGrid = function(container, config){
57000 config = config || {};
57001 var store = new Roo.grid.PropertyStore(this);
57002 this.store = store;
57003 var cm = new Roo.grid.PropertyColumnModel(this, store);
57004 store.store.sort('name', 'ASC');
57005 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57008 enableColLock:false,
57009 enableColumnMove:false,
57011 trackMouseOver: false,
57014 this.getGridEl().addClass('x-props-grid');
57015 this.lastEditRow = null;
57016 this.on('columnresize', this.onColumnResize, this);
57019 * @event beforepropertychange
57020 * Fires before a property changes (return false to stop?)
57021 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57022 * @param {String} id Record Id
57023 * @param {String} newval New Value
57024 * @param {String} oldval Old Value
57026 "beforepropertychange": true,
57028 * @event propertychange
57029 * Fires after a property changes
57030 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57031 * @param {String} id Record Id
57032 * @param {String} newval New Value
57033 * @param {String} oldval Old Value
57035 "propertychange": true
57037 this.customEditors = this.customEditors || {};
57039 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57042 * @cfg {Object} customEditors map of colnames=> custom editors.
57043 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57044 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57045 * false disables editing of the field.
57049 * @cfg {Object} propertyNames map of property Names to their displayed value
57052 render : function(){
57053 Roo.grid.PropertyGrid.superclass.render.call(this);
57054 this.autoSize.defer(100, this);
57057 autoSize : function(){
57058 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57060 this.view.fitColumns();
57064 onColumnResize : function(){
57065 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57069 * Sets the data for the Grid
57070 * accepts a Key => Value object of all the elements avaiable.
57071 * @param {Object} data to appear in grid.
57073 setSource : function(source){
57074 this.store.setSource(source);
57078 * Gets all the data from the grid.
57079 * @return {Object} data data stored in grid
57081 getSource : function(){
57082 return this.store.getSource();
57091 * @class Roo.grid.Calendar
57092 * @extends Roo.util.Grid
57093 * This class extends the Grid to provide a calendar widget
57094 * <br><br>Usage:<pre><code>
57095 var grid = new Roo.grid.Calendar("my-container-id", {
57098 selModel: mySelectionModel,
57099 autoSizeColumns: true,
57100 monitorWindowResize: false,
57101 trackMouseOver: true
57102 eventstore : real data store..
57108 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57109 * The container MUST have some type of size defined for the grid to fill. The container will be
57110 * automatically set to position relative if it isn't already.
57111 * @param {Object} config A config object that sets properties on this grid.
57113 Roo.grid.Calendar = function(container, config){
57114 // initialize the container
57115 this.container = Roo.get(container);
57116 this.container.update("");
57117 this.container.setStyle("overflow", "hidden");
57118 this.container.addClass('x-grid-container');
57120 this.id = this.container.id;
57122 Roo.apply(this, config);
57123 // check and correct shorthanded configs
57127 for (var r = 0;r < 6;r++) {
57130 for (var c =0;c < 7;c++) {
57134 if (this.eventStore) {
57135 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57136 this.eventStore.on('load',this.onLoad, this);
57137 this.eventStore.on('beforeload',this.clearEvents, this);
57141 this.dataSource = new Roo.data.Store({
57142 proxy: new Roo.data.MemoryProxy(rows),
57143 reader: new Roo.data.ArrayReader({}, [
57144 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57147 this.dataSource.load();
57148 this.ds = this.dataSource;
57149 this.ds.xmodule = this.xmodule || false;
57152 var cellRender = function(v,x,r)
57154 return String.format(
57155 '<div class="fc-day fc-widget-content"><div>' +
57156 '<div class="fc-event-container"></div>' +
57157 '<div class="fc-day-number">{0}</div>'+
57159 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57160 '</div></div>', v);
57165 this.colModel = new Roo.grid.ColumnModel( [
57167 xtype: 'ColumnModel',
57169 dataIndex : 'weekday0',
57171 renderer : cellRender
57174 xtype: 'ColumnModel',
57176 dataIndex : 'weekday1',
57178 renderer : cellRender
57181 xtype: 'ColumnModel',
57183 dataIndex : 'weekday2',
57184 header : 'Tuesday',
57185 renderer : cellRender
57188 xtype: 'ColumnModel',
57190 dataIndex : 'weekday3',
57191 header : 'Wednesday',
57192 renderer : cellRender
57195 xtype: 'ColumnModel',
57197 dataIndex : 'weekday4',
57198 header : 'Thursday',
57199 renderer : cellRender
57202 xtype: 'ColumnModel',
57204 dataIndex : 'weekday5',
57206 renderer : cellRender
57209 xtype: 'ColumnModel',
57211 dataIndex : 'weekday6',
57212 header : 'Saturday',
57213 renderer : cellRender
57216 this.cm = this.colModel;
57217 this.cm.xmodule = this.xmodule || false;
57221 //this.selModel = new Roo.grid.CellSelectionModel();
57222 //this.sm = this.selModel;
57223 //this.selModel.init(this);
57227 this.container.setWidth(this.width);
57231 this.container.setHeight(this.height);
57238 * The raw click event for the entire grid.
57239 * @param {Roo.EventObject} e
57244 * The raw dblclick event for the entire grid.
57245 * @param {Roo.EventObject} e
57249 * @event contextmenu
57250 * The raw contextmenu event for the entire grid.
57251 * @param {Roo.EventObject} e
57253 "contextmenu" : true,
57256 * The raw mousedown event for the entire grid.
57257 * @param {Roo.EventObject} e
57259 "mousedown" : true,
57262 * The raw mouseup event for the entire grid.
57263 * @param {Roo.EventObject} e
57268 * The raw mouseover event for the entire grid.
57269 * @param {Roo.EventObject} e
57271 "mouseover" : true,
57274 * The raw mouseout event for the entire grid.
57275 * @param {Roo.EventObject} e
57280 * The raw keypress event for the entire grid.
57281 * @param {Roo.EventObject} e
57286 * The raw keydown event for the entire grid.
57287 * @param {Roo.EventObject} e
57295 * Fires when a cell is clicked
57296 * @param {Grid} this
57297 * @param {Number} rowIndex
57298 * @param {Number} columnIndex
57299 * @param {Roo.EventObject} e
57301 "cellclick" : true,
57303 * @event celldblclick
57304 * Fires when a cell is double clicked
57305 * @param {Grid} this
57306 * @param {Number} rowIndex
57307 * @param {Number} columnIndex
57308 * @param {Roo.EventObject} e
57310 "celldblclick" : true,
57313 * Fires when a row is clicked
57314 * @param {Grid} this
57315 * @param {Number} rowIndex
57316 * @param {Roo.EventObject} e
57320 * @event rowdblclick
57321 * Fires when a row is double clicked
57322 * @param {Grid} this
57323 * @param {Number} rowIndex
57324 * @param {Roo.EventObject} e
57326 "rowdblclick" : true,
57328 * @event headerclick
57329 * Fires when a header is clicked
57330 * @param {Grid} this
57331 * @param {Number} columnIndex
57332 * @param {Roo.EventObject} e
57334 "headerclick" : true,
57336 * @event headerdblclick
57337 * Fires when a header cell is double clicked
57338 * @param {Grid} this
57339 * @param {Number} columnIndex
57340 * @param {Roo.EventObject} e
57342 "headerdblclick" : true,
57344 * @event rowcontextmenu
57345 * Fires when a row is right clicked
57346 * @param {Grid} this
57347 * @param {Number} rowIndex
57348 * @param {Roo.EventObject} e
57350 "rowcontextmenu" : true,
57352 * @event cellcontextmenu
57353 * Fires when a cell is right clicked
57354 * @param {Grid} this
57355 * @param {Number} rowIndex
57356 * @param {Number} cellIndex
57357 * @param {Roo.EventObject} e
57359 "cellcontextmenu" : true,
57361 * @event headercontextmenu
57362 * Fires when a header is right clicked
57363 * @param {Grid} this
57364 * @param {Number} columnIndex
57365 * @param {Roo.EventObject} e
57367 "headercontextmenu" : true,
57369 * @event bodyscroll
57370 * Fires when the body element is scrolled
57371 * @param {Number} scrollLeft
57372 * @param {Number} scrollTop
57374 "bodyscroll" : true,
57376 * @event columnresize
57377 * Fires when the user resizes a column
57378 * @param {Number} columnIndex
57379 * @param {Number} newSize
57381 "columnresize" : true,
57383 * @event columnmove
57384 * Fires when the user moves a column
57385 * @param {Number} oldIndex
57386 * @param {Number} newIndex
57388 "columnmove" : true,
57391 * Fires when row(s) start being dragged
57392 * @param {Grid} this
57393 * @param {Roo.GridDD} dd The drag drop object
57394 * @param {event} e The raw browser event
57396 "startdrag" : true,
57399 * Fires when a drag operation is complete
57400 * @param {Grid} this
57401 * @param {Roo.GridDD} dd The drag drop object
57402 * @param {event} e The raw browser event
57407 * Fires when dragged row(s) are dropped on a valid DD target
57408 * @param {Grid} this
57409 * @param {Roo.GridDD} dd The drag drop object
57410 * @param {String} targetId The target drag drop object
57411 * @param {event} e The raw browser event
57416 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57417 * @param {Grid} this
57418 * @param {Roo.GridDD} dd The drag drop object
57419 * @param {String} targetId The target drag drop object
57420 * @param {event} e The raw browser event
57425 * Fires when the dragged row(s) first cross another DD target while being dragged
57426 * @param {Grid} this
57427 * @param {Roo.GridDD} dd The drag drop object
57428 * @param {String} targetId The target drag drop object
57429 * @param {event} e The raw browser event
57431 "dragenter" : true,
57434 * Fires when the dragged row(s) leave another DD target while being dragged
57435 * @param {Grid} this
57436 * @param {Roo.GridDD} dd The drag drop object
57437 * @param {String} targetId The target drag drop object
57438 * @param {event} e The raw browser event
57443 * Fires when a row is rendered, so you can change add a style to it.
57444 * @param {GridView} gridview The grid view
57445 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57451 * Fires when the grid is rendered
57452 * @param {Grid} grid
57457 * Fires when a date is selected
57458 * @param {DatePicker} this
57459 * @param {Date} date The selected date
57463 * @event monthchange
57464 * Fires when the displayed month changes
57465 * @param {DatePicker} this
57466 * @param {Date} date The selected month
57468 'monthchange': true,
57470 * @event evententer
57471 * Fires when mouse over an event
57472 * @param {Calendar} this
57473 * @param {event} Event
57475 'evententer': true,
57477 * @event eventleave
57478 * Fires when the mouse leaves an
57479 * @param {Calendar} this
57482 'eventleave': true,
57484 * @event eventclick
57485 * Fires when the mouse click an
57486 * @param {Calendar} this
57489 'eventclick': true,
57491 * @event eventrender
57492 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57493 * @param {Calendar} this
57494 * @param {data} data to be modified
57496 'eventrender': true
57500 Roo.grid.Grid.superclass.constructor.call(this);
57501 this.on('render', function() {
57502 this.view.el.addClass('x-grid-cal');
57504 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57508 if (!Roo.grid.Calendar.style) {
57509 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57512 '.x-grid-cal .x-grid-col' : {
57513 height: 'auto !important',
57514 'vertical-align': 'top'
57516 '.x-grid-cal .fc-event-hori' : {
57527 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57529 * @cfg {Store} eventStore The store that loads events.
57534 activeDate : false,
57537 monitorWindowResize : false,
57540 resizeColumns : function() {
57541 var col = (this.view.el.getWidth() / 7) - 3;
57542 // loop through cols, and setWidth
57543 for(var i =0 ; i < 7 ; i++){
57544 this.cm.setColumnWidth(i, col);
57547 setDate :function(date) {
57549 Roo.log('setDate?');
57551 this.resizeColumns();
57552 var vd = this.activeDate;
57553 this.activeDate = date;
57554 // if(vd && this.el){
57555 // var t = date.getTime();
57556 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57557 // Roo.log('using add remove');
57559 // this.fireEvent('monthchange', this, date);
57561 // this.cells.removeClass("fc-state-highlight");
57562 // this.cells.each(function(c){
57563 // if(c.dateValue == t){
57564 // c.addClass("fc-state-highlight");
57565 // setTimeout(function(){
57566 // try{c.dom.firstChild.focus();}catch(e){}
57576 var days = date.getDaysInMonth();
57578 var firstOfMonth = date.getFirstDateOfMonth();
57579 var startingPos = firstOfMonth.getDay()-this.startDay;
57581 if(startingPos < this.startDay){
57585 var pm = date.add(Date.MONTH, -1);
57586 var prevStart = pm.getDaysInMonth()-startingPos;
57590 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57592 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57593 //this.cells.addClassOnOver('fc-state-hover');
57595 var cells = this.cells.elements;
57596 var textEls = this.textNodes;
57598 //Roo.each(cells, function(cell){
57599 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57602 days += startingPos;
57604 // convert everything to numbers so it's fast
57605 var day = 86400000;
57606 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57609 //Roo.log(prevStart);
57611 var today = new Date().clearTime().getTime();
57612 var sel = date.clearTime().getTime();
57613 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57614 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57615 var ddMatch = this.disabledDatesRE;
57616 var ddText = this.disabledDatesText;
57617 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57618 var ddaysText = this.disabledDaysText;
57619 var format = this.format;
57621 var setCellClass = function(cal, cell){
57623 //Roo.log('set Cell Class');
57625 var t = d.getTime();
57630 cell.dateValue = t;
57632 cell.className += " fc-today";
57633 cell.className += " fc-state-highlight";
57634 cell.title = cal.todayText;
57637 // disable highlight in other month..
57638 cell.className += " fc-state-highlight";
57643 //cell.className = " fc-state-disabled";
57644 cell.title = cal.minText;
57648 //cell.className = " fc-state-disabled";
57649 cell.title = cal.maxText;
57653 if(ddays.indexOf(d.getDay()) != -1){
57654 // cell.title = ddaysText;
57655 // cell.className = " fc-state-disabled";
57658 if(ddMatch && format){
57659 var fvalue = d.dateFormat(format);
57660 if(ddMatch.test(fvalue)){
57661 cell.title = ddText.replace("%0", fvalue);
57662 cell.className = " fc-state-disabled";
57666 if (!cell.initialClassName) {
57667 cell.initialClassName = cell.dom.className;
57670 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57675 for(; i < startingPos; i++) {
57676 cells[i].dayName = (++prevStart);
57677 Roo.log(textEls[i]);
57678 d.setDate(d.getDate()+1);
57680 //cells[i].className = "fc-past fc-other-month";
57681 setCellClass(this, cells[i]);
57686 for(; i < days; i++){
57687 intDay = i - startingPos + 1;
57688 cells[i].dayName = (intDay);
57689 d.setDate(d.getDate()+1);
57691 cells[i].className = ''; // "x-date-active";
57692 setCellClass(this, cells[i]);
57696 for(; i < 42; i++) {
57697 //textEls[i].innerHTML = (++extraDays);
57699 d.setDate(d.getDate()+1);
57700 cells[i].dayName = (++extraDays);
57701 cells[i].className = "fc-future fc-other-month";
57702 setCellClass(this, cells[i]);
57705 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57707 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57709 // this will cause all the cells to mis
57712 for (var r = 0;r < 6;r++) {
57713 for (var c =0;c < 7;c++) {
57714 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57718 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57719 for(i=0;i<cells.length;i++) {
57721 this.cells.elements[i].dayName = cells[i].dayName ;
57722 this.cells.elements[i].className = cells[i].className;
57723 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57724 this.cells.elements[i].title = cells[i].title ;
57725 this.cells.elements[i].dateValue = cells[i].dateValue ;
57731 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57732 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57734 ////if(totalRows != 6){
57735 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57736 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57739 this.fireEvent('monthchange', this, date);
57744 * Returns the grid's SelectionModel.
57745 * @return {SelectionModel}
57747 getSelectionModel : function(){
57748 if(!this.selModel){
57749 this.selModel = new Roo.grid.CellSelectionModel();
57751 return this.selModel;
57755 this.eventStore.load()
57761 findCell : function(dt) {
57762 dt = dt.clearTime().getTime();
57764 this.cells.each(function(c){
57765 //Roo.log("check " +c.dateValue + '?=' + dt);
57766 if(c.dateValue == dt){
57776 findCells : function(rec) {
57777 var s = rec.data.start_dt.clone().clearTime().getTime();
57779 var e= rec.data.end_dt.clone().clearTime().getTime();
57782 this.cells.each(function(c){
57783 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57785 if(c.dateValue > e){
57788 if(c.dateValue < s){
57797 findBestRow: function(cells)
57801 for (var i =0 ; i < cells.length;i++) {
57802 ret = Math.max(cells[i].rows || 0,ret);
57809 addItem : function(rec)
57811 // look for vertical location slot in
57812 var cells = this.findCells(rec);
57814 rec.row = this.findBestRow(cells);
57816 // work out the location.
57820 for(var i =0; i < cells.length; i++) {
57828 if (crow.start.getY() == cells[i].getY()) {
57830 crow.end = cells[i];
57846 for (var i = 0; i < cells.length;i++) {
57847 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57854 clearEvents: function() {
57856 if (!this.eventStore.getCount()) {
57859 // reset number of rows in cells.
57860 Roo.each(this.cells.elements, function(c){
57864 this.eventStore.each(function(e) {
57865 this.clearEvent(e);
57870 clearEvent : function(ev)
57873 Roo.each(ev.els, function(el) {
57874 el.un('mouseenter' ,this.onEventEnter, this);
57875 el.un('mouseleave' ,this.onEventLeave, this);
57883 renderEvent : function(ev,ctr) {
57885 ctr = this.view.el.select('.fc-event-container',true).first();
57889 this.clearEvent(ev);
57895 var cells = ev.cells;
57896 var rows = ev.rows;
57897 this.fireEvent('eventrender', this, ev);
57899 for(var i =0; i < rows.length; i++) {
57903 cls += ' fc-event-start';
57905 if ((i+1) == rows.length) {
57906 cls += ' fc-event-end';
57909 //Roo.log(ev.data);
57910 // how many rows should it span..
57911 var cg = this.eventTmpl.append(ctr,Roo.apply({
57914 }, ev.data) , true);
57917 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57918 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57919 cg.on('click', this.onEventClick, this, ev);
57923 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57924 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57927 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57928 cg.setWidth(ebox.right - sbox.x -2);
57932 renderEvents: function()
57934 // first make sure there is enough space..
57936 if (!this.eventTmpl) {
57937 this.eventTmpl = new Roo.Template(
57938 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57939 '<div class="fc-event-inner">' +
57940 '<span class="fc-event-time">{time}</span>' +
57941 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57943 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57951 this.cells.each(function(c) {
57952 //Roo.log(c.select('.fc-day-content div',true).first());
57953 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57956 var ctr = this.view.el.select('.fc-event-container',true).first();
57959 this.eventStore.each(function(ev){
57961 this.renderEvent(ev);
57965 this.view.layout();
57969 onEventEnter: function (e, el,event,d) {
57970 this.fireEvent('evententer', this, el, event);
57973 onEventLeave: function (e, el,event,d) {
57974 this.fireEvent('eventleave', this, el, event);
57977 onEventClick: function (e, el,event,d) {
57978 this.fireEvent('eventclick', this, el, event);
57981 onMonthChange: function () {
57985 onLoad: function () {
57987 //Roo.log('calendar onload');
57989 if(this.eventStore.getCount() > 0){
57993 this.eventStore.each(function(d){
57998 if (typeof(add.end_dt) == 'undefined') {
57999 Roo.log("Missing End time in calendar data: ");
58003 if (typeof(add.start_dt) == 'undefined') {
58004 Roo.log("Missing Start time in calendar data: ");
58008 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58009 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58010 add.id = add.id || d.id;
58011 add.title = add.title || '??';
58019 this.renderEvents();
58029 render : function ()
58033 if (!this.view.el.hasClass('course-timesheet')) {
58034 this.view.el.addClass('course-timesheet');
58036 if (this.tsStyle) {
58041 Roo.log(_this.grid.view.el.getWidth());
58044 this.tsStyle = Roo.util.CSS.createStyleSheet({
58045 '.course-timesheet .x-grid-row' : {
58048 '.x-grid-row td' : {
58049 'vertical-align' : 0
58051 '.course-edit-link' : {
58053 'text-overflow' : 'ellipsis',
58054 'overflow' : 'hidden',
58055 'white-space' : 'nowrap',
58056 'cursor' : 'pointer'
58061 '.de-act-sup-link' : {
58062 'color' : 'purple',
58063 'text-decoration' : 'line-through'
58067 'text-decoration' : 'line-through'
58069 '.course-timesheet .course-highlight' : {
58070 'border-top-style': 'dashed !important',
58071 'border-bottom-bottom': 'dashed !important'
58073 '.course-timesheet .course-item' : {
58074 'font-family' : 'tahoma, arial, helvetica',
58075 'font-size' : '11px',
58076 'overflow' : 'hidden',
58077 'padding-left' : '10px',
58078 'padding-right' : '10px',
58079 'padding-top' : '10px'
58087 monitorWindowResize : false,
58088 cellrenderer : function(v,x,r)
58093 xtype: 'CellSelectionModel',
58100 beforeload : function (_self, options)
58102 options.params = options.params || {};
58103 options.params._month = _this.monthField.getValue();
58104 options.params.limit = 9999;
58105 options.params['sort'] = 'when_dt';
58106 options.params['dir'] = 'ASC';
58107 this.proxy.loadResponse = this.loadResponse;
58109 //this.addColumns();
58111 load : function (_self, records, options)
58113 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58114 // if you click on the translation.. you can edit it...
58115 var el = Roo.get(this);
58116 var id = el.dom.getAttribute('data-id');
58117 var d = el.dom.getAttribute('data-date');
58118 var t = el.dom.getAttribute('data-time');
58119 //var id = this.child('span').dom.textContent;
58122 Pman.Dialog.CourseCalendar.show({
58126 productitem_active : id ? 1 : 0
58128 _this.grid.ds.load({});
58133 _this.panel.fireEvent('resize', [ '', '' ]);
58136 loadResponse : function(o, success, response){
58137 // this is overridden on before load..
58139 Roo.log("our code?");
58140 //Roo.log(success);
58141 //Roo.log(response)
58142 delete this.activeRequest;
58144 this.fireEvent("loadexception", this, o, response);
58145 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58150 result = o.reader.read(response);
58152 Roo.log("load exception?");
58153 this.fireEvent("loadexception", this, o, response, e);
58154 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58157 Roo.log("ready...");
58158 // loop through result.records;
58159 // and set this.tdate[date] = [] << array of records..
58161 Roo.each(result.records, function(r){
58163 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58164 _this.tdata[r.data.when_dt.format('j')] = [];
58166 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58169 //Roo.log(_this.tdata);
58171 result.records = [];
58172 result.totalRecords = 6;
58174 // let's generate some duumy records for the rows.
58175 //var st = _this.dateField.getValue();
58177 // work out monday..
58178 //st = st.add(Date.DAY, -1 * st.format('w'));
58180 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58182 var firstOfMonth = date.getFirstDayOfMonth();
58183 var days = date.getDaysInMonth();
58185 var firstAdded = false;
58186 for (var i = 0; i < result.totalRecords ; i++) {
58187 //var d= st.add(Date.DAY, i);
58190 for(var w = 0 ; w < 7 ; w++){
58191 if(!firstAdded && firstOfMonth != w){
58198 var dd = (d > 0 && d < 10) ? "0"+d : d;
58199 row['weekday'+w] = String.format(
58200 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58201 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58203 date.format('Y-m-')+dd
58206 if(typeof(_this.tdata[d]) != 'undefined'){
58207 Roo.each(_this.tdata[d], function(r){
58211 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58212 if(r.parent_id*1>0){
58213 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58216 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58217 deactive = 'de-act-link';
58220 row['weekday'+w] += String.format(
58221 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58223 r.product_id_name, //1
58224 r.when_dt.format('h:ia'), //2
58234 // only do this if something added..
58236 result.records.push(_this.grid.dataSource.reader.newRow(row));
58240 // push it twice. (second one with an hour..
58244 this.fireEvent("load", this, o, o.request.arg);
58245 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58247 sortInfo : {field: 'when_dt', direction : 'ASC' },
58249 xtype: 'HttpProxy',
58252 url : baseURL + '/Roo/Shop_course.php'
58255 xtype: 'JsonReader',
58272 'name': 'parent_id',
58276 'name': 'product_id',
58280 'name': 'productitem_id',
58298 click : function (_self, e)
58300 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58301 sd.setMonth(sd.getMonth()-1);
58302 _this.monthField.setValue(sd.format('Y-m-d'));
58303 _this.grid.ds.load({});
58309 xtype: 'Separator',
58313 xtype: 'MonthField',
58316 render : function (_self)
58318 _this.monthField = _self;
58319 // _this.monthField.set today
58321 select : function (combo, date)
58323 _this.grid.ds.load({});
58326 value : (function() { return new Date(); })()
58329 xtype: 'Separator',
58335 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58345 click : function (_self, e)
58347 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58348 sd.setMonth(sd.getMonth()+1);
58349 _this.monthField.setValue(sd.format('Y-m-d'));
58350 _this.grid.ds.load({});
58363 * Ext JS Library 1.1.1
58364 * Copyright(c) 2006-2007, Ext JS, LLC.
58366 * Originally Released Under LGPL - original licence link has changed is not relivant.
58369 * <script type="text/javascript">
58373 * @class Roo.LoadMask
58374 * A simple utility class for generically masking elements while loading data. If the element being masked has
58375 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58376 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58377 * element's UpdateManager load indicator and will be destroyed after the initial load.
58379 * Create a new LoadMask
58380 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58381 * @param {Object} config The config object
58383 Roo.LoadMask = function(el, config){
58384 this.el = Roo.get(el);
58385 Roo.apply(this, config);
58387 this.store.on('beforeload', this.onBeforeLoad, this);
58388 this.store.on('load', this.onLoad, this);
58389 this.store.on('loadexception', this.onLoadException, this);
58390 this.removeMask = false;
58392 var um = this.el.getUpdateManager();
58393 um.showLoadIndicator = false; // disable the default indicator
58394 um.on('beforeupdate', this.onBeforeLoad, this);
58395 um.on('update', this.onLoad, this);
58396 um.on('failure', this.onLoad, this);
58397 this.removeMask = true;
58401 Roo.LoadMask.prototype = {
58403 * @cfg {Boolean} removeMask
58404 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58405 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58408 * @cfg {String} msg
58409 * The text to display in a centered loading message box (defaults to 'Loading...')
58411 msg : 'Loading...',
58413 * @cfg {String} msgCls
58414 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58416 msgCls : 'x-mask-loading',
58419 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58425 * Disables the mask to prevent it from being displayed
58427 disable : function(){
58428 this.disabled = true;
58432 * Enables the mask so that it can be displayed
58434 enable : function(){
58435 this.disabled = false;
58438 onLoadException : function()
58440 Roo.log(arguments);
58442 if (typeof(arguments[3]) != 'undefined') {
58443 Roo.MessageBox.alert("Error loading",arguments[3]);
58447 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58448 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58457 this.el.unmask(this.removeMask);
58460 onLoad : function()
58462 this.el.unmask(this.removeMask);
58466 onBeforeLoad : function(){
58467 if(!this.disabled){
58468 this.el.mask(this.msg, this.msgCls);
58473 destroy : function(){
58475 this.store.un('beforeload', this.onBeforeLoad, this);
58476 this.store.un('load', this.onLoad, this);
58477 this.store.un('loadexception', this.onLoadException, this);
58479 var um = this.el.getUpdateManager();
58480 um.un('beforeupdate', this.onBeforeLoad, this);
58481 um.un('update', this.onLoad, this);
58482 um.un('failure', this.onLoad, this);
58487 * Ext JS Library 1.1.1
58488 * Copyright(c) 2006-2007, Ext JS, LLC.
58490 * Originally Released Under LGPL - original licence link has changed is not relivant.
58493 * <script type="text/javascript">
58498 * @class Roo.XTemplate
58499 * @extends Roo.Template
58500 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58502 var t = new Roo.XTemplate(
58503 '<select name="{name}">',
58504 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58508 // then append, applying the master template values
58511 * Supported features:
58516 {a_variable} - output encoded.
58517 {a_variable.format:("Y-m-d")} - call a method on the variable
58518 {a_variable:raw} - unencoded output
58519 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58520 {a_variable:this.method_on_template(...)} - call a method on the template object.
58525 <tpl for="a_variable or condition.."></tpl>
58526 <tpl if="a_variable or condition"></tpl>
58527 <tpl exec="some javascript"></tpl>
58528 <tpl name="named_template"></tpl> (experimental)
58530 <tpl for="."></tpl> - just iterate the property..
58531 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58535 Roo.XTemplate = function()
58537 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58544 Roo.extend(Roo.XTemplate, Roo.Template, {
58547 * The various sub templates
58552 * basic tag replacing syntax
58555 * // you can fake an object call by doing this
58559 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58562 * compile the template
58564 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58567 compile: function()
58571 s = ['<tpl>', s, '</tpl>'].join('');
58573 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58574 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58575 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58576 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58577 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58582 while(true == !!(m = s.match(re))){
58583 var forMatch = m[0].match(nameRe),
58584 ifMatch = m[0].match(ifRe),
58585 execMatch = m[0].match(execRe),
58586 namedMatch = m[0].match(namedRe),
58591 name = forMatch && forMatch[1] ? forMatch[1] : '';
58594 // if - puts fn into test..
58595 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58597 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58602 // exec - calls a function... returns empty if true is returned.
58603 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58605 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58613 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58614 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58615 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58618 var uid = namedMatch ? namedMatch[1] : id;
58622 id: namedMatch ? namedMatch[1] : id,
58629 s = s.replace(m[0], '');
58631 s = s.replace(m[0], '{xtpl'+ id + '}');
58636 for(var i = tpls.length-1; i >= 0; --i){
58637 this.compileTpl(tpls[i]);
58638 this.tpls[tpls[i].id] = tpls[i];
58640 this.master = tpls[tpls.length-1];
58644 * same as applyTemplate, except it's done to one of the subTemplates
58645 * when using named templates, you can do:
58647 * var str = pl.applySubTemplate('your-name', values);
58650 * @param {Number} id of the template
58651 * @param {Object} values to apply to template
58652 * @param {Object} parent (normaly the instance of this object)
58654 applySubTemplate : function(id, values, parent)
58658 var t = this.tpls[id];
58662 if(t.test && !t.test.call(this, values, parent)){
58666 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58667 Roo.log(e.toString());
58673 if(t.exec && t.exec.call(this, values, parent)){
58677 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58678 Roo.log(e.toString());
58683 var vs = t.target ? t.target.call(this, values, parent) : values;
58684 parent = t.target ? values : parent;
58685 if(t.target && vs instanceof Array){
58687 for(var i = 0, len = vs.length; i < len; i++){
58688 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58690 return buf.join('');
58692 return t.compiled.call(this, vs, parent);
58694 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58695 Roo.log(e.toString());
58696 Roo.log(t.compiled);
58701 compileTpl : function(tpl)
58703 var fm = Roo.util.Format;
58704 var useF = this.disableFormats !== true;
58705 var sep = Roo.isGecko ? "+" : ",";
58706 var undef = function(str) {
58707 Roo.log("Property not found :" + str);
58711 var fn = function(m, name, format, args)
58713 //Roo.log(arguments);
58714 args = args ? args.replace(/\\'/g,"'") : args;
58715 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58716 if (typeof(format) == 'undefined') {
58717 format= 'htmlEncode';
58719 if (format == 'raw' ) {
58723 if(name.substr(0, 4) == 'xtpl'){
58724 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58727 // build an array of options to determine if value is undefined..
58729 // basically get 'xxxx.yyyy' then do
58730 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58731 // (function () { Roo.log("Property not found"); return ''; })() :
58736 Roo.each(name.split('.'), function(st) {
58737 lookfor += (lookfor.length ? '.': '') + st;
58738 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58741 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58744 if(format && useF){
58746 args = args ? ',' + args : "";
58748 if(format.substr(0, 5) != "this."){
58749 format = "fm." + format + '(';
58751 format = 'this.call("'+ format.substr(5) + '", ';
58755 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58759 // called with xxyx.yuu:(test,test)
58761 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58763 // raw.. - :raw modifier..
58764 return "'"+ sep + udef_st + name + ")"+sep+"'";
58768 // branched to use + in gecko and [].join() in others
58770 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58771 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58774 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58775 body.push(tpl.body.replace(/(\r\n|\n)/g,
58776 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58777 body.push("'].join('');};};");
58778 body = body.join('');
58781 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58783 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58789 applyTemplate : function(values){
58790 return this.master.compiled.call(this, values, {});
58791 //var s = this.subs;
58794 apply : function(){
58795 return this.applyTemplate.apply(this, arguments);
58800 Roo.XTemplate.from = function(el){
58801 el = Roo.getDom(el);
58802 return new Roo.XTemplate(el.value || el.innerHTML);