4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64 isTouch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * 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]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
622 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623 * you may want to set this to true.
626 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
631 * Selects a single element as a Roo Element
632 * This is about as close as you can get to jQuery's $('do crazy stuff')
633 * @param {String} selector The selector/xpath query
634 * @param {Node} root (optional) The start of the query (defaults to document).
635 * @return {Roo.Element}
637 selectNode : function(selector, root)
639 var node = Roo.DomQuery.selectNode(selector,root);
640 return node ? Roo.get(node) : new Roo.Element(false);
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
652 * Ext JS Library 1.1.1
653 * Copyright(c) 2006-2007, Ext JS, LLC.
655 * Originally Released Under LGPL - original licence link has changed is not relivant.
658 * <script type="text/javascript">
662 // wrappedn so fnCleanup is not in global scope...
664 function fnCleanUp() {
665 var p = Function.prototype;
666 delete p.createSequence;
668 delete p.createDelegate;
669 delete p.createCallback;
670 delete p.createInterceptor;
672 window.detachEvent("onunload", fnCleanUp);
674 window.attachEvent("onunload", fnCleanUp);
681 * These functions are available on every Function object (any JavaScript function).
683 Roo.apply(Function.prototype, {
685 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687 * Will create a function that is bound to those 2 args.
688 * @return {Function} The new function
690 createCallback : function(/*args...*/){
691 // make args available, in function below
692 var args = arguments;
695 return method.apply(window, args);
700 * Creates a delegate (callback) that sets the scope to obj.
701 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702 * Will create a function that is automatically scoped to this.
703 * @param {Object} obj (optional) The object for which the scope is set
704 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706 * if a number the args are inserted at the specified position
707 * @return {Function} The new function
709 createDelegate : function(obj, args, appendArgs){
712 var callArgs = args || arguments;
713 if(appendArgs === true){
714 callArgs = Array.prototype.slice.call(arguments, 0);
715 callArgs = callArgs.concat(args);
716 }else if(typeof appendArgs == "number"){
717 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
721 return method.apply(obj || window, callArgs);
726 * Calls this function after the number of millseconds specified.
727 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728 * @param {Object} obj (optional) The object for which the scope is set
729 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731 * if a number the args are inserted at the specified position
732 * @return {Number} The timeout id that can be used with clearTimeout
734 defer : function(millis, obj, args, appendArgs){
735 var fn = this.createDelegate(obj, args, appendArgs);
737 return setTimeout(fn, millis);
743 * Create a combined function call sequence of the original function + the passed function.
744 * The resulting function returns the results of the original function.
745 * The passed fcn is called with the parameters of the original function
746 * @param {Function} fcn The function to sequence
747 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748 * @return {Function} The new function
750 createSequence : function(fcn, scope){
751 if(typeof fcn != "function"){
756 var retval = method.apply(this || window, arguments);
757 fcn.apply(scope || this || window, arguments);
763 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function.
767 * @param {Function} fcn The function to call before the original
768 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769 * @return {Function} The new function
771 createInterceptor : function(fcn, scope){
772 if(typeof fcn != "function"){
779 if(fcn.apply(scope || this || window, arguments) === false){
782 return method.apply(this || window, arguments);
788 * Ext JS Library 1.1.1
789 * Copyright(c) 2006-2007, Ext JS, LLC.
791 * Originally Released Under LGPL - original licence link has changed is not relivant.
794 * <script type="text/javascript">
797 Roo.applyIf(String, {
802 * Escapes the passed string for ' and \
803 * @param {String} string The string to escape
804 * @return {String} The escaped string
807 escape : function(string) {
808 return string.replace(/('|\\)/g, "\\$1");
812 * Pads the left side of a string with a specified character. This is especially useful
813 * for normalizing number and date strings. Example usage:
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
818 * @param {String} string The original string
819 * @param {Number} size The total length of the output string
820 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821 * @return {String} The padded string
824 leftPad : function (val, size, ch) {
825 var result = new String(val);
826 if(ch === null || ch === undefined || ch === '') {
829 while (result.length < size) {
830 result = ch + result;
836 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
837 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
843 * @param {String} string The tokenized string to be formatted
844 * @param {String} value1 The value to replace token {0}
845 * @param {String} value2 Etc...
846 * @return {String} The formatted string
849 format : function(format){
850 var args = Array.prototype.slice.call(arguments, 1);
851 return format.replace(/\{(\d+)\}/g, function(m, i){
852 return Roo.util.Format.htmlEncode(args[i]);
858 * Utility function that allows you to easily switch a string between two alternating values. The passed value
859 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
860 * they are already different, the first value passed in is returned. Note that this method returns the new value
861 * but does not change the current string.
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
869 * @param {String} value The value to compare to the current string
870 * @param {String} other The new value to use if the string already equals the first value passed in
871 * @return {String} The new value
874 String.prototype.toggle = function(value, other){
875 return this == value ? other : value;
878 * Ext JS Library 1.1.1
879 * Copyright(c) 2006-2007, Ext JS, LLC.
881 * Originally Released Under LGPL - original licence link has changed is not relivant.
884 * <script type="text/javascript">
890 Roo.applyIf(Number.prototype, {
892 * Checks whether or not the current number is within a desired range. If the number is already within the
893 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894 * exceeded. Note that this method returns the constrained value but does not change the current number.
895 * @param {Number} min The minimum number in the range
896 * @param {Number} max The maximum number in the range
897 * @return {Number} The constrained value if outside the range, otherwise the current value
899 constrain : function(min, max){
900 return Math.min(Math.max(this, min), max);
904 * Ext JS Library 1.1.1
905 * Copyright(c) 2006-2007, Ext JS, LLC.
907 * Originally Released Under LGPL - original licence link has changed is not relivant.
910 * <script type="text/javascript">
915 Roo.applyIf(Array.prototype, {
917 * Checks whether or not the specified object exists in the array.
918 * @param {Object} o The object to check for
919 * @return {Number} The index of o in the array (or -1 if it is not found)
921 indexOf : function(o){
922 for (var i = 0, len = this.length; i < len; i++){
923 if(this[i] == o) return i;
929 * Removes the specified object from the array. If the object is not found nothing happens.
930 * @param {Object} o The object to remove
932 remove : function(o){
933 var index = this.indexOf(o);
935 this.splice(index, 1);
939 * Map (JS 1.6 compatibility)
940 * @param {Function} function to call
944 var len = this.length >>> 0;
945 if (typeof fun != "function")
946 throw new TypeError();
948 var res = new Array(len);
949 var thisp = arguments[1];
950 for (var i = 0; i < len; i++)
953 res[i] = fun.call(thisp, this[i], i, this);
964 * Ext JS Library 1.1.1
965 * Copyright(c) 2006-2007, Ext JS, LLC.
967 * Originally Released Under LGPL - original licence link has changed is not relivant.
970 * <script type="text/javascript">
976 * The date parsing and format syntax is a subset of
977 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978 * supported will provide results equivalent to their PHP versions.
980 * Following is the list of all currently supported formats:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
985 Format Output Description
986 ------ ---------- --------------------------------------------------------------
987 d 10 Day of the month, 2 digits with leading zeros
988 D Wed A textual representation of a day, three letters
989 j 10 Day of the month without leading zeros
990 l Wednesday A full textual representation of the day of the week
991 S th English ordinal day of month suffix, 2 chars (use with j)
992 w 3 Numeric representation of the day of the week
993 z 9 The julian date, or day of the year (0-365)
994 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995 F January A full textual representation of the month
996 m 01 Numeric representation of a month, with leading zeros
997 M Jan Month name abbreviation, three letters
998 n 1 Numeric representation of a month, without leading zeros
999 t 31 Number of days in the given month
1000 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1001 Y 2007 A full numeric representation of a year, 4 digits
1002 y 07 A two digit representation of a year
1003 a pm Lowercase Ante meridiem and Post meridiem
1004 A PM Uppercase Ante meridiem and Post meridiem
1005 g 3 12-hour format of an hour without leading zeros
1006 G 15 24-hour format of an hour without leading zeros
1007 h 03 12-hour format of an hour with leading zeros
1008 H 15 24-hour format of an hour with leading zeros
1009 i 05 Minutes with leading zeros
1010 s 01 Seconds, with leading zeros
1011 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1013 T CST Timezone setting of the machine running the code
1014 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1017 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d')); //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1022 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
1025 * Here are some standard date/time patterns that you might find helpful. They
1026 * are not part of the source of Date.js, but to use them you can simply copy this
1027 * block of code into any script that is included after Date.js and they will also become
1028 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1031 ISO8601Long:"Y-m-d H:i:s",
1032 ISO8601Short:"Y-m-d",
1034 LongDate: "l, F d, Y",
1035 FullDateTime: "l, F d, Y g:i:s A",
1038 LongTime: "g:i:s A",
1039 SortableDateTime: "Y-m-d\\TH:i:s",
1040 UniversalSortableDateTime: "Y-m-d H:i:sO",
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1053 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054 * They generate precompiled functions from date formats instead of parsing and
1055 * processing the pattern every time you format a date. These functions are available
1056 * on every Date object (any javascript function).
1058 * The original article and download are here:
1059 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1066 Returns the number of milliseconds between this date and date
1067 @param {Date} date (optional) Defaults to now
1068 @return {Number} The diff in milliseconds
1069 @member Date getElapsed
1071 Date.prototype.getElapsed = function(date) {
1072 return Math.abs((date || new Date()).getTime()-this.getTime());
1074 // was in date file..
1078 Date.parseFunctions = {count:0};
1080 Date.parseRegexes = [];
1082 Date.formatFunctions = {count:0};
1085 Date.prototype.dateFormat = function(format) {
1086 if (Date.formatFunctions[format] == null) {
1087 Date.createNewFormat(format);
1089 var func = Date.formatFunctions[format];
1090 return this[func]();
1095 * Formats a date given the supplied format string
1096 * @param {String} format The format string
1097 * @return {String} The formatted date
1100 Date.prototype.format = Date.prototype.dateFormat;
1103 Date.createNewFormat = function(format) {
1104 var funcName = "format" + Date.formatFunctions.count++;
1105 Date.formatFunctions[format] = funcName;
1106 var code = "Date.prototype." + funcName + " = function(){return ";
1107 var special = false;
1109 for (var i = 0; i < format.length; ++i) {
1110 ch = format.charAt(i);
1111 if (!special && ch == "\\") {
1116 code += "'" + String.escape(ch) + "' + ";
1119 code += Date.getFormatCode(ch);
1122 /** eval:var:zzzzzzzzzzzzz */
1123 eval(code.substring(0, code.length - 3) + ";}");
1127 Date.getFormatCode = function(character) {
1128 switch (character) {
1130 return "String.leftPad(this.getDate(), 2, '0') + ";
1132 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1134 return "this.getDate() + ";
1136 return "Date.dayNames[this.getDay()] + ";
1138 return "this.getSuffix() + ";
1140 return "this.getDay() + ";
1142 return "this.getDayOfYear() + ";
1144 return "this.getWeekOfYear() + ";
1146 return "Date.monthNames[this.getMonth()] + ";
1148 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1150 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1152 return "(this.getMonth() + 1) + ";
1154 return "this.getDaysInMonth() + ";
1156 return "(this.isLeapYear() ? 1 : 0) + ";
1158 return "this.getFullYear() + ";
1160 return "('' + this.getFullYear()).substring(2, 4) + ";
1162 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1164 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1166 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1168 return "this.getHours() + ";
1170 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1172 return "String.leftPad(this.getHours(), 2, '0') + ";
1174 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1176 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1178 return "this.getGMTOffset() + ";
1180 return "this.getGMTColonOffset() + ";
1182 return "this.getTimezone() + ";
1184 return "(this.getTimezoneOffset() * -60) + ";
1186 return "'" + String.escape(character) + "' + ";
1191 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1193 * the date format that is not specified will default to the current date value for that part. Time parts can also
1194 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1195 * string or the parse operation will fail.
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1210 * @param {String} input The unparsed date as a string
1211 * @param {String} format The format the date is in
1212 * @return {Date} The parsed date
1215 Date.parseDate = function(input, format) {
1216 if (Date.parseFunctions[format] == null) {
1217 Date.createParser(format);
1219 var func = Date.parseFunctions[format];
1220 return Date[func](input);
1225 Date.createParser = function(format) {
1226 var funcName = "parse" + Date.parseFunctions.count++;
1227 var regexNum = Date.parseRegexes.length;
1228 var currentGroup = 1;
1229 Date.parseFunctions[format] = funcName;
1231 var code = "Date." + funcName + " = function(input){\n"
1232 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233 + "var d = new Date();\n"
1234 + "y = d.getFullYear();\n"
1235 + "m = d.getMonth();\n"
1236 + "d = d.getDate();\n"
1237 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238 + "if (results && results.length > 0) {";
1241 var special = false;
1243 for (var i = 0; i < format.length; ++i) {
1244 ch = format.charAt(i);
1245 if (!special && ch == "\\") {
1250 regex += String.escape(ch);
1253 var obj = Date.formatCodeToRegex(ch, currentGroup);
1254 currentGroup += obj.g;
1256 if (obj.g && obj.c) {
1262 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i, s);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265 + "{v = new Date(y, m, d, h, i);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267 + "{v = new Date(y, m, d, h);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269 + "{v = new Date(y, m, d);}\n"
1270 + "else if (y >= 0 && m >= 0)\n"
1271 + "{v = new Date(y, m);}\n"
1272 + "else if (y >= 0)\n"
1273 + "{v = new Date(y);}\n"
1274 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1279 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280 /** eval:var:zzzzzzzzzzzzz */
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286 switch (character) {
1290 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1293 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294 s:"(\\d{1,2})"}; // day of month without leading zeroes
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{2})"}; // day of month with leading zeroes
1302 s:"(?:" + Date.dayNames.join("|") + ")"};
1306 s:"(?:st|nd|rd|th)"};
1321 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322 s:"(" + Date.monthNames.join("|") + ")"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1329 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1345 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354 c:"if (results[" + currentGroup + "] == 'am') {\n"
1355 + "if (h == 12) { h = 0; }\n"
1356 + "} else { if (h < 12) { h += 12; }}",
1360 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361 + "if (h == 12) { h = 0; }\n"
1362 + "} else { if (h < 12) { h += 12; }}",
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1372 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1376 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385 "o = results[", currentGroup, "];\n",
1386 "var sn = o.substring(0,1);\n", // get + / - sign
1387 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1392 s:"([+\-]\\d{2,4})"};
1398 "o = results[", currentGroup, "];\n",
1399 "var sn = o.substring(0,1);\n",
1400 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401 "var mn = o.substring(4,6) % 60;\n",
1402 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1409 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1412 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418 s:String.escape(character)};
1423 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424 * @return {String} The abbreviated timezone name (e.g. 'CST')
1426 Date.prototype.getTimezone = function() {
1427 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1434 Date.prototype.getGMTOffset = function() {
1435 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442 * @return {String} 2-characters representing hours and 2-characters representing minutes
1443 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1445 Date.prototype.getGMTColonOffset = function() {
1446 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 * Get the numeric day number of the year, adjusted for leap year.
1454 * @return {Number} 0 through 364 (365 in leap years)
1456 Date.prototype.getDayOfYear = function() {
1458 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459 for (var i = 0; i < this.getMonth(); ++i) {
1460 num += Date.daysInMonth[i];
1462 return num + this.getDate() - 1;
1466 * Get the string representation of the numeric week number of the year
1467 * (equivalent to the format specifier 'W').
1468 * @return {String} '00' through '52'
1470 Date.prototype.getWeekOfYear = function() {
1471 // Skip to Thursday of this week
1472 var now = this.getDayOfYear() + (4 - this.getDay());
1473 // Find the first Thursday of the year
1474 var jan1 = new Date(this.getFullYear(), 0, 1);
1475 var then = (7 - jan1.getDay() + 4);
1476 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 * Whether or not the current date is in a leap year.
1481 * @return {Boolean} True if the current date is in a leap year, else false
1483 Date.prototype.isLeapYear = function() {
1484 var year = this.getFullYear();
1485 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 * Get the first day of the current month, adjusted for leap year. The returned value
1490 * is the numeric day index within the week (0-6) which can be used in conjunction with
1491 * the {@link #monthNames} array to retrieve the textual day name.
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1497 * @return {Number} The day number (0-6)
1499 Date.prototype.getFirstDayOfMonth = function() {
1500 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501 return (day < 0) ? (day + 7) : day;
1505 * Get the last day of the current month, adjusted for leap year. The returned value
1506 * is the numeric day index within the week (0-6) which can be used in conjunction with
1507 * the {@link #monthNames} array to retrieve the textual day name.
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1513 * @return {Number} The day number (0-6)
1515 Date.prototype.getLastDayOfMonth = function() {
1516 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517 return (day < 0) ? (day + 7) : day;
1522 * Get the first date of this date's month
1525 Date.prototype.getFirstDateOfMonth = function() {
1526 return new Date(this.getFullYear(), this.getMonth(), 1);
1530 * Get the last date of this date's month
1533 Date.prototype.getLastDateOfMonth = function() {
1534 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1537 * Get the number of days in the current month, adjusted for leap year.
1538 * @return {Number} The number of days in the month
1540 Date.prototype.getDaysInMonth = function() {
1541 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542 return Date.daysInMonth[this.getMonth()];
1546 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547 * @return {String} 'st, 'nd', 'rd' or 'th'
1549 Date.prototype.getSuffix = function() {
1550 switch (this.getDate()) {
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1570 * An array of textual month names.
1571 * Override these values for international dates, for example...
1572 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1591 * An array of textual day names.
1592 * Override these values for international dates, for example...
1593 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1609 Date.monthNumbers = {
1624 * Creates and returns a new Date instance with the exact same date value as the called instance.
1625 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626 * variable will also be changed. When the intention is to create a new variable that will not
1627 * modify the original instance, you should create a clone.
1629 * Example of correctly cloning a date:
1632 var orig = new Date('10/1/2006');
1635 document.write(orig); //returns 'Thu Oct 05 2006'!
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1641 document.write(orig); //returns 'Thu Oct 01 2006'
1643 * @return {Date} The new Date instance
1645 Date.prototype.clone = function() {
1646 return new Date(this.getTime());
1650 * Clears any time information from this date
1651 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652 @return {Date} this or the clone
1654 Date.prototype.clearTime = function(clone){
1656 return this.clone().clearTime();
1661 this.setMilliseconds(0);
1666 // safari setMonth is broken
1668 Date.brokenSetMonth = Date.prototype.setMonth;
1669 Date.prototype.setMonth = function(num){
1671 var n = Math.ceil(-num);
1672 var back_year = Math.ceil(n/12);
1673 var month = (n % 12) ? 12 - n % 12 : 0 ;
1674 this.setFullYear(this.getFullYear() - back_year);
1675 return Date.brokenSetMonth.call(this, month);
1677 return Date.brokenSetMonth.apply(this, arguments);
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1712 * Provides a convenient method of performing basic date arithmetic. This method
1713 * does not modify the Date instance being called - it creates and returns
1714 * a new Date instance containing the resulting date value.
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1731 * @param {String} interval A valid date interval enum value
1732 * @param {Number} value The amount to add to the current date
1733 * @return {Date} The new Date instance
1735 Date.prototype.add = function(interval, value){
1736 var d = this.clone();
1737 if (!interval || value === 0) return d;
1738 switch(interval.toLowerCase()){
1740 d.setMilliseconds(this.getMilliseconds() + value);
1743 d.setSeconds(this.getSeconds() + value);
1746 d.setMinutes(this.getMinutes() + value);
1749 d.setHours(this.getHours() + value);
1752 d.setDate(this.getDate() + value);
1755 var day = this.getDate();
1757 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1760 d.setMonth(this.getMonth() + value);
1763 d.setFullYear(this.getFullYear() + value);
1770 * Ext JS Library 1.1.1
1771 * Copyright(c) 2006-2007, Ext JS, LLC.
1773 * Originally Released Under LGPL - original licence link has changed is not relivant.
1776 * <script type="text/javascript">
1780 * @class Roo.lib.Dom
1783 * Dom utils (from YIU afaik)
1788 * Get the view width
1789 * @param {Boolean} full True will get the full document, otherwise it's the view width
1790 * @return {Number} The width
1793 getViewWidth : function(full) {
1794 return full ? this.getDocumentWidth() : this.getViewportWidth();
1797 * Get the view height
1798 * @param {Boolean} full True will get the full document, otherwise it's the view height
1799 * @return {Number} The height
1801 getViewHeight : function(full) {
1802 return full ? this.getDocumentHeight() : this.getViewportHeight();
1805 getDocumentHeight: function() {
1806 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807 return Math.max(scrollHeight, this.getViewportHeight());
1810 getDocumentWidth: function() {
1811 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812 return Math.max(scrollWidth, this.getViewportWidth());
1815 getViewportHeight: function() {
1816 var height = self.innerHeight;
1817 var mode = document.compatMode;
1819 if ((mode || Roo.isIE) && !Roo.isOpera) {
1820 height = (mode == "CSS1Compat") ?
1821 document.documentElement.clientHeight :
1822 document.body.clientHeight;
1828 getViewportWidth: function() {
1829 var width = self.innerWidth;
1830 var mode = document.compatMode;
1832 if (mode || Roo.isIE) {
1833 width = (mode == "CSS1Compat") ?
1834 document.documentElement.clientWidth :
1835 document.body.clientWidth;
1840 isAncestor : function(p, c) {
1847 if (p.contains && !Roo.isSafari) {
1848 return p.contains(c);
1849 } else if (p.compareDocumentPosition) {
1850 return !!(p.compareDocumentPosition(c) & 16);
1852 var parent = c.parentNode;
1857 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1860 parent = parent.parentNode;
1866 getRegion : function(el) {
1867 return Roo.lib.Region.getRegion(el);
1870 getY : function(el) {
1871 return this.getXY(el)[1];
1874 getX : function(el) {
1875 return this.getXY(el)[0];
1878 getXY : function(el) {
1879 var p, pe, b, scroll, bd = document.body;
1880 el = Roo.getDom(el);
1881 var fly = Roo.lib.AnimBase.fly;
1882 if (el.getBoundingClientRect) {
1883 b = el.getBoundingClientRect();
1884 scroll = fly(document).getScroll();
1885 return [b.left + scroll.left, b.top + scroll.top];
1891 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1898 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1905 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1913 if (p != el && pe.getStyle('overflow') != 'visible') {
1921 if (Roo.isSafari && hasAbsolute) {
1926 if (Roo.isGecko && !hasAbsolute) {
1928 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933 while (p && p != bd) {
1934 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1946 setXY : function(el, xy) {
1947 el = Roo.fly(el, '_setXY');
1949 var pts = el.translatePoints(xy);
1950 if (xy[0] !== false) {
1951 el.dom.style.left = pts.left + "px";
1953 if (xy[1] !== false) {
1954 el.dom.style.top = pts.top + "px";
1958 setX : function(el, x) {
1959 this.setXY(el, [x, false]);
1962 setY : function(el, y) {
1963 this.setXY(el, [false, y]);
1967 * Portions of this file are based on pieces of Yahoo User Interface Library
1968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969 * YUI licensed under the BSD License:
1970 * http://developer.yahoo.net/yui/license.txt
1971 * <script type="text/javascript">
1975 Roo.lib.Event = function() {
1976 var loadComplete = false;
1978 var unloadListeners = [];
1980 var onAvailStack = [];
1982 var lastError = null;
1995 startInterval: function() {
1996 if (!this._interval) {
1998 var callback = function() {
1999 self._tryPreloadAttach();
2001 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007 onAvailStack.push({ id: p_id,
2010 override: p_override,
2011 checkReady: false });
2013 retryCount = this.POLL_RETRYS;
2014 this.startInterval();
2018 addListener: function(el, eventName, fn) {
2019 el = Roo.getDom(el);
2024 if ("unload" == eventName) {
2025 unloadListeners[unloadListeners.length] =
2026 [el, eventName, fn];
2030 var wrappedFn = function(e) {
2031 return fn(Roo.lib.Event.getEvent(e));
2034 var li = [el, eventName, fn, wrappedFn];
2036 var index = listeners.length;
2037 listeners[index] = li;
2039 this.doAdd(el, eventName, wrappedFn, false);
2045 removeListener: function(el, eventName, fn) {
2048 el = Roo.getDom(el);
2051 return this.purgeElement(el, false, eventName);
2055 if ("unload" == eventName) {
2057 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058 var li = unloadListeners[i];
2061 li[1] == eventName &&
2063 unloadListeners.splice(i, 1);
2071 var cacheItem = null;
2074 var index = arguments[3];
2076 if ("undefined" == typeof index) {
2077 index = this._getCacheIndex(el, eventName, fn);
2081 cacheItem = listeners[index];
2084 if (!el || !cacheItem) {
2088 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2090 delete listeners[index][this.WFN];
2091 delete listeners[index][this.FN];
2092 listeners.splice(index, 1);
2099 getTarget: function(ev, resolveTextNode) {
2100 ev = ev.browserEvent || ev;
2101 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2102 var t = ev.target || ev.srcElement;
2103 return this.resolveTextNode(t);
2107 resolveTextNode: function(node) {
2108 if (Roo.isSafari && node && 3 == node.nodeType) {
2109 return node.parentNode;
2116 getPageX: function(ev) {
2117 ev = ev.browserEvent || ev;
2118 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2120 if (!x && 0 !== x) {
2121 x = ev.clientX || 0;
2124 x += this.getScroll()[1];
2132 getPageY: function(ev) {
2133 ev = ev.browserEvent || ev;
2134 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2136 if (!y && 0 !== y) {
2137 y = ev.clientY || 0;
2140 y += this.getScroll()[0];
2149 getXY: function(ev) {
2150 ev = ev.browserEvent || ev;
2151 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 return [this.getPageX(ev), this.getPageY(ev)];
2156 getRelatedTarget: function(ev) {
2157 ev = ev.browserEvent || ev;
2158 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 var t = ev.relatedTarget;
2161 if (ev.type == "mouseout") {
2163 } else if (ev.type == "mouseover") {
2168 return this.resolveTextNode(t);
2172 getTime: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2176 var t = new Date().getTime();
2180 this.lastError = ex;
2189 stopEvent: function(ev) {
2190 this.stopPropagation(ev);
2191 this.preventDefault(ev);
2195 stopPropagation: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 if (ev.stopPropagation) {
2198 ev.stopPropagation();
2200 ev.cancelBubble = true;
2205 preventDefault: function(ev) {
2206 ev = ev.browserEvent || ev;
2207 if(ev.preventDefault) {
2208 ev.preventDefault();
2210 ev.returnValue = false;
2215 getEvent: function(e) {
2216 var ev = e || window.event;
2218 var c = this.getEvent.caller;
2220 ev = c.arguments[0];
2221 if (ev && Event == ev.constructor) {
2231 getCharCode: function(ev) {
2232 ev = ev.browserEvent || ev;
2233 return ev.charCode || ev.keyCode || 0;
2237 _getCacheIndex: function(el, eventName, fn) {
2238 for (var i = 0,len = listeners.length; i < len; ++i) {
2239 var li = listeners[i];
2241 li[this.FN] == fn &&
2242 li[this.EL] == el &&
2243 li[this.TYPE] == eventName) {
2255 getEl: function(id) {
2256 return document.getElementById(id);
2260 clearCache: function() {
2264 _load: function(e) {
2265 loadComplete = true;
2266 var EU = Roo.lib.Event;
2270 EU.doRemove(window, "load", EU._load);
2275 _tryPreloadAttach: function() {
2284 var tryAgain = !loadComplete;
2286 tryAgain = (retryCount > 0);
2291 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292 var item = onAvailStack[i];
2294 var el = this.getEl(item.id);
2297 if (!item.checkReady ||
2300 (document && document.body)) {
2303 if (item.override) {
2304 if (item.override === true) {
2307 scope = item.override;
2310 item.fn.call(scope, item.obj);
2311 onAvailStack[i] = null;
2314 notAvail.push(item);
2319 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323 this.startInterval();
2325 clearInterval(this._interval);
2326 this._interval = null;
2329 this.locked = false;
2336 purgeElement: function(el, recurse, eventName) {
2337 var elListeners = this.getListeners(el, eventName);
2339 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340 var l = elListeners[i];
2341 this.removeListener(el, l.type, l.fn);
2345 if (recurse && el && el.childNodes) {
2346 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347 this.purgeElement(el.childNodes[i], recurse, eventName);
2353 getListeners: function(el, eventName) {
2354 var results = [], searchLists;
2356 searchLists = [listeners, unloadListeners];
2357 } else if (eventName == "unload") {
2358 searchLists = [unloadListeners];
2360 searchLists = [listeners];
2363 for (var j = 0; j < searchLists.length; ++j) {
2364 var searchList = searchLists[j];
2365 if (searchList && searchList.length > 0) {
2366 for (var i = 0,len = searchList.length; i < len; ++i) {
2367 var l = searchList[i];
2368 if (l && l[this.EL] === el &&
2369 (!eventName || eventName === l[this.TYPE])) {
2374 adjust: l[this.ADJ_SCOPE],
2382 return (results.length) ? results : null;
2386 _unload: function(e) {
2388 var EU = Roo.lib.Event, i, j, l, len, index;
2390 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391 l = unloadListeners[i];
2394 if (l[EU.ADJ_SCOPE]) {
2395 if (l[EU.ADJ_SCOPE] === true) {
2398 scope = l[EU.ADJ_SCOPE];
2401 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402 unloadListeners[i] = null;
2408 unloadListeners = null;
2410 if (listeners && listeners.length > 0) {
2411 j = listeners.length;
2414 l = listeners[index];
2416 EU.removeListener(l[EU.EL], l[EU.TYPE],
2426 EU.doRemove(window, "unload", EU._unload);
2431 getScroll: function() {
2432 var dd = document.documentElement, db = document.body;
2433 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434 return [dd.scrollTop, dd.scrollLeft];
2436 return [db.scrollTop, db.scrollLeft];
2443 doAdd: function () {
2444 if (window.addEventListener) {
2445 return function(el, eventName, fn, capture) {
2446 el.addEventListener(eventName, fn, (capture));
2448 } else if (window.attachEvent) {
2449 return function(el, eventName, fn, capture) {
2450 el.attachEvent("on" + eventName, fn);
2459 doRemove: function() {
2460 if (window.removeEventListener) {
2461 return function (el, eventName, fn, capture) {
2462 el.removeEventListener(eventName, fn, (capture));
2464 } else if (window.detachEvent) {
2465 return function (el, eventName, fn) {
2466 el.detachEvent("on" + eventName, fn);
2478 var E = Roo.lib.Event;
2479 E.on = E.addListener;
2480 E.un = E.removeListener;
2482 if (document && document.body) {
2485 E.doAdd(window, "load", E._load);
2487 E.doAdd(window, "unload", E._unload);
2488 E._tryPreloadAttach();
2492 * Portions of this file are based on pieces of Yahoo User Interface Library
2493 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494 * YUI licensed under the BSD License:
2495 * http://developer.yahoo.net/yui/license.txt
2496 * <script type="text/javascript">
2502 * @class Roo.lib.Ajax
2509 request : function(method, uri, cb, data, options) {
2511 var hs = options.headers;
2514 if(hs.hasOwnProperty(h)){
2515 this.initHeader(h, hs[h], false);
2519 if(options.xmlData){
2520 this.initHeader('Content-Type', 'text/xml', false);
2522 data = options.xmlData;
2526 return this.asyncRequest(method, uri, cb, data);
2529 serializeForm : function(form) {
2530 if(typeof form == 'string') {
2531 form = (document.getElementById(form) || document.forms[form]);
2534 var el, name, val, disabled, data = '', hasSubmit = false;
2535 for (var i = 0; i < form.elements.length; i++) {
2536 el = form.elements[i];
2537 disabled = form.elements[i].disabled;
2538 name = form.elements[i].name;
2539 val = form.elements[i].value;
2541 if (!disabled && name){
2545 case 'select-multiple':
2546 for (var j = 0; j < el.options.length; j++) {
2547 if (el.options[j].selected) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2560 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573 if(hasSubmit == false) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584 data = data.substr(0, data.length - 1);
2592 useDefaultHeader:true,
2594 defaultPostHeader:'application/x-www-form-urlencoded',
2596 useDefaultXhrHeader:true,
2598 defaultXhrHeader:'XMLHttpRequest',
2600 hasDefaultHeaders:true,
2612 setProgId:function(id)
2614 this.activeX.unshift(id);
2617 setDefaultPostHeader:function(b)
2619 this.useDefaultHeader = b;
2622 setDefaultXhrHeader:function(b)
2624 this.useDefaultXhrHeader = b;
2627 setPollingInterval:function(i)
2629 if (typeof i == 'number' && isFinite(i)) {
2630 this.pollInterval = i;
2634 createXhrObject:function(transactionId)
2640 http = new XMLHttpRequest();
2642 obj = { conn:http, tId:transactionId };
2646 for (var i = 0; i < this.activeX.length; ++i) {
2650 http = new ActiveXObject(this.activeX[i]);
2652 obj = { conn:http, tId:transactionId };
2665 getConnectionObject:function()
2668 var tId = this.transactionId;
2672 o = this.createXhrObject(tId);
2674 this.transactionId++;
2685 asyncRequest:function(method, uri, callback, postData)
2687 var o = this.getConnectionObject();
2693 o.conn.open(method, uri, true);
2695 if (this.useDefaultXhrHeader) {
2696 if (!this.defaultHeaders['X-Requested-With']) {
2697 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701 if(postData && this.useDefaultHeader){
2702 this.initHeader('Content-Type', this.defaultPostHeader);
2705 if (this.hasDefaultHeaders || this.hasHeaders) {
2709 this.handleReadyState(o, callback);
2710 o.conn.send(postData || null);
2716 handleReadyState:function(o, callback)
2720 if (callback && callback.timeout) {
2722 this.timeout[o.tId] = window.setTimeout(function() {
2723 oConn.abort(o, callback, true);
2724 }, callback.timeout);
2727 this.poll[o.tId] = window.setInterval(
2729 if (o.conn && o.conn.readyState == 4) {
2730 window.clearInterval(oConn.poll[o.tId]);
2731 delete oConn.poll[o.tId];
2733 if(callback && callback.timeout) {
2734 window.clearTimeout(oConn.timeout[o.tId]);
2735 delete oConn.timeout[o.tId];
2738 oConn.handleTransactionResponse(o, callback);
2741 , this.pollInterval);
2744 handleTransactionResponse:function(o, callback, isAbort)
2748 this.releaseObject(o);
2752 var httpStatus, responseObject;
2756 if (o.conn.status !== undefined && o.conn.status != 0) {
2757 httpStatus = o.conn.status;
2769 if (httpStatus >= 200 && httpStatus < 300) {
2770 responseObject = this.createResponseObject(o, callback.argument);
2771 if (callback.success) {
2772 if (!callback.scope) {
2773 callback.success(responseObject);
2778 callback.success.apply(callback.scope, [responseObject]);
2783 switch (httpStatus) {
2791 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792 if (callback.failure) {
2793 if (!callback.scope) {
2794 callback.failure(responseObject);
2797 callback.failure.apply(callback.scope, [responseObject]);
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.failure) {
2804 if (!callback.scope) {
2805 callback.failure(responseObject);
2808 callback.failure.apply(callback.scope, [responseObject]);
2814 this.releaseObject(o);
2815 responseObject = null;
2818 createResponseObject:function(o, callbackArg)
2825 var headerStr = o.conn.getAllResponseHeaders();
2826 var header = headerStr.split('\n');
2827 for (var i = 0; i < header.length; i++) {
2828 var delimitPos = header[i].indexOf(':');
2829 if (delimitPos != -1) {
2830 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2838 obj.status = o.conn.status;
2839 obj.statusText = o.conn.statusText;
2840 obj.getResponseHeader = headerObj;
2841 obj.getAllResponseHeaders = headerStr;
2842 obj.responseText = o.conn.responseText;
2843 obj.responseXML = o.conn.responseXML;
2845 if (typeof callbackArg !== undefined) {
2846 obj.argument = callbackArg;
2852 createExceptionObject:function(tId, callbackArg, isAbort)
2855 var COMM_ERROR = 'communication failure';
2856 var ABORT_CODE = -1;
2857 var ABORT_ERROR = 'transaction aborted';
2863 obj.status = ABORT_CODE;
2864 obj.statusText = ABORT_ERROR;
2867 obj.status = COMM_CODE;
2868 obj.statusText = COMM_ERROR;
2872 obj.argument = callbackArg;
2878 initHeader:function(label, value, isDefault)
2880 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2882 if (headerObj[label] === undefined) {
2883 headerObj[label] = value;
2888 headerObj[label] = value + "," + headerObj[label];
2892 this.hasDefaultHeaders = true;
2895 this.hasHeaders = true;
2900 setHeader:function(o)
2902 if (this.hasDefaultHeaders) {
2903 for (var prop in this.defaultHeaders) {
2904 if (this.defaultHeaders.hasOwnProperty(prop)) {
2905 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910 if (this.hasHeaders) {
2911 for (var prop in this.headers) {
2912 if (this.headers.hasOwnProperty(prop)) {
2913 o.conn.setRequestHeader(prop, this.headers[prop]);
2917 this.hasHeaders = false;
2921 resetDefaultHeaders:function() {
2922 delete this.defaultHeaders;
2923 this.defaultHeaders = {};
2924 this.hasDefaultHeaders = false;
2927 abort:function(o, callback, isTimeout)
2929 if(this.isCallInProgress(o)) {
2931 window.clearInterval(this.poll[o.tId]);
2932 delete this.poll[o.tId];
2934 delete this.timeout[o.tId];
2937 this.handleTransactionResponse(o, callback, true);
2947 isCallInProgress:function(o)
2950 return o.conn.readyState != 4 && o.conn.readyState != 0;
2959 releaseObject:function(o)
2968 'MSXML2.XMLHTTP.3.0',
2976 * Portions of this file are based on pieces of Yahoo User Interface Library
2977 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978 * YUI licensed under the BSD License:
2979 * http://developer.yahoo.net/yui/license.txt
2980 * <script type="text/javascript">
2984 Roo.lib.Region = function(t, r, b, l) {
2994 Roo.lib.Region.prototype = {
2995 contains : function(region) {
2996 return ( region.left >= this.left &&
2997 region.right <= this.right &&
2998 region.top >= this.top &&
2999 region.bottom <= this.bottom );
3003 getArea : function() {
3004 return ( (this.bottom - this.top) * (this.right - this.left) );
3007 intersect : function(region) {
3008 var t = Math.max(this.top, region.top);
3009 var r = Math.min(this.right, region.right);
3010 var b = Math.min(this.bottom, region.bottom);
3011 var l = Math.max(this.left, region.left);
3013 if (b >= t && r >= l) {
3014 return new Roo.lib.Region(t, r, b, l);
3019 union : function(region) {
3020 var t = Math.min(this.top, region.top);
3021 var r = Math.max(this.right, region.right);
3022 var b = Math.max(this.bottom, region.bottom);
3023 var l = Math.min(this.left, region.left);
3025 return new Roo.lib.Region(t, r, b, l);
3028 adjust : function(t, l, b, r) {
3037 Roo.lib.Region.getRegion = function(el) {
3038 var p = Roo.lib.Dom.getXY(el);
3041 var r = p[0] + el.offsetWidth;
3042 var b = p[1] + el.offsetHeight;
3045 return new Roo.lib.Region(t, r, b, l);
3048 * Portions of this file are based on pieces of Yahoo User Interface Library
3049 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050 * YUI licensed under the BSD License:
3051 * http://developer.yahoo.net/yui/license.txt
3052 * <script type="text/javascript">
3055 //@@dep Roo.lib.Region
3058 Roo.lib.Point = function(x, y) {
3059 if (x instanceof Array) {
3063 this.x = this.right = this.left = this[0] = x;
3064 this.y = this.top = this.bottom = this[1] = y;
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3069 * Portions of this file are based on pieces of Yahoo User Interface Library
3070 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071 * YUI licensed under the BSD License:
3072 * http://developer.yahoo.net/yui/license.txt
3073 * <script type="text/javascript">
3080 scroll : function(el, args, duration, easing, cb, scope) {
3081 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3084 motion : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3088 color : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3092 run : function(el, args, duration, easing, cb, scope, type) {
3093 type = type || Roo.lib.AnimBase;
3094 if (typeof easing == "string") {
3095 easing = Roo.lib.Easing[easing];
3097 var anim = new type(el, args, duration, easing);
3098 anim.animateX(function() {
3099 Roo.callback(cb, scope);
3105 * Portions of this file are based on pieces of Yahoo User Interface Library
3106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107 * YUI licensed under the BSD License:
3108 * http://developer.yahoo.net/yui/license.txt
3109 * <script type="text/javascript">
3117 if (!libFlyweight) {
3118 libFlyweight = new Roo.Element.Flyweight();
3120 libFlyweight.dom = el;
3121 return libFlyweight;
3124 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3130 this.init(el, attributes, duration, method);
3134 Roo.lib.AnimBase.fly = fly;
3138 Roo.lib.AnimBase.prototype = {
3140 toString: function() {
3141 var el = this.getEl();
3142 var id = el.id || el.tagName;
3143 return ("Anim " + id);
3147 noNegatives: /width|height|opacity|padding/i,
3148 offsetAttribute: /^((width|height)|(top|left))$/,
3149 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3150 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154 doMethod: function(attr, start, end) {
3155 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159 setAttribute: function(attr, val, unit) {
3160 if (this.patterns.noNegatives.test(attr)) {
3161 val = (val > 0) ? val : 0;
3164 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168 getAttribute: function(attr) {
3169 var el = this.getEl();
3170 var val = fly(el).getStyle(attr);
3172 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173 return parseFloat(val);
3176 var a = this.patterns.offsetAttribute.exec(attr) || [];
3177 var pos = !!( a[3] );
3178 var box = !!( a[2] );
3181 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3191 getDefaultUnit: function(attr) {
3192 if (this.patterns.defaultUnit.test(attr)) {
3199 animateX : function(callback, scope) {
3200 var f = function() {
3201 this.onComplete.removeListener(f);
3202 if (typeof callback == "function") {
3203 callback.call(scope || this, this);
3206 this.onComplete.addListener(f, this);
3211 setRuntimeAttribute: function(attr) {
3214 var attributes = this.attributes;
3216 this.runtimeAttributes[attr] = {};
3218 var isset = function(prop) {
3219 return (typeof prop !== 'undefined');
3222 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3229 if (isset(attributes[attr]['to'])) {
3230 end = attributes[attr]['to'];
3231 } else if (isset(attributes[attr]['by'])) {
3232 if (start.constructor == Array) {
3234 for (var i = 0, len = start.length; i < len; ++i) {
3235 end[i] = start[i] + attributes[attr]['by'][i];
3238 end = start + attributes[attr]['by'];
3242 this.runtimeAttributes[attr].start = start;
3243 this.runtimeAttributes[attr].end = end;
3246 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250 init: function(el, attributes, duration, method) {
3252 var isAnimated = false;
3255 var startTime = null;
3258 var actualFrames = 0;
3261 el = Roo.getDom(el);
3264 this.attributes = attributes || {};
3267 this.duration = duration || 1;
3270 this.method = method || Roo.lib.Easing.easeNone;
3273 this.useSeconds = true;
3276 this.currentFrame = 0;
3279 this.totalFrames = Roo.lib.AnimMgr.fps;
3282 this.getEl = function() {
3287 this.isAnimated = function() {
3292 this.getStartTime = function() {
3296 this.runtimeAttributes = {};
3299 this.animate = function() {
3300 if (this.isAnimated()) {
3304 this.currentFrame = 0;
3306 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3308 Roo.lib.AnimMgr.registerElement(this);
3312 this.stop = function(finish) {
3314 this.currentFrame = this.totalFrames;
3315 this._onTween.fire();
3317 Roo.lib.AnimMgr.stop(this);
3320 var onStart = function() {
3321 this.onStart.fire();
3323 this.runtimeAttributes = {};
3324 for (var attr in this.attributes) {
3325 this.setRuntimeAttribute(attr);
3330 startTime = new Date();
3334 var onTween = function() {
3336 duration: new Date() - this.getStartTime(),
3337 currentFrame: this.currentFrame
3340 data.toString = function() {
3342 'duration: ' + data.duration +
3343 ', currentFrame: ' + data.currentFrame
3347 this.onTween.fire(data);
3349 var runtimeAttributes = this.runtimeAttributes;
3351 for (var attr in runtimeAttributes) {
3352 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3358 var onComplete = function() {
3359 var actual_duration = (new Date() - startTime) / 1000 ;
3362 duration: actual_duration,
3363 frames: actualFrames,
3364 fps: actualFrames / actual_duration
3367 data.toString = function() {
3369 'duration: ' + data.duration +
3370 ', frames: ' + data.frames +
3371 ', fps: ' + data.fps
3377 this.onComplete.fire(data);
3381 this._onStart = new Roo.util.Event(this);
3382 this.onStart = new Roo.util.Event(this);
3383 this.onTween = new Roo.util.Event(this);
3384 this._onTween = new Roo.util.Event(this);
3385 this.onComplete = new Roo.util.Event(this);
3386 this._onComplete = new Roo.util.Event(this);
3387 this._onStart.addListener(onStart);
3388 this._onTween.addListener(onTween);
3389 this._onComplete.addListener(onComplete);
3394 * Portions of this file are based on pieces of Yahoo User Interface Library
3395 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396 * YUI licensed under the BSD License:
3397 * http://developer.yahoo.net/yui/license.txt
3398 * <script type="text/javascript">
3402 Roo.lib.AnimMgr = new function() {
3419 this.registerElement = function(tween) {
3420 queue[queue.length] = tween;
3422 tween._onStart.fire();
3427 this.unRegister = function(tween, index) {
3428 tween._onComplete.fire();
3429 index = index || getIndex(tween);
3431 queue.splice(index, 1);
3435 if (tweenCount <= 0) {
3441 this.start = function() {
3442 if (thread === null) {
3443 thread = setInterval(this.run, this.delay);
3448 this.stop = function(tween) {
3450 clearInterval(thread);
3452 for (var i = 0, len = queue.length; i < len; ++i) {
3453 if (queue[0].isAnimated()) {
3454 this.unRegister(queue[0], 0);
3463 this.unRegister(tween);
3468 this.run = function() {
3469 for (var i = 0, len = queue.length; i < len; ++i) {
3470 var tween = queue[i];
3471 if (!tween || !tween.isAnimated()) {
3475 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3477 tween.currentFrame += 1;
3479 if (tween.useSeconds) {
3480 correctFrame(tween);
3482 tween._onTween.fire();
3485 Roo.lib.AnimMgr.stop(tween, i);
3490 var getIndex = function(anim) {
3491 for (var i = 0, len = queue.length; i < len; ++i) {
3492 if (queue[i] == anim) {
3500 var correctFrame = function(tween) {
3501 var frames = tween.totalFrames;
3502 var frame = tween.currentFrame;
3503 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504 var elapsed = (new Date() - tween.getStartTime());
3507 if (elapsed < tween.duration * 1000) {
3508 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3510 tweak = frames - (frame + 1);
3512 if (tweak > 0 && isFinite(tweak)) {
3513 if (tween.currentFrame + tweak >= frames) {
3514 tweak = frames - (frame + 1);
3517 tween.currentFrame += tweak;
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3530 Roo.lib.Bezier = new function() {
3532 this.getPosition = function(points, t) {
3533 var n = points.length;
3536 for (var i = 0; i < n; ++i) {
3537 tmp[i] = [points[i][0], points[i][1]];
3540 for (var j = 1; j < n; ++j) {
3541 for (i = 0; i < n - j; ++i) {
3542 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547 return [ tmp[0][0], tmp[0][1] ];
3551 * Portions of this file are based on pieces of Yahoo User Interface Library
3552 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553 * YUI licensed under the BSD License:
3554 * http://developer.yahoo.net/yui/license.txt
3555 * <script type="text/javascript">
3560 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3564 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3566 var fly = Roo.lib.AnimBase.fly;
3568 var superclass = Y.ColorAnim.superclass;
3569 var proto = Y.ColorAnim.prototype;
3571 proto.toString = function() {
3572 var el = this.getEl();
3573 var id = el.id || el.tagName;
3574 return ("ColorAnim " + id);
3577 proto.patterns.color = /color$/i;
3578 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3584 proto.parseColor = function(s) {
3585 if (s.length == 3) {
3589 var c = this.patterns.hex.exec(s);
3590 if (c && c.length == 4) {
3591 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3594 c = this.patterns.rgb.exec(s);
3595 if (c && c.length == 4) {
3596 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3599 c = this.patterns.hex3.exec(s);
3600 if (c && c.length == 4) {
3601 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607 proto.getAttribute = function(attr) {
3608 var el = this.getEl();
3609 if (this.patterns.color.test(attr)) {
3610 var val = fly(el).getStyle(attr);
3612 if (this.patterns.transparent.test(val)) {
3613 var parent = el.parentNode;
3614 val = fly(parent).getStyle(attr);
3616 while (parent && this.patterns.transparent.test(val)) {
3617 parent = parent.parentNode;
3618 val = fly(parent).getStyle(attr);
3619 if (parent.tagName.toUpperCase() == 'HTML') {
3625 val = superclass.getAttribute.call(this, attr);
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3654 proto.doMethod = function(attr, start, end) {
3657 if (this.patterns.color.test(attr)) {
3659 for (var i = 0, len = start.length; i < len; ++i) {
3660 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3663 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3666 val = superclass.doMethod.call(this, attr, start, end);
3672 proto.setRuntimeAttribute = function(attr) {
3673 superclass.setRuntimeAttribute.call(this, attr);
3675 if (this.patterns.color.test(attr)) {
3676 var attributes = this.attributes;
3677 var start = this.parseColor(this.runtimeAttributes[attr].start);
3678 var end = this.parseColor(this.runtimeAttributes[attr].end);
3680 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681 end = this.parseColor(attributes[attr].by);
3683 for (var i = 0, len = start.length; i < len; ++i) {
3684 end[i] = start[i] + end[i];
3688 this.runtimeAttributes[attr].start = start;
3689 this.runtimeAttributes[attr].end = end;
3695 * Portions of this file are based on pieces of Yahoo User Interface Library
3696 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697 * YUI licensed under the BSD License:
3698 * http://developer.yahoo.net/yui/license.txt
3699 * <script type="text/javascript">
3705 easeNone: function (t, b, c, d) {
3706 return c * t / d + b;
3710 easeIn: function (t, b, c, d) {
3711 return c * (t /= d) * t + b;
3715 easeOut: function (t, b, c, d) {
3716 return -c * (t /= d) * (t - 2) + b;
3720 easeBoth: function (t, b, c, d) {
3721 if ((t /= d / 2) < 1) {
3722 return c / 2 * t * t + b;
3725 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729 easeInStrong: function (t, b, c, d) {
3730 return c * (t /= d) * t * t * t + b;
3734 easeOutStrong: function (t, b, c, d) {
3735 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739 easeBothStrong: function (t, b, c, d) {
3740 if ((t /= d / 2) < 1) {
3741 return c / 2 * t * t * t * t + b;
3744 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749 elasticIn: function (t, b, c, d, a, p) {
3753 if ((t /= d) == 1) {
3760 if (!a || a < Math.abs(c)) {
3765 var s = p / (2 * Math.PI) * Math.asin(c / a);
3768 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772 elasticOut: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795 elasticBoth: function (t, b, c, d, a, p) {
3800 if ((t /= d / 2) == 2) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3817 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3820 return a * Math.pow(2, -10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826 backIn: function (t, b, c, d, s) {
3827 if (typeof s == 'undefined') {
3830 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834 backOut: function (t, b, c, d, s) {
3835 if (typeof s == 'undefined') {
3838 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842 backBoth: function (t, b, c, d, s) {
3843 if (typeof s == 'undefined') {
3847 if ((t /= d / 2 ) < 1) {
3848 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3850 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854 bounceIn: function (t, b, c, d) {
3855 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859 bounceOut: function (t, b, c, d) {
3860 if ((t /= d) < (1 / 2.75)) {
3861 return c * (7.5625 * t * t) + b;
3862 } else if (t < (2 / 2.75)) {
3863 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864 } else if (t < (2.5 / 2.75)) {
3865 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3867 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871 bounceBoth: function (t, b, c, d) {
3873 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3875 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3878 * Portions of this file are based on pieces of Yahoo User Interface Library
3879 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880 * YUI licensed under the BSD License:
3881 * http://developer.yahoo.net/yui/license.txt
3882 * <script type="text/javascript">
3886 Roo.lib.Motion = function(el, attributes, duration, method) {
3888 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896 var superclass = Y.Motion.superclass;
3897 var proto = Y.Motion.prototype;
3899 proto.toString = function() {
3900 var el = this.getEl();
3901 var id = el.id || el.tagName;
3902 return ("Motion " + id);
3905 proto.patterns.points = /^points$/i;
3907 proto.setAttribute = function(attr, val, unit) {
3908 if (this.patterns.points.test(attr)) {
3909 unit = unit || 'px';
3910 superclass.setAttribute.call(this, 'left', val[0], unit);
3911 superclass.setAttribute.call(this, 'top', val[1], unit);
3913 superclass.setAttribute.call(this, attr, val, unit);
3917 proto.getAttribute = function(attr) {
3918 if (this.patterns.points.test(attr)) {
3920 superclass.getAttribute.call(this, 'left'),
3921 superclass.getAttribute.call(this, 'top')
3924 val = superclass.getAttribute.call(this, attr);
3930 proto.doMethod = function(attr, start, end) {
3933 if (this.patterns.points.test(attr)) {
3934 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3937 val = superclass.doMethod.call(this, attr, start, end);
3942 proto.setRuntimeAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3944 var el = this.getEl();
3945 var attributes = this.attributes;
3947 var control = attributes['points']['control'] || [];
3951 if (control.length > 0 && !(control[0] instanceof Array)) {
3952 control = [control];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 tmp[i] = control[i];
3961 Roo.fly(el).position();
3963 if (isset(attributes['points']['from'])) {
3964 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3967 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3970 start = this.getAttribute('points');
3973 if (isset(attributes['points']['to'])) {
3974 end = translateValues.call(this, attributes['points']['to'], start);
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 for (i = 0,len = control.length; i < len; ++i) {
3978 control[i] = translateValues.call(this, control[i], start);
3982 } else if (isset(attributes['points']['by'])) {
3983 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3985 for (i = 0,len = control.length; i < len; ++i) {
3986 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990 this.runtimeAttributes[attr] = [start];
3992 if (control.length > 0) {
3993 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3996 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3999 superclass.setRuntimeAttribute.call(this, attr);
4003 var translateValues = function(val, start) {
4004 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010 var isset = function(prop) {
4011 return (typeof prop !== 'undefined');
4015 * Portions of this file are based on pieces of Yahoo User Interface Library
4016 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017 * YUI licensed under the BSD License:
4018 * http://developer.yahoo.net/yui/license.txt
4019 * <script type="text/javascript">
4023 Roo.lib.Scroll = function(el, attributes, duration, method) {
4025 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033 var superclass = Y.Scroll.superclass;
4034 var proto = Y.Scroll.prototype;
4036 proto.toString = function() {
4037 var el = this.getEl();
4038 var id = el.id || el.tagName;
4039 return ("Scroll " + id);
4042 proto.doMethod = function(attr, start, end) {
4045 if (attr == 'scroll') {
4047 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052 val = superclass.doMethod.call(this, attr, start, end);
4057 proto.getAttribute = function(attr) {
4059 var el = this.getEl();
4061 if (attr == 'scroll') {
4062 val = [ el.scrollLeft, el.scrollTop ];
4064 val = superclass.getAttribute.call(this, attr);
4070 proto.setAttribute = function(attr, val, unit) {
4071 var el = this.getEl();
4073 if (attr == 'scroll') {
4074 el.scrollLeft = val[0];
4075 el.scrollTop = val[1];
4077 superclass.setAttribute.call(this, attr, val, unit);
4083 * Ext JS Library 1.1.1
4084 * Copyright(c) 2006-2007, Ext JS, LLC.
4086 * Originally Released Under LGPL - original licence link has changed is not relivant.
4089 * <script type="text/javascript">
4093 // nasty IE9 hack - what a pile of crap that is..
4095 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096 Range.prototype.createContextualFragment = function (html) {
4097 var doc = window.document;
4098 var container = doc.createElement("div");
4099 container.innerHTML = html;
4100 var frag = doc.createDocumentFragment(), n;
4101 while ((n = container.firstChild)) {
4102 frag.appendChild(n);
4109 * @class Roo.DomHelper
4110 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111 * 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>.
4114 Roo.DomHelper = function(){
4115 var tempTableEl = null;
4116 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117 var tableRe = /^table|tbody|tr|td$/i;
4119 // build as innerHTML where available
4121 var createHtml = function(o){
4122 if(typeof o == 'string'){
4131 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132 if(attr == "style"){
4134 if(typeof s == "function"){
4137 if(typeof s == "string"){
4138 b += ' style="' + s + '"';
4139 }else if(typeof s == "object"){
4142 if(typeof s[key] != "function"){
4143 b += key + ":" + s[key] + ";";
4150 b += ' class="' + o["cls"] + '"';
4151 }else if(attr == "htmlFor"){
4152 b += ' for="' + o["htmlFor"] + '"';
4154 b += " " + attr + '="' + o[attr] + '"';
4158 if(emptyTags.test(o.tag)){
4162 var cn = o.children || o.cn;
4164 //http://bugs.kde.org/show_bug.cgi?id=71506
4165 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166 for(var i = 0, len = cn.length; i < len; i++) {
4167 b += createHtml(cn[i], b);
4170 b += createHtml(cn, b);
4176 b += "</" + o.tag + ">";
4183 var createDom = function(o, parentNode){
4185 // defininition craeted..
4187 if (o.ns && o.ns != 'html') {
4189 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190 xmlns[o.ns] = o.xmlns;
4193 if (typeof(xmlns[o.ns]) == 'undefined') {
4194 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4200 if (typeof(o) == 'string') {
4201 return parentNode.appendChild(document.createTextNode(o));
4203 o.tag = o.tag || div;
4204 if (o.ns && Roo.isIE) {
4206 o.tag = o.ns + ':' + o.tag;
4209 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4210 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4213 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4214 attr == "style" || typeof o[attr] == "function") continue;
4216 if(attr=="cls" && Roo.isIE){
4217 el.className = o["cls"];
4219 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220 else el[attr] = o[attr];
4223 Roo.DomHelper.applyStyles(el, o.style);
4224 var cn = o.children || o.cn;
4226 //http://bugs.kde.org/show_bug.cgi?id=71506
4227 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228 for(var i = 0, len = cn.length; i < len; i++) {
4229 createDom(cn[i], el);
4236 el.innerHTML = o.html;
4239 parentNode.appendChild(el);
4244 var ieTable = function(depth, s, h, e){
4245 tempTableEl.innerHTML = [s, h, e].join('');
4246 var i = -1, el = tempTableEl;
4253 // kill repeat to save bytes
4257 tbe = '</tbody>'+te,
4263 * Nasty code for IE's broken table implementation
4265 var insertIntoTable = function(tag, where, el, html){
4267 tempTableEl = document.createElement('div');
4272 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4275 if(where == 'beforebegin'){
4279 before = el.nextSibling;
4282 node = ieTable(4, trs, html, tre);
4284 else if(tag == 'tr'){
4285 if(where == 'beforebegin'){
4288 node = ieTable(3, tbs, html, tbe);
4289 } else if(where == 'afterend'){
4290 before = el.nextSibling;
4292 node = ieTable(3, tbs, html, tbe);
4293 } else{ // INTO a TR
4294 if(where == 'afterbegin'){
4295 before = el.firstChild;
4297 node = ieTable(4, trs, html, tre);
4299 } else if(tag == 'tbody'){
4300 if(where == 'beforebegin'){
4303 node = ieTable(2, ts, html, te);
4304 } else if(where == 'afterend'){
4305 before = el.nextSibling;
4307 node = ieTable(2, ts, html, te);
4309 if(where == 'afterbegin'){
4310 before = el.firstChild;
4312 node = ieTable(3, tbs, html, tbe);
4315 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4318 if(where == 'afterbegin'){
4319 before = el.firstChild;
4321 node = ieTable(2, ts, html, te);
4323 el.insertBefore(node, before);
4328 /** True to force the use of DOM instead of html fragments @type Boolean */
4332 * Returns the markup for the passed Element(s) config
4333 * @param {Object} o The Dom object spec (and children)
4336 markup : function(o){
4337 return createHtml(o);
4341 * Applies a style specification to an element
4342 * @param {String/HTMLElement} el The element to apply styles to
4343 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344 * a function which returns such a specification.
4346 applyStyles : function(el, styles){
4349 if(typeof styles == "string"){
4350 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4352 while ((matches = re.exec(styles)) != null){
4353 el.setStyle(matches[1], matches[2]);
4355 }else if (typeof styles == "object"){
4356 for (var style in styles){
4357 el.setStyle(style, styles[style]);
4359 }else if (typeof styles == "function"){
4360 Roo.DomHelper.applyStyles(el, styles.call());
4366 * Inserts an HTML fragment into the Dom
4367 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368 * @param {HTMLElement} el The context element
4369 * @param {String} html The HTML fragmenet
4370 * @return {HTMLElement} The new node
4372 insertHtml : function(where, el, html){
4373 where = where.toLowerCase();
4374 if(el.insertAdjacentHTML){
4375 if(tableRe.test(el.tagName)){
4377 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4383 el.insertAdjacentHTML('BeforeBegin', html);
4384 return el.previousSibling;
4386 el.insertAdjacentHTML('AfterBegin', html);
4387 return el.firstChild;
4389 el.insertAdjacentHTML('BeforeEnd', html);
4390 return el.lastChild;
4392 el.insertAdjacentHTML('AfterEnd', html);
4393 return el.nextSibling;
4395 throw 'Illegal insertion point -> "' + where + '"';
4397 var range = el.ownerDocument.createRange();
4401 range.setStartBefore(el);
4402 frag = range.createContextualFragment(html);
4403 el.parentNode.insertBefore(frag, el);
4404 return el.previousSibling;
4407 range.setStartBefore(el.firstChild);
4408 frag = range.createContextualFragment(html);
4409 el.insertBefore(frag, el.firstChild);
4410 return el.firstChild;
4412 el.innerHTML = html;
4413 return el.firstChild;
4417 range.setStartAfter(el.lastChild);
4418 frag = range.createContextualFragment(html);
4419 el.appendChild(frag);
4420 return el.lastChild;
4422 el.innerHTML = html;
4423 return el.lastChild;
4426 range.setStartAfter(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el.nextSibling);
4429 return el.nextSibling;
4431 throw 'Illegal insertion point -> "' + where + '"';
4435 * Creates new Dom element(s) and inserts them before el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertBefore : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "beforeBegin");
4446 * Creates new Dom element(s) and inserts them after el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object} o The Dom object spec (and children)
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertAfter : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457 * Creates new Dom element(s) and inserts them as the first child of el
4458 * @param {String/HTMLElement/Element} el The context element
4459 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461 * @return {HTMLElement/Roo.Element} The new node
4463 insertFirst : function(el, o, returnElement){
4464 return this.doInsert(el, o, returnElement, "afterBegin");
4468 doInsert : function(el, o, returnElement, pos, sibling){
4469 el = Roo.getDom(el);
4471 if(this.useDom || o.ns){
4472 newNode = createDom(o, null);
4473 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4475 var html = createHtml(o);
4476 newNode = this.insertHtml(pos, el, html);
4478 return returnElement ? Roo.get(newNode, true) : newNode;
4482 * Creates new Dom element(s) and appends them to el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 append : function(el, o, returnElement){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.appendChild(newNode);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml("beforeEnd", el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and overwrites the contents of el with them
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 overwrite : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4512 while (el.childNodes.length) {
4513 el.removeChild(el.firstChild);
4517 el.innerHTML = createHtml(o);
4520 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524 * Creates a new Roo.DomHelper.Template from the Dom object spec
4525 * @param {Object} o The Dom object spec (and children)
4526 * @return {Roo.DomHelper.Template} The new template
4528 createTemplate : function(o){
4529 var html = createHtml(o);
4530 return new Roo.Template(html);
4536 * Ext JS Library 1.1.1
4537 * Copyright(c) 2006-2007, Ext JS, LLC.
4539 * Originally Released Under LGPL - original licence link has changed is not relivant.
4542 * <script type="text/javascript">
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4551 var t = new Roo.Template({
4552 html : '<div name="{id}">' +
4553 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4555 myformat: function (value, allValues) {
4556 return 'XX' + value;
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4561 * For more information see this blog post with examples:
4562 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563 - Create Elements using DOM, HTML fragments and Templates</a>.
4565 * @param {Object} cfg - Configuration object.
4567 Roo.Template = function(cfg){
4569 if(cfg instanceof Array){
4571 }else if(arguments.length > 1){
4572 cfg = Array.prototype.join.call(arguments, "");
4576 if (typeof(cfg) == 'object') {
4587 Roo.Template.prototype = {
4590 * @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..
4591 * it should be fixed so that template is observable...
4595 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599 * Returns an HTML fragment of this template with the specified values applied.
4600 * @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'})
4601 * @return {String} The HTML fragment
4603 applyTemplate : function(values){
4607 return this.compiled(values);
4609 var useF = this.disableFormats !== true;
4610 var fm = Roo.util.Format, tpl = this;
4611 var fn = function(m, name, format, args){
4613 if(format.substr(0, 5) == "this."){
4614 return tpl.call(format.substr(5), values[name], values);
4617 // quoted values are required for strings in compiled templates,
4618 // but for non compiled we need to strip them
4619 // quoted reversed for jsmin
4620 var re = /^\s*['"](.*)["']\s*$/;
4621 args = args.split(',');
4622 for(var i = 0, len = args.length; i < len; i++){
4623 args[i] = args[i].replace(re, "$1");
4625 args = [values[name]].concat(args);
4627 args = [values[name]];
4629 return fm[format].apply(fm, args);
4632 return values[name] !== undefined ? values[name] : "";
4635 return this.html.replace(this.re, fn);
4653 this.loading = true;
4654 this.compiled = false;
4656 var cx = new Roo.data.Connection();
4660 success : function (response) {
4662 _t.html = response.responseText;
4666 failure : function(response) {
4667 Roo.log("Template failed to load from " + _t.url);
4674 * Sets the HTML used as the template and optionally compiles it.
4675 * @param {String} html
4676 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677 * @return {Roo.Template} this
4679 set : function(html, compile){
4681 this.compiled = null;
4689 * True to disable format functions (defaults to false)
4692 disableFormats : false,
4695 * The regular expression used to match template variables
4699 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4702 * Compiles the template into an internal function, eliminating the RegEx overhead.
4703 * @return {Roo.Template} this
4705 compile : function(){
4706 var fm = Roo.util.Format;
4707 var useF = this.disableFormats !== true;
4708 var sep = Roo.isGecko ? "+" : ",";
4709 var fn = function(m, name, format, args){
4711 args = args ? ',' + args : "";
4712 if(format.substr(0, 5) != "this."){
4713 format = "fm." + format + '(';
4715 format = 'this.call("'+ format.substr(5) + '", ';
4719 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4721 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4724 // branched to use + in gecko and [].join() in others
4726 body = "this.compiled = function(values){ return '" +
4727 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4730 body = ["this.compiled = function(values){ return ['"];
4731 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732 body.push("'].join('');};");
4733 body = body.join('');
4743 // private function used to call members
4744 call : function(fnName, value, allValues){
4745 return this[fnName](value, allValues);
4749 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @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'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertFirst: function(el, values, returnElement){
4756 return this.doInsert('afterBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) before el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @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'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertBefore: function(el, values, returnElement){
4767 return this.doInsert('beforeBegin', el, values, returnElement);
4771 * Applies the supplied values to the template and inserts the new node(s) after el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @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'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 insertAfter : function(el, values, returnElement){
4778 return this.doInsert('afterEnd', el, values, returnElement);
4782 * Applies the supplied values to the template and appends the new node(s) to el.
4783 * @param {String/HTMLElement/Roo.Element} el The context element
4784 * @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'})
4785 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786 * @return {HTMLElement/Roo.Element} The new node or Element
4788 append : function(el, values, returnElement){
4789 return this.doInsert('beforeEnd', el, values, returnElement);
4792 doInsert : function(where, el, values, returnEl){
4793 el = Roo.getDom(el);
4794 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795 return returnEl ? Roo.get(newNode, true) : newNode;
4799 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800 * @param {String/HTMLElement/Roo.Element} el The context element
4801 * @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'})
4802 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803 * @return {HTMLElement/Roo.Element} The new node or Element
4805 overwrite : function(el, values, returnElement){
4806 el = Roo.getDom(el);
4807 el.innerHTML = this.applyTemplate(values);
4808 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812 * Alias for {@link #applyTemplate}
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4818 Roo.DomHelper.Template = Roo.Template;
4821 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822 * @param {String/HTMLElement} el A DOM element or its id
4823 * @returns {Roo.Template} The created template
4826 Roo.Template.from = function(el){
4827 el = Roo.getDom(el);
4828 return new Roo.Template(el.value || el.innerHTML);
4831 * Ext JS Library 1.1.1
4832 * Copyright(c) 2006-2007, Ext JS, LLC.
4834 * Originally Released Under LGPL - original licence link has changed is not relivant.
4837 * <script type="text/javascript">
4842 * This is code is also distributed under MIT license for use
4843 * with jQuery and prototype JavaScript libraries.
4846 * @class Roo.DomQuery
4847 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).
4849 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>
4852 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.
4854 <h4>Element Selectors:</h4>
4856 <li> <b>*</b> any element</li>
4857 <li> <b>E</b> an element with the tag E</li>
4858 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4866 <li> <b>E[foo]</b> has an attribute "foo"</li>
4867 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4874 <h4>Pseudo Classes:</h4>
4876 <li> <b>E:first-child</b> E is the first child of its parent</li>
4877 <li> <b>E:last-child</b> E is the last child of its parent</li>
4878 <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>
4879 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881 <li> <b>E:only-child</b> E is the only child of its parent</li>
4882 <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>
4883 <li> <b>E:first</b> the first E in the resultset</li>
4884 <li> <b>E:last</b> the last E in the resultset</li>
4885 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4895 <h4>CSS Value Selectors:</h4>
4897 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 Roo.DomQuery = function(){
4907 var cache = {}, simpleCache = {}, valueCache = {};
4908 var nonSpace = /\S/;
4909 var trimRe = /^\s+|\s+$/g;
4910 var tplRe = /\{(\d+)\}/g;
4911 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912 var tagTokenRe = /^(#)?([\w-\*]+)/;
4913 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4915 function child(p, index){
4917 var n = p.firstChild;
4919 if(n.nodeType == 1){
4930 while((n = n.nextSibling) && n.nodeType != 1);
4935 while((n = n.previousSibling) && n.nodeType != 1);
4939 function children(d){
4940 var n = d.firstChild, ni = -1;
4942 var nx = n.nextSibling;
4943 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4953 function byClassName(c, a, v){
4957 var r = [], ri = -1, cn;
4958 for(var i = 0, ci; ci = c[i]; i++){
4959 if((' '+ci.className+' ').indexOf(v) != -1){
4966 function attrValue(n, attr){
4967 if(!n.tagName && typeof n.length != "undefined"){
4976 if(attr == "class" || attr == "className"){
4979 return n.getAttribute(attr) || n[attr];
4983 function getNodes(ns, mode, tagName){
4984 var result = [], ri = -1, cs;
4988 tagName = tagName || "*";
4989 if(typeof ns.getElementsByTagName != "undefined"){
4993 for(var i = 0, ni; ni = ns[i]; i++){
4994 cs = ni.getElementsByTagName(tagName);
4995 for(var j = 0, ci; ci = cs[j]; j++){
4999 }else if(mode == "/" || mode == ">"){
5000 var utag = tagName.toUpperCase();
5001 for(var i = 0, ni, cn; ni = ns[i]; i++){
5002 cn = ni.children || ni.childNodes;
5003 for(var j = 0, cj; cj = cn[j]; j++){
5004 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5009 }else if(mode == "+"){
5010 var utag = tagName.toUpperCase();
5011 for(var i = 0, n; n = ns[i]; i++){
5012 while((n = n.nextSibling) && n.nodeType != 1);
5013 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017 }else if(mode == "~"){
5018 for(var i = 0, n; n = ns[i]; i++){
5019 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5028 function concat(a, b){
5032 for(var i = 0, l = b.length; i < l; i++){
5038 function byTag(cs, tagName){
5039 if(cs.tagName || cs == document){
5045 var r = [], ri = -1;
5046 tagName = tagName.toLowerCase();
5047 for(var i = 0, ci; ci = cs[i]; i++){
5048 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5055 function byId(cs, attr, id){
5056 if(cs.tagName || cs == document){
5062 var r = [], ri = -1;
5063 for(var i = 0,ci; ci = cs[i]; i++){
5064 if(ci && ci.id == id){
5072 function byAttribute(cs, attr, value, op, custom){
5073 var r = [], ri = -1, st = custom=="{";
5074 var f = Roo.DomQuery.operators[op];
5075 for(var i = 0, ci; ci = cs[i]; i++){
5078 a = Roo.DomQuery.getStyle(ci, attr);
5080 else if(attr == "class" || attr == "className"){
5082 }else if(attr == "for"){
5084 }else if(attr == "href"){
5085 a = ci.getAttribute("href", 2);
5087 a = ci.getAttribute(attr);
5089 if((f && f(a, value)) || (!f && a)){
5096 function byPseudo(cs, name, value){
5097 return Roo.DomQuery.pseudos[name](cs, value);
5100 // This is for IE MSXML which does not support expandos.
5101 // IE runs the same speed using setAttribute, however FF slows way down
5102 // and Safari completely fails so they need to continue to use expandos.
5103 var isIE = window.ActiveXObject ? true : false;
5105 // this eval is stop the compressor from
5106 // renaming the variable to something shorter
5108 /** eval:var:batch */
5113 function nodupIEXml(cs){
5115 cs[0].setAttribute("_nodup", d);
5117 for(var i = 1, len = cs.length; i < len; i++){
5119 if(!c.getAttribute("_nodup") != d){
5120 c.setAttribute("_nodup", d);
5124 for(var i = 0, len = cs.length; i < len; i++){
5125 cs[i].removeAttribute("_nodup");
5134 var len = cs.length, c, i, r = cs, cj, ri = -1;
5135 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5138 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139 return nodupIEXml(cs);
5143 for(i = 1; c = cs[i]; i++){
5148 for(var j = 0; j < i; j++){
5151 for(j = i+1; cj = cs[j]; j++){
5163 function quickDiffIEXml(c1, c2){
5165 for(var i = 0, len = c1.length; i < len; i++){
5166 c1[i].setAttribute("_qdiff", d);
5169 for(var i = 0, len = c2.length; i < len; i++){
5170 if(c2[i].getAttribute("_qdiff") != d){
5171 r[r.length] = c2[i];
5174 for(var i = 0, len = c1.length; i < len; i++){
5175 c1[i].removeAttribute("_qdiff");
5180 function quickDiff(c1, c2){
5181 var len1 = c1.length;
5185 if(isIE && c1[0].selectSingleNode){
5186 return quickDiffIEXml(c1, c2);
5189 for(var i = 0; i < len1; i++){
5193 for(var i = 0, len = c2.length; i < len; i++){
5194 if(c2[i]._qdiff != d){
5195 r[r.length] = c2[i];
5201 function quickId(ns, mode, root, id){
5203 var d = root.ownerDocument || root;
5204 return d.getElementById(id);
5206 ns = getNodes(ns, mode, "*");
5207 return byId(ns, null, id);
5211 getStyle : function(el, name){
5212 return Roo.fly(el).getStyle(name);
5215 * Compiles a selector/xpath query into a reusable function. The returned function
5216 * takes one parameter "root" (optional), which is the context node from where the query should start.
5217 * @param {String} selector The selector/xpath query
5218 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219 * @return {Function}
5221 compile : function(path, type){
5222 type = type || "select";
5224 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225 var q = path, mode, lq;
5226 var tk = Roo.DomQuery.matchers;
5227 var tklen = tk.length;
5230 // accept leading mode switch
5231 var lmode = q.match(modeRe);
5232 if(lmode && lmode[1]){
5233 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234 q = q.replace(lmode[1], "");
5236 // strip leading slashes
5237 while(path.substr(0, 1)=="/"){
5238 path = path.substr(1);
5241 while(q && lq != q){
5243 var tm = q.match(tagTokenRe);
5244 if(type == "select"){
5247 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5252 }else if(q.substr(0, 1) != '@'){
5253 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5260 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5262 q = q.replace(tm[0], "");
5265 while(!(mm = q.match(modeRe))){
5266 var matched = false;
5267 for(var j = 0; j < tklen; j++){
5269 var m = q.match(t.re);
5271 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5274 q = q.replace(m[0], "");
5279 // prevent infinite loop on bad selector
5281 throw 'Error parsing selector, parsing failed at "' + q + '"';
5285 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5286 q = q.replace(mm[1], "");
5289 fn[fn.length] = "return nodup(n);\n}";
5292 * list of variables that need from compression as they are used by eval.
5302 * eval:var:byClassName
5304 * eval:var:byAttribute
5305 * eval:var:attrValue
5313 * Selects a group of elements.
5314 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5315 * @param {Node} root (optional) The start of the query (defaults to document).
5318 select : function(path, root, type){
5319 if(!root || root == document){
5322 if(typeof root == "string"){
5323 root = document.getElementById(root);
5325 var paths = path.split(",");
5327 for(var i = 0, len = paths.length; i < len; i++){
5328 var p = paths[i].replace(trimRe, "");
5330 cache[p] = Roo.DomQuery.compile(p);
5332 throw p + " is not a valid selector";
5335 var result = cache[p](root);
5336 if(result && result != document){
5337 results = results.concat(result);
5340 if(paths.length > 1){
5341 return nodup(results);
5347 * Selects a single element.
5348 * @param {String} selector The selector/xpath query
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 selectNode : function(path, root){
5353 return Roo.DomQuery.select(path, root)[0];
5357 * Selects the value of a node, optionally replacing null with the defaultValue.
5358 * @param {String} selector The selector/xpath query
5359 * @param {Node} root (optional) The start of the query (defaults to document).
5360 * @param {String} defaultValue
5362 selectValue : function(path, root, defaultValue){
5363 path = path.replace(trimRe, "");
5364 if(!valueCache[path]){
5365 valueCache[path] = Roo.DomQuery.compile(path, "select");
5367 var n = valueCache[path](root);
5368 n = n[0] ? n[0] : n;
5369 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5370 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374 * Selects the value of a node, parsing integers and floats.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5377 * @param {Number} defaultValue
5380 selectNumber : function(path, root, defaultValue){
5381 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5382 return parseFloat(v);
5386 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5387 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5388 * @param {String} selector The simple selector to test
5391 is : function(el, ss){
5392 if(typeof el == "string"){
5393 el = document.getElementById(el);
5395 var isArray = (el instanceof Array);
5396 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5397 return isArray ? (result.length == el.length) : (result.length > 0);
5401 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5402 * @param {Array} el An array of elements to filter
5403 * @param {String} selector The simple selector to test
5404 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5405 * the selector instead of the ones that match
5408 filter : function(els, ss, nonMatches){
5409 ss = ss.replace(trimRe, "");
5410 if(!simpleCache[ss]){
5411 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5413 var result = simpleCache[ss](els);
5414 return nonMatches ? quickDiff(result, els) : result;
5418 * Collection of matching regular expressions and code snippets.
5422 select: 'n = byClassName(n, null, " {1} ");'
5424 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5425 select: 'n = byPseudo(n, "{1}", "{2}");'
5427 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5428 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5431 select: 'n = byId(n, null, "{1}");'
5434 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5440 * 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, > <.
5443 "=" : function(a, v){
5446 "!=" : function(a, v){
5449 "^=" : function(a, v){
5450 return a && a.substr(0, v.length) == v;
5452 "$=" : function(a, v){
5453 return a && a.substr(a.length-v.length) == v;
5455 "*=" : function(a, v){
5456 return a && a.indexOf(v) !== -1;
5458 "%=" : function(a, v){
5459 return (a % v) == 0;
5461 "|=" : function(a, v){
5462 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5464 "~=" : function(a, v){
5465 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5471 * and the argument (if any) supplied in the selector.
5474 "first-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.previousSibling) && n.nodeType != 1);
5485 "last-child" : function(c){
5486 var r = [], ri = -1, n;
5487 for(var i = 0, ci; ci = n = c[i]; i++){
5488 while((n = n.nextSibling) && n.nodeType != 1);
5496 "nth-child" : function(c, a) {
5497 var r = [], ri = -1;
5498 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5499 var f = (m[1] || 1) - 0, l = m[2] - 0;
5500 for(var i = 0, n; n = c[i]; i++){
5501 var pn = n.parentNode;
5502 if (batch != pn._batch) {
5504 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5505 if(cn.nodeType == 1){
5512 if (l == 0 || n.nodeIndex == l){
5515 } else if ((n.nodeIndex + l) % f == 0){
5523 "only-child" : function(c){
5524 var r = [], ri = -1;;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if(!prev(ci) && !next(ci)){
5533 "empty" : function(c){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 var cns = ci.childNodes, j = 0, cn, empty = true;
5539 if(cn.nodeType == 1 || cn.nodeType == 3){
5551 "contains" : function(c, v){
5552 var r = [], ri = -1;
5553 for(var i = 0, ci; ci = c[i]; i++){
5554 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5561 "nodeValue" : function(c, v){
5562 var r = [], ri = -1;
5563 for(var i = 0, ci; ci = c[i]; i++){
5564 if(ci.firstChild && ci.firstChild.nodeValue == v){
5571 "checked" : function(c){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if(ci.checked == true){
5581 "not" : function(c, ss){
5582 return Roo.DomQuery.filter(c, ss, true);
5585 "odd" : function(c){
5586 return this["nth-child"](c, "odd");
5589 "even" : function(c){
5590 return this["nth-child"](c, "even");
5593 "nth" : function(c, a){
5594 return c[a-1] || [];
5597 "first" : function(c){
5601 "last" : function(c){
5602 return c[c.length-1] || [];
5605 "has" : function(c, ss){
5606 var s = Roo.DomQuery.select;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5609 if(s(ss, ci).length > 0){
5616 "next" : function(c, ss){
5617 var is = Roo.DomQuery.is;
5618 var r = [], ri = -1;
5619 for(var i = 0, ci; ci = c[i]; i++){
5628 "prev" : function(c, ss){
5629 var is = Roo.DomQuery.is;
5630 var r = [], ri = -1;
5631 for(var i = 0, ci; ci = c[i]; i++){
5644 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5645 * @param {String} path The selector/xpath query
5646 * @param {Node} root (optional) The start of the query (defaults to document).
5651 Roo.query = Roo.DomQuery.select;
5654 * Ext JS Library 1.1.1
5655 * Copyright(c) 2006-2007, Ext JS, LLC.
5657 * Originally Released Under LGPL - original licence link has changed is not relivant.
5660 * <script type="text/javascript">
5664 * @class Roo.util.Observable
5665 * Base class that provides a common interface for publishing events. Subclasses are expected to
5666 * to have a property "events" with all the events defined.<br>
5669 Employee = function(name){
5676 Roo.extend(Employee, Roo.util.Observable);
5678 * @param {Object} config properties to use (incuding events / listeners)
5681 Roo.util.Observable = function(cfg){
5684 this.addEvents(cfg.events || {});
5686 delete cfg.events; // make sure
5689 Roo.apply(this, cfg);
5692 this.on(this.listeners);
5693 delete this.listeners;
5696 Roo.util.Observable.prototype = {
5698 * @cfg {Object} listeners list of events and functions to call for this object,
5702 'click' : function(e) {
5712 * Fires the specified event with the passed parameters (minus the event name).
5713 * @param {String} eventName
5714 * @param {Object...} args Variable number of parameters are passed to handlers
5715 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5717 fireEvent : function(){
5718 var ce = this.events[arguments[0].toLowerCase()];
5719 if(typeof ce == "object"){
5720 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5727 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5730 * Appends an event handler to this component
5731 * @param {String} eventName The type of event to listen for
5732 * @param {Function} handler The method the event invokes
5733 * @param {Object} scope (optional) The scope in which to execute the handler
5734 * function. The handler function's "this" context.
5735 * @param {Object} options (optional) An object containing handler configuration
5736 * properties. This may contain any of the following properties:<ul>
5737 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5738 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5739 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5740 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5741 * by the specified number of milliseconds. If the event fires again within that time, the original
5742 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5745 * <b>Combining Options</b><br>
5746 * Using the options argument, it is possible to combine different types of listeners:<br>
5748 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5750 el.on('click', this.onClick, this, {
5757 * <b>Attaching multiple handlers in 1 call</b><br>
5758 * The method also allows for a single argument to be passed which is a config object containing properties
5759 * which specify multiple handlers.
5768 fn: this.onMouseOver,
5772 fn: this.onMouseOut,
5778 * Or a shorthand syntax which passes the same scope object to all handlers:
5781 'click': this.onClick,
5782 'mouseover': this.onMouseOver,
5783 'mouseout': this.onMouseOut,
5788 addListener : function(eventName, fn, scope, o){
5789 if(typeof eventName == "object"){
5792 if(this.filterOptRe.test(e)){
5795 if(typeof o[e] == "function"){
5797 this.addListener(e, o[e], o.scope, o);
5799 // individual options
5800 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805 o = (!o || typeof o == "boolean") ? {} : o;
5806 eventName = eventName.toLowerCase();
5807 var ce = this.events[eventName] || true;
5808 if(typeof ce == "boolean"){
5809 ce = new Roo.util.Event(this, eventName);
5810 this.events[eventName] = ce;
5812 ce.addListener(fn, scope, o);
5816 * Removes a listener
5817 * @param {String} eventName The type of event to listen for
5818 * @param {Function} handler The handler to remove
5819 * @param {Object} scope (optional) The scope (this object) for the handler
5821 removeListener : function(eventName, fn, scope){
5822 var ce = this.events[eventName.toLowerCase()];
5823 if(typeof ce == "object"){
5824 ce.removeListener(fn, scope);
5829 * Removes all listeners for this object
5831 purgeListeners : function(){
5832 for(var evt in this.events){
5833 if(typeof this.events[evt] == "object"){
5834 this.events[evt].clearListeners();
5839 relayEvents : function(o, events){
5840 var createHandler = function(ename){
5842 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5845 for(var i = 0, len = events.length; i < len; i++){
5846 var ename = events[i];
5847 if(!this.events[ename]){ this.events[ename] = true; };
5848 o.on(ename, createHandler(ename), this);
5853 * Used to define events on this Observable
5854 * @param {Object} object The object with the events defined
5856 addEvents : function(o){
5860 Roo.applyIf(this.events, o);
5864 * Checks to see if this object has any listeners for a specified event
5865 * @param {String} eventName The name of the event to check for
5866 * @return {Boolean} True if the event is being listened for, else false
5868 hasListener : function(eventName){
5869 var e = this.events[eventName];
5870 return typeof e == "object" && e.listeners.length > 0;
5874 * Appends an event handler to this element (shorthand for addListener)
5875 * @param {String} eventName The type of event to listen for
5876 * @param {Function} handler The method the event invokes
5877 * @param {Object} scope (optional) The scope in which to execute the handler
5878 * function. The handler function's "this" context.
5879 * @param {Object} options (optional)
5882 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5884 * Removes a listener (shorthand for removeListener)
5885 * @param {String} eventName The type of event to listen for
5886 * @param {Function} handler The handler to remove
5887 * @param {Object} scope (optional) The scope (this object) for the handler
5890 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5893 * Starts capture on the specified Observable. All events will be passed
5894 * to the supplied function with the event name + standard signature of the event
5895 * <b>before</b> the event is fired. If the supplied function returns false,
5896 * the event will not fire.
5897 * @param {Observable} o The Observable to capture
5898 * @param {Function} fn The function to call
5899 * @param {Object} scope (optional) The scope (this object) for the fn
5902 Roo.util.Observable.capture = function(o, fn, scope){
5903 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 * Removes <b>all</b> added captures from the Observable.
5908 * @param {Observable} o The Observable to release
5911 Roo.util.Observable.releaseCapture = function(o){
5912 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 var createBuffered = function(h, o, scope){
5918 var task = new Roo.util.DelayedTask();
5920 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924 var createSingle = function(h, e, fn, scope){
5926 e.removeListener(fn, scope);
5927 return h.apply(scope, arguments);
5931 var createDelayed = function(h, o, scope){
5933 var args = Array.prototype.slice.call(arguments, 0);
5934 setTimeout(function(){
5935 h.apply(scope, args);
5940 Roo.util.Event = function(obj, name){
5943 this.listeners = [];
5946 Roo.util.Event.prototype = {
5947 addListener : function(fn, scope, options){
5948 var o = options || {};
5949 scope = scope || this.obj;
5950 if(!this.isListening(fn, scope)){
5951 var l = {fn: fn, scope: scope, options: o};
5954 h = createDelayed(h, o, scope);
5957 h = createSingle(h, this, fn, scope);
5960 h = createBuffered(h, o, scope);
5963 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5964 this.listeners.push(l);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.push(l);
5972 findListener : function(fn, scope){
5973 scope = scope || this.obj;
5974 var ls = this.listeners;
5975 for(var i = 0, len = ls.length; i < len; i++){
5977 if(l.fn == fn && l.scope == scope){
5984 isListening : function(fn, scope){
5985 return this.findListener(fn, scope) != -1;
5988 removeListener : function(fn, scope){
5990 if((index = this.findListener(fn, scope)) != -1){
5992 this.listeners.splice(index, 1);
5994 this.listeners = this.listeners.slice(0);
5995 this.listeners.splice(index, 1);
6002 clearListeners : function(){
6003 this.listeners = [];
6007 var ls = this.listeners, scope, len = ls.length;
6010 var args = Array.prototype.slice.call(arguments, 0);
6011 for(var i = 0; i < len; i++){
6013 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6014 this.firing = false;
6018 this.firing = false;
6025 * Ext JS Library 1.1.1
6026 * Copyright(c) 2006-2007, Ext JS, LLC.
6028 * Originally Released Under LGPL - original licence link has changed is not relivant.
6031 * <script type="text/javascript">
6035 * @class Roo.EventManager
6036 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6037 * several useful events directly.
6038 * See {@link Roo.EventObject} for more details on normalized event objects.
6041 Roo.EventManager = function(){
6042 var docReadyEvent, docReadyProcId, docReadyState = false;
6043 var resizeEvent, resizeTask, textEvent, textSize;
6044 var E = Roo.lib.Event;
6045 var D = Roo.lib.Dom;
6048 var fireDocReady = function(){
6050 docReadyState = true;
6053 clearInterval(docReadyProcId);
6055 if(Roo.isGecko || Roo.isOpera) {
6056 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6059 var defer = document.getElementById("ie-deferred-loader");
6061 defer.onreadystatechange = null;
6062 defer.parentNode.removeChild(defer);
6066 docReadyEvent.fire();
6067 docReadyEvent.clearListeners();
6072 var initDocReady = function(){
6073 docReadyEvent = new Roo.util.Event();
6074 if(Roo.isGecko || Roo.isOpera) {
6075 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6077 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6078 var defer = document.getElementById("ie-deferred-loader");
6079 defer.onreadystatechange = function(){
6080 if(this.readyState == "complete"){
6084 }else if(Roo.isSafari){
6085 docReadyProcId = setInterval(function(){
6086 var rs = document.readyState;
6087 if(rs == "complete") {
6092 // no matter what, make sure it fires on load
6093 E.on(window, "load", fireDocReady);
6096 var createBuffered = function(h, o){
6097 var task = new Roo.util.DelayedTask(h);
6099 // create new event object impl so new events don't wipe out properties
6100 e = new Roo.EventObjectImpl(e);
6101 task.delay(o.buffer, h, null, [e]);
6105 var createSingle = function(h, el, ename, fn){
6107 Roo.EventManager.removeListener(el, ename, fn);
6112 var createDelayed = function(h, o){
6114 // create new event object impl so new events don't wipe out properties
6115 e = new Roo.EventObjectImpl(e);
6116 setTimeout(function(){
6122 var listen = function(element, ename, opt, fn, scope){
6123 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6124 fn = fn || o.fn; scope = scope || o.scope;
6125 var el = Roo.getDom(element);
6127 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6129 var h = function(e){
6130 e = Roo.EventObject.setEvent(e);
6133 t = e.getTarget(o.delegate, el);
6140 if(o.stopEvent === true){
6143 if(o.preventDefault === true){
6146 if(o.stopPropagation === true){
6147 e.stopPropagation();
6150 if(o.normalized === false){
6154 fn.call(scope || el, e, t, o);
6157 h = createDelayed(h, o);
6160 h = createSingle(h, el, ename, fn);
6163 h = createBuffered(h, o);
6165 fn._handlers = fn._handlers || [];
6166 fn._handlers.push([Roo.id(el), ename, h]);
6169 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6170 el.addEventListener("DOMMouseScroll", h, false);
6171 E.on(window, 'unload', function(){
6172 el.removeEventListener("DOMMouseScroll", h, false);
6175 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6176 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6181 var stopListening = function(el, ename, fn){
6182 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6184 for(var i = 0, len = hds.length; i < len; i++){
6186 if(h[0] == id && h[1] == ename){
6193 E.un(el, ename, hd);
6194 el = Roo.getDom(el);
6195 if(ename == "mousewheel" && el.addEventListener){
6196 el.removeEventListener("DOMMouseScroll", hd, false);
6198 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6199 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6210 * @scope Roo.EventManager
6215 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6216 * object with a Roo.EventObject
6217 * @param {Function} fn The method the event invokes
6218 * @param {Object} scope An object that becomes the scope of the handler
6219 * @param {boolean} override If true, the obj passed in becomes
6220 * the execution scope of the listener
6221 * @return {Function} The wrapped function
6224 wrap : function(fn, scope, override){
6226 Roo.EventObject.setEvent(e);
6227 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6232 * Appends an event handler to an element (shorthand for addListener)
6233 * @param {String/HTMLElement} element The html element or id to assign the
6234 * @param {String} eventName The type of event to listen for
6235 * @param {Function} handler The method the event invokes
6236 * @param {Object} scope (optional) The scope in which to execute the handler
6237 * function. The handler function's "this" context.
6238 * @param {Object} options (optional) An object containing handler configuration
6239 * properties. This may contain any of the following properties:<ul>
6240 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6241 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6242 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6243 * <li>preventDefault {Boolean} True to prevent the default action</li>
6244 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6245 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6246 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6247 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6248 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6249 * by the specified number of milliseconds. If the event fires again within that time, the original
6250 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6253 * <b>Combining Options</b><br>
6254 * Using the options argument, it is possible to combine different types of listeners:<br>
6256 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6258 el.on('click', this.onClick, this, {
6265 * <b>Attaching multiple handlers in 1 call</b><br>
6266 * The method also allows for a single argument to be passed which is a config object containing properties
6267 * which specify multiple handlers.
6277 fn: this.onMouseOver
6286 * Or a shorthand syntax:<br>
6289 'click' : this.onClick,
6290 'mouseover' : this.onMouseOver,
6291 'mouseout' : this.onMouseOut
6295 addListener : function(element, eventName, fn, scope, options){
6296 if(typeof eventName == "object"){
6302 if(typeof o[e] == "function"){
6304 listen(element, e, o, o[e], o.scope);
6306 // individual options
6307 listen(element, e, o[e]);
6312 return listen(element, eventName, options, fn, scope);
6316 * Removes an event handler
6318 * @param {String/HTMLElement} element The id or html element to remove the
6320 * @param {String} eventName The type of event
6321 * @param {Function} fn
6322 * @return {Boolean} True if a listener was actually removed
6324 removeListener : function(element, eventName, fn){
6325 return stopListening(element, eventName, fn);
6329 * Fires when the document is ready (before onload and before images are loaded). Can be
6330 * accessed shorthanded Roo.onReady().
6331 * @param {Function} fn The method the event invokes
6332 * @param {Object} scope An object that becomes the scope of the handler
6333 * @param {boolean} options
6335 onDocumentReady : function(fn, scope, options){
6336 if(docReadyState){ // if it already fired
6337 docReadyEvent.addListener(fn, scope, options);
6338 docReadyEvent.fire();
6339 docReadyEvent.clearListeners();
6345 docReadyEvent.addListener(fn, scope, options);
6349 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6350 * @param {Function} fn The method the event invokes
6351 * @param {Object} scope An object that becomes the scope of the handler
6352 * @param {boolean} options
6354 onWindowResize : function(fn, scope, options){
6356 resizeEvent = new Roo.util.Event();
6357 resizeTask = new Roo.util.DelayedTask(function(){
6358 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6360 E.on(window, "resize", function(){
6362 resizeTask.delay(50);
6364 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368 resizeEvent.addListener(fn, scope, options);
6372 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6373 * @param {Function} fn The method the event invokes
6374 * @param {Object} scope An object that becomes the scope of the handler
6375 * @param {boolean} options
6377 onTextResize : function(fn, scope, options){
6379 textEvent = new Roo.util.Event();
6380 var textEl = new Roo.Element(document.createElement('div'));
6381 textEl.dom.className = 'x-text-resize';
6382 textEl.dom.innerHTML = 'X';
6383 textEl.appendTo(document.body);
6384 textSize = textEl.dom.offsetHeight;
6385 setInterval(function(){
6386 if(textEl.dom.offsetHeight != textSize){
6387 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6389 }, this.textResizeInterval);
6391 textEvent.addListener(fn, scope, options);
6395 * Removes the passed window resize listener.
6396 * @param {Function} fn The method the event invokes
6397 * @param {Object} scope The scope of handler
6399 removeResizeListener : function(fn, scope){
6401 resizeEvent.removeListener(fn, scope);
6406 fireResize : function(){
6408 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6418 textResizeInterval : 50
6423 * @scopeAlias pub=Roo.EventManager
6427 * Appends an event handler to an element (shorthand for addListener)
6428 * @param {String/HTMLElement} element The html element or id to assign the
6429 * @param {String} eventName The type of event to listen for
6430 * @param {Function} handler The method the event invokes
6431 * @param {Object} scope (optional) The scope in which to execute the handler
6432 * function. The handler function's "this" context.
6433 * @param {Object} options (optional) An object containing handler configuration
6434 * properties. This may contain any of the following properties:<ul>
6435 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6436 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6437 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6438 * <li>preventDefault {Boolean} True to prevent the default action</li>
6439 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6440 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6441 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6442 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6443 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6444 * by the specified number of milliseconds. If the event fires again within that time, the original
6445 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6448 * <b>Combining Options</b><br>
6449 * Using the options argument, it is possible to combine different types of listeners:<br>
6451 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6453 el.on('click', this.onClick, this, {
6460 * <b>Attaching multiple handlers in 1 call</b><br>
6461 * The method also allows for a single argument to be passed which is a config object containing properties
6462 * which specify multiple handlers.
6472 fn: this.onMouseOver
6481 * Or a shorthand syntax:<br>
6484 'click' : this.onClick,
6485 'mouseover' : this.onMouseOver,
6486 'mouseout' : this.onMouseOut
6490 pub.on = pub.addListener;
6491 pub.un = pub.removeListener;
6493 pub.stoppedMouseDownEvent = new Roo.util.Event();
6497 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6498 * @param {Function} fn The method the event invokes
6499 * @param {Object} scope An object that becomes the scope of the handler
6500 * @param {boolean} override If true, the obj passed in becomes
6501 * the execution scope of the listener
6505 Roo.onReady = Roo.EventManager.onDocumentReady;
6507 Roo.onReady(function(){
6508 var bd = Roo.get(document.body);
6513 : Roo.isGecko ? "roo-gecko"
6514 : Roo.isOpera ? "roo-opera"
6515 : Roo.isSafari ? "roo-safari" : ""];
6518 cls.push("roo-mac");
6521 cls.push("roo-linux");
6523 if(Roo.isBorderBox){
6524 cls.push('roo-border-box');
6526 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6527 var p = bd.dom.parentNode;
6529 p.className += ' roo-strict';
6532 bd.addClass(cls.join(' '));
6536 * @class Roo.EventObject
6537 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6538 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6541 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6543 var target = e.getTarget();
6546 var myDiv = Roo.get("myDiv");
6547 myDiv.on("click", handleClick);
6549 Roo.EventManager.on("myDiv", 'click', handleClick);
6550 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554 Roo.EventObject = function(){
6556 var E = Roo.lib.Event;
6558 // safari keypress events for special keys return bad keycodes
6561 63235 : 39, // right
6564 63276 : 33, // page up
6565 63277 : 34, // page down
6566 63272 : 46, // delete
6571 // normalize button clicks
6572 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6573 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6575 Roo.EventObjectImpl = function(e){
6577 this.setEvent(e.browserEvent || e);
6580 Roo.EventObjectImpl.prototype = {
6582 * Used to fix doc tools.
6583 * @scope Roo.EventObject.prototype
6589 /** The normal browser event */
6590 browserEvent : null,
6591 /** The button pressed in a mouse event */
6593 /** True if the shift key was down during the event */
6595 /** True if the control key was down during the event */
6597 /** True if the alt key was down during the event */
6656 setEvent : function(e){
6657 if(e == this || (e && e.browserEvent)){ // already wrapped
6660 this.browserEvent = e;
6662 // normalize buttons
6663 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6664 if(e.type == 'click' && this.button == -1){
6668 this.shiftKey = e.shiftKey;
6669 // mac metaKey behaves like ctrlKey
6670 this.ctrlKey = e.ctrlKey || e.metaKey;
6671 this.altKey = e.altKey;
6672 // in getKey these will be normalized for the mac
6673 this.keyCode = e.keyCode;
6674 // keyup warnings on firefox.
6675 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6676 // cache the target for the delayed and or buffered events
6677 this.target = E.getTarget(e);
6679 this.xy = E.getXY(e);
6682 this.shiftKey = false;
6683 this.ctrlKey = false;
6684 this.altKey = false;
6694 * Stop the event (preventDefault and stopPropagation)
6696 stopEvent : function(){
6697 if(this.browserEvent){
6698 if(this.browserEvent.type == 'mousedown'){
6699 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6701 E.stopEvent(this.browserEvent);
6706 * Prevents the browsers default handling of the event.
6708 preventDefault : function(){
6709 if(this.browserEvent){
6710 E.preventDefault(this.browserEvent);
6715 isNavKeyPress : function(){
6716 var k = this.keyCode;
6717 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6718 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6721 isSpecialKey : function(){
6722 var k = this.keyCode;
6723 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6724 (k == 16) || (k == 17) ||
6725 (k >= 18 && k <= 20) ||
6726 (k >= 33 && k <= 35) ||
6727 (k >= 36 && k <= 39) ||
6728 (k >= 44 && k <= 45);
6731 * Cancels bubbling of the event.
6733 stopPropagation : function(){
6734 if(this.browserEvent){
6735 if(this.type == 'mousedown'){
6736 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6738 E.stopPropagation(this.browserEvent);
6743 * Gets the key code for the event.
6746 getCharCode : function(){
6747 return this.charCode || this.keyCode;
6751 * Returns a normalized keyCode for the event.
6752 * @return {Number} The key code
6754 getKey : function(){
6755 var k = this.keyCode || this.charCode;
6756 return Roo.isSafari ? (safariKeys[k] || k) : k;
6760 * Gets the x coordinate of the event.
6763 getPageX : function(){
6768 * Gets the y coordinate of the event.
6771 getPageY : function(){
6776 * Gets the time of the event.
6779 getTime : function(){
6780 if(this.browserEvent){
6781 return E.getTime(this.browserEvent);
6787 * Gets the page coordinates of the event.
6788 * @return {Array} The xy values like [x, y]
6795 * Gets the target for the event.
6796 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6797 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6798 search as a number or element (defaults to 10 || document.body)
6799 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6800 * @return {HTMLelement}
6802 getTarget : function(selector, maxDepth, returnEl){
6803 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6806 * Gets the related target.
6807 * @return {HTMLElement}
6809 getRelatedTarget : function(){
6810 if(this.browserEvent){
6811 return E.getRelatedTarget(this.browserEvent);
6817 * Normalizes mouse wheel delta across browsers
6818 * @return {Number} The delta
6820 getWheelDelta : function(){
6821 var e = this.browserEvent;
6823 if(e.wheelDelta){ /* IE/Opera. */
6824 delta = e.wheelDelta/120;
6825 }else if(e.detail){ /* Mozilla case. */
6826 delta = -e.detail/3;
6832 * Returns true if the control, meta, shift or alt key was pressed during this event.
6835 hasModifier : function(){
6836 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840 * Returns true if the target of this event equals el or is a child of el
6841 * @param {String/HTMLElement/Element} el
6842 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6845 within : function(el, related){
6846 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6847 return t && Roo.fly(el).contains(t);
6850 getPoint : function(){
6851 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855 return new Roo.EventObjectImpl();
6860 * Ext JS Library 1.1.1
6861 * Copyright(c) 2006-2007, Ext JS, LLC.
6863 * Originally Released Under LGPL - original licence link has changed is not relivant.
6866 * <script type="text/javascript">
6870 // was in Composite Element!??!?!
6873 var D = Roo.lib.Dom;
6874 var E = Roo.lib.Event;
6875 var A = Roo.lib.Anim;
6877 // local style camelizing for speed
6879 var camelRe = /(-[a-z])/gi;
6880 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6881 var view = document.defaultView;
6884 * @class Roo.Element
6885 * Represents an Element in the DOM.<br><br>
6888 var el = Roo.get("my-div");
6891 var el = getEl("my-div");
6893 // or with a DOM element
6894 var el = Roo.get(myDivElement);
6896 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6897 * each call instead of constructing a new one.<br><br>
6898 * <b>Animations</b><br />
6899 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6900 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6902 Option Default Description
6903 --------- -------- ---------------------------------------------
6904 duration .35 The duration of the animation in seconds
6905 easing easeOut The YUI easing method
6906 callback none A function to execute when the anim completes
6907 scope this The scope (this) of the callback function
6909 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6910 * manipulate the animation. Here's an example:
6912 var el = Roo.get("my-div");
6917 // default animation
6918 el.setWidth(100, true);
6920 // animation with some options set
6927 // using the "anim" property to get the Anim object
6933 el.setWidth(100, opt);
6935 if(opt.anim.isAnimated()){
6939 * <b> Composite (Collections of) Elements</b><br />
6940 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6941 * @constructor Create a new Element directly.
6942 * @param {String/HTMLElement} element
6943 * @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).
6945 Roo.Element = function(element, forceNew){
6946 var dom = typeof element == "string" ?
6947 document.getElementById(element) : element;
6948 if(!dom){ // invalid id/element
6952 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6953 return Roo.Element.cache[id];
6963 * The DOM element ID
6966 this.id = id || Roo.id(dom);
6969 var El = Roo.Element;
6973 * The element's default display mode (defaults to "")
6976 originalDisplay : "",
6980 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6985 * Sets the element's visibility mode. When setVisible() is called it
6986 * will use this to determine whether to set the visibility or the display property.
6987 * @param visMode Element.VISIBILITY or Element.DISPLAY
6988 * @return {Roo.Element} this
6990 setVisibilityMode : function(visMode){
6991 this.visibilityMode = visMode;
6995 * Convenience method for setVisibilityMode(Element.DISPLAY)
6996 * @param {String} display (optional) What to set display to when visible
6997 * @return {Roo.Element} this
6999 enableDisplayMode : function(display){
7000 this.setVisibilityMode(El.DISPLAY);
7001 if(typeof display != "undefined") this.originalDisplay = display;
7006 * 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)
7007 * @param {String} selector The simple selector to test
7008 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7009 search as a number or element (defaults to 10 || document.body)
7010 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7011 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7013 findParent : function(simpleSelector, maxDepth, returnEl){
7014 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7015 maxDepth = maxDepth || 50;
7016 if(typeof maxDepth != "number"){
7017 stopEl = Roo.getDom(maxDepth);
7020 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7021 if(dq.is(p, simpleSelector)){
7022 return returnEl ? Roo.get(p) : p;
7032 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7033 * @param {String} selector The simple selector to test
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7039 findParentNode : function(simpleSelector, maxDepth, returnEl){
7040 var p = Roo.fly(this.dom.parentNode, '_internal');
7041 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7046 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7047 * @param {String} selector The simple selector to test
7048 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049 search as a number or element (defaults to 10 || document.body)
7050 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7052 up : function(simpleSelector, maxDepth){
7053 return this.findParentNode(simpleSelector, maxDepth, true);
7059 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7060 * @param {String} selector The simple selector to test
7061 * @return {Boolean} True if this element matches the selector, else false
7063 is : function(simpleSelector){
7064 return Roo.DomQuery.is(this.dom, simpleSelector);
7068 * Perform animation on this element.
7069 * @param {Object} args The YUI animation control args
7070 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7071 * @param {Function} onComplete (optional) Function to call when animation completes
7072 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7073 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7074 * @return {Roo.Element} this
7076 animate : function(args, duration, onComplete, easing, animType){
7077 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7082 * @private Internal animation call
7084 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7085 animType = animType || 'run';
7087 var anim = Roo.lib.Anim[animType](
7089 (opt.duration || defaultDur) || .35,
7090 (opt.easing || defaultEase) || 'easeOut',
7092 Roo.callback(cb, this);
7093 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7101 // private legacy anim prep
7102 preanim : function(a, i){
7103 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107 * Removes worthless text nodes
7108 * @param {Boolean} forceReclean (optional) By default the element
7109 * keeps track if it has been cleaned already so
7110 * you can call this over and over. However, if you update the element and
7111 * need to force a reclean, you can pass true.
7113 clean : function(forceReclean){
7114 if(this.isCleaned && forceReclean !== true){
7118 var d = this.dom, n = d.firstChild, ni = -1;
7120 var nx = n.nextSibling;
7121 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7128 this.isCleaned = true;
7133 calcOffsetsTo : function(el){
7136 var restorePos = false;
7137 if(el.getStyle('position') == 'static'){
7138 el.position('relative');
7143 while(op && op != d && op.tagName != 'HTML'){
7146 op = op.offsetParent;
7149 el.position('static');
7155 * Scrolls this element into view within the passed container.
7156 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7157 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7158 * @return {Roo.Element} this
7160 scrollIntoView : function(container, hscroll){
7161 var c = Roo.getDom(container) || document.body;
7164 var o = this.calcOffsetsTo(c),
7167 b = t+el.offsetHeight,
7168 r = l+el.offsetWidth;
7170 var ch = c.clientHeight;
7171 var ct = parseInt(c.scrollTop, 10);
7172 var cl = parseInt(c.scrollLeft, 10);
7174 var cr = cl + c.clientWidth;
7182 if(hscroll !== false){
7186 c.scrollLeft = r-c.clientWidth;
7193 scrollChildIntoView : function(child, hscroll){
7194 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7199 * the new height may not be available immediately.
7200 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7201 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7202 * @param {Function} onComplete (optional) Function to call when animation completes
7203 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7204 * @return {Roo.Element} this
7206 autoHeight : function(animate, duration, onComplete, easing){
7207 var oldHeight = this.getHeight();
7209 this.setHeight(1); // force clipping
7210 setTimeout(function(){
7211 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7213 this.setHeight(height);
7215 if(typeof onComplete == "function"){
7219 this.setHeight(oldHeight); // restore original height
7220 this.setHeight(height, animate, duration, function(){
7222 if(typeof onComplete == "function") onComplete();
7223 }.createDelegate(this), easing);
7225 }.createDelegate(this), 0);
7230 * Returns true if this element is an ancestor of the passed element
7231 * @param {HTMLElement/String} el The element to check
7232 * @return {Boolean} True if this element is an ancestor of el, else false
7234 contains : function(el){
7235 if(!el){return false;}
7236 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240 * Checks whether the element is currently visible using both visibility and display properties.
7241 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7242 * @return {Boolean} True if the element is currently visible, else false
7244 isVisible : function(deep) {
7245 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7246 if(deep !== true || !vis){
7249 var p = this.dom.parentNode;
7250 while(p && p.tagName.toLowerCase() != "body"){
7251 if(!Roo.fly(p, '_isVisible').isVisible()){
7260 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7261 * @param {String} selector The CSS selector
7262 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7263 * @return {CompositeElement/CompositeElementLite} The composite element
7265 select : function(selector, unique){
7266 return El.select(selector, unique, this.dom);
7270 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7271 * @param {String} selector The CSS selector
7272 * @return {Array} An array of the matched nodes
7274 query : function(selector, unique){
7275 return Roo.DomQuery.select(selector, this.dom);
7279 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 child : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7291 * @param {String} selector The CSS selector
7292 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7293 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7295 down : function(selector, returnDom){
7296 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7297 return returnDom ? n : Roo.get(n);
7301 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7302 * @param {String} group The group the DD object is member of
7303 * @param {Object} config The DD config object
7304 * @param {Object} overrides An object containing methods to override/implement on the DD object
7305 * @return {Roo.dd.DD} The DD object
7307 initDD : function(group, config, overrides){
7308 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7309 return Roo.apply(dd, overrides);
7313 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7314 * @param {String} group The group the DDProxy object is member of
7315 * @param {Object} config The DDProxy config object
7316 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7317 * @return {Roo.dd.DDProxy} The DDProxy object
7319 initDDProxy : function(group, config, overrides){
7320 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7321 return Roo.apply(dd, overrides);
7325 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7326 * @param {String} group The group the DDTarget object is member of
7327 * @param {Object} config The DDTarget config object
7328 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7329 * @return {Roo.dd.DDTarget} The DDTarget object
7331 initDDTarget : function(group, config, overrides){
7332 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7333 return Roo.apply(dd, overrides);
7337 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7338 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7339 * @param {Boolean} visible Whether the element is visible
7340 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7341 * @return {Roo.Element} this
7343 setVisible : function(visible, animate){
7345 if(this.visibilityMode == El.DISPLAY){
7346 this.setDisplayed(visible);
7349 this.dom.style.visibility = visible ? "visible" : "hidden";
7352 // closure for composites
7354 var visMode = this.visibilityMode;
7356 this.setOpacity(.01);
7357 this.setVisible(true);
7359 this.anim({opacity: { to: (visible?1:0) }},
7360 this.preanim(arguments, 1),
7361 null, .35, 'easeIn', function(){
7363 if(visMode == El.DISPLAY){
7364 dom.style.display = "none";
7366 dom.style.visibility = "hidden";
7368 Roo.get(dom).setOpacity(1);
7376 * Returns true if display is not "none"
7379 isDisplayed : function() {
7380 return this.getStyle("display") != "none";
7384 * Toggles the element's visibility or display, depending on visibility mode.
7385 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7386 * @return {Roo.Element} this
7388 toggle : function(animate){
7389 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7394 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7395 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7396 * @return {Roo.Element} this
7398 setDisplayed : function(value) {
7399 if(typeof value == "boolean"){
7400 value = value ? this.originalDisplay : "none";
7402 this.setStyle("display", value);
7407 * Tries to focus the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7410 focus : function() {
7418 * Tries to blur the element. Any exceptions are caught and ignored.
7419 * @return {Roo.Element} this
7429 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7430 * @param {String/Array} className The CSS class to add, or an array of classes
7431 * @return {Roo.Element} this
7433 addClass : function(className){
7434 if(className instanceof Array){
7435 for(var i = 0, len = className.length; i < len; i++) {
7436 this.addClass(className[i]);
7439 if(className && !this.hasClass(className)){
7440 this.dom.className = this.dom.className + " " + className;
7447 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7448 * @param {String/Array} className The CSS class to add, or an array of classes
7449 * @return {Roo.Element} this
7451 radioClass : function(className){
7452 var siblings = this.dom.parentNode.childNodes;
7453 for(var i = 0; i < siblings.length; i++) {
7454 var s = siblings[i];
7455 if(s.nodeType == 1){
7456 Roo.get(s).removeClass(className);
7459 this.addClass(className);
7464 * Removes one or more CSS classes from the element.
7465 * @param {String/Array} className The CSS class to remove, or an array of classes
7466 * @return {Roo.Element} this
7468 removeClass : function(className){
7469 if(!className || !this.dom.className){
7472 if(className instanceof Array){
7473 for(var i = 0, len = className.length; i < len; i++) {
7474 this.removeClass(className[i]);
7477 if(this.hasClass(className)){
7478 var re = this.classReCache[className];
7480 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7481 this.classReCache[className] = re;
7483 this.dom.className =
7484 this.dom.className.replace(re, " ");
7494 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7495 * @param {String} className The CSS class to toggle
7496 * @return {Roo.Element} this
7498 toggleClass : function(className){
7499 if(this.hasClass(className)){
7500 this.removeClass(className);
7502 this.addClass(className);
7508 * Checks if the specified CSS class exists on this element's DOM node.
7509 * @param {String} className The CSS class to check for
7510 * @return {Boolean} True if the class exists, else false
7512 hasClass : function(className){
7513 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7518 * @param {String} oldClassName The CSS class to replace
7519 * @param {String} newClassName The replacement CSS class
7520 * @return {Roo.Element} this
7522 replaceClass : function(oldClassName, newClassName){
7523 this.removeClass(oldClassName);
7524 this.addClass(newClassName);
7529 * Returns an object with properties matching the styles requested.
7530 * For example, el.getStyles('color', 'font-size', 'width') might return
7531 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7532 * @param {String} style1 A style name
7533 * @param {String} style2 A style name
7534 * @param {String} etc.
7535 * @return {Object} The style object
7537 getStyles : function(){
7538 var a = arguments, len = a.length, r = {};
7539 for(var i = 0; i < len; i++){
7540 r[a[i]] = this.getStyle(a[i]);
7546 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7547 * @param {String} property The style property whose value is returned.
7548 * @return {String} The current value of the style property for this element.
7550 getStyle : function(){
7551 return view && view.getComputedStyle ?
7553 var el = this.dom, v, cs, camel;
7554 if(prop == 'float'){
7557 if(el.style && (v = el.style[prop])){
7560 if(cs = view.getComputedStyle(el, "")){
7561 if(!(camel = propCache[prop])){
7562 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7569 var el = this.dom, v, cs, camel;
7570 if(prop == 'opacity'){
7571 if(typeof el.style.filter == 'string'){
7572 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7574 var fv = parseFloat(m[1]);
7576 return fv ? fv / 100 : 0;
7581 }else if(prop == 'float'){
7582 prop = "styleFloat";
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7587 if(v = el.style[camel]){
7590 if(cs = el.currentStyle){
7598 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7599 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7600 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7601 * @return {Roo.Element} this
7603 setStyle : function(prop, value){
7604 if(typeof prop == "string"){
7606 if (prop == 'float') {
7607 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7612 if(!(camel = propCache[prop])){
7613 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616 if(camel == 'opacity') {
7617 this.setOpacity(value);
7619 this.dom.style[camel] = value;
7622 for(var style in prop){
7623 if(typeof prop[style] != "function"){
7624 this.setStyle(style, prop[style]);
7632 * More flexible version of {@link #setStyle} for setting style properties.
7633 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7634 * a function which returns such a specification.
7635 * @return {Roo.Element} this
7637 applyStyles : function(style){
7638 Roo.DomHelper.applyStyles(this.dom, style);
7643 * 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).
7644 * @return {Number} The X position of the element
7647 return D.getX(this.dom);
7651 * 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).
7652 * @return {Number} The Y position of the element
7655 return D.getY(this.dom);
7659 * 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).
7660 * @return {Array} The XY position of the element
7663 return D.getXY(this.dom);
7667 * 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).
7668 * @param {Number} The X position of the element
7669 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7670 * @return {Roo.Element} this
7672 setX : function(x, animate){
7674 D.setX(this.dom, x);
7676 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7682 * 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).
7683 * @param {Number} The Y position of the element
7684 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7685 * @return {Roo.Element} this
7687 setY : function(y, animate){
7689 D.setY(this.dom, y);
7691 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7697 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7698 * @param {String} left The left CSS property value
7699 * @return {Roo.Element} this
7701 setLeft : function(left){
7702 this.setStyle("left", this.addUnits(left));
7707 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7708 * @param {String} top The top CSS property value
7709 * @return {Roo.Element} this
7711 setTop : function(top){
7712 this.setStyle("top", this.addUnits(top));
7717 * Sets the element's CSS right style.
7718 * @param {String} right The right CSS property value
7719 * @return {Roo.Element} this
7721 setRight : function(right){
7722 this.setStyle("right", this.addUnits(right));
7727 * Sets the element's CSS bottom style.
7728 * @param {String} bottom The bottom CSS property value
7729 * @return {Roo.Element} this
7731 setBottom : function(bottom){
7732 this.setStyle("bottom", this.addUnits(bottom));
7737 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7738 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setXY : function(pos, animate){
7745 D.setXY(this.dom, pos);
7747 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7753 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7754 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7755 * @param {Number} x X value for new position (coordinates are page-based)
7756 * @param {Number} y Y value for new position (coordinates are page-based)
7757 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7758 * @return {Roo.Element} this
7760 setLocation : function(x, y, animate){
7761 this.setXY([x, y], this.preanim(arguments, 2));
7766 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7767 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7768 * @param {Number} x X value for new position (coordinates are page-based)
7769 * @param {Number} y Y value for new position (coordinates are page-based)
7770 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7771 * @return {Roo.Element} this
7773 moveTo : function(x, y, animate){
7774 this.setXY([x, y], this.preanim(arguments, 2));
7779 * Returns the region of the given element.
7780 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7781 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7783 getRegion : function(){
7784 return D.getRegion(this.dom);
7788 * Returns the offset height of the element
7789 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7790 * @return {Number} The element's height
7792 getHeight : function(contentHeight){
7793 var h = this.dom.offsetHeight || 0;
7794 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798 * Returns the offset width of the element
7799 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7800 * @return {Number} The element's width
7802 getWidth : function(contentWidth){
7803 var w = this.dom.offsetWidth || 0;
7804 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7809 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7810 * if a height has not been set using CSS.
7813 getComputedHeight : function(){
7814 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7816 h = parseInt(this.getStyle('height'), 10) || 0;
7817 if(!this.isBorderBox()){
7818 h += this.getFrameWidth('tb');
7825 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7826 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7827 * if a width has not been set using CSS.
7830 getComputedWidth : function(){
7831 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7833 w = parseInt(this.getStyle('width'), 10) || 0;
7834 if(!this.isBorderBox()){
7835 w += this.getFrameWidth('lr');
7842 * Returns the size of the element.
7843 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7844 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7846 getSize : function(contentSize){
7847 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851 * Returns the width and height of the viewport.
7852 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7854 getViewSize : function(){
7855 var d = this.dom, doc = document, aw = 0, ah = 0;
7856 if(d == doc || d == doc.body){
7857 return {width : D.getViewWidth(), height: D.getViewHeight()};
7860 width : d.clientWidth,
7861 height: d.clientHeight
7867 * Returns the value of the "value" attribute
7868 * @param {Boolean} asNumber true to parse the value as a number
7869 * @return {String/Number}
7871 getValue : function(asNumber){
7872 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876 adjustWidth : function(width){
7877 if(typeof width == "number"){
7878 if(this.autoBoxAdjust && !this.isBorderBox()){
7879 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7889 adjustHeight : function(height){
7890 if(typeof height == "number"){
7891 if(this.autoBoxAdjust && !this.isBorderBox()){
7892 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7902 * Set the width of the element
7903 * @param {Number} width The new width
7904 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7905 * @return {Roo.Element} this
7907 setWidth : function(width, animate){
7908 width = this.adjustWidth(width);
7910 this.dom.style.width = this.addUnits(width);
7912 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7918 * Set the height of the element
7919 * @param {Number} height The new height
7920 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7921 * @return {Roo.Element} this
7923 setHeight : function(height, animate){
7924 height = this.adjustHeight(height);
7926 this.dom.style.height = this.addUnits(height);
7928 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7934 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7935 * @param {Number} width The new width
7936 * @param {Number} height The new height
7937 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7938 * @return {Roo.Element} this
7940 setSize : function(width, height, animate){
7941 if(typeof width == "object"){ // in case of object from getSize()
7942 height = width.height; width = width.width;
7944 width = this.adjustWidth(width); height = this.adjustHeight(height);
7946 this.dom.style.width = this.addUnits(width);
7947 this.dom.style.height = this.addUnits(height);
7949 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7955 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7956 * @param {Number} x X value for new position (coordinates are page-based)
7957 * @param {Number} y Y value for new position (coordinates are page-based)
7958 * @param {Number} width The new width
7959 * @param {Number} height The new height
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setBounds : function(x, y, width, height, animate){
7965 this.setSize(width, height);
7966 this.setLocation(x, y);
7968 width = this.adjustWidth(width); height = this.adjustHeight(height);
7969 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7970 this.preanim(arguments, 4), 'motion');
7976 * 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.
7977 * @param {Roo.lib.Region} region The region to fill
7978 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setRegion : function(region, animate){
7982 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7987 * Appends an event handler
7989 * @param {String} eventName The type of event to append
7990 * @param {Function} fn The method the event invokes
7991 * @param {Object} scope (optional) The scope (this object) of the fn
7992 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7994 addListener : function(eventName, fn, scope, options){
7996 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8001 * Removes an event handler from this element
8002 * @param {String} eventName the type of event to remove
8003 * @param {Function} fn the method the event invokes
8004 * @return {Roo.Element} this
8006 removeListener : function(eventName, fn){
8007 Roo.EventManager.removeListener(this.dom, eventName, fn);
8012 * Removes all previous added listeners from this element
8013 * @return {Roo.Element} this
8015 removeAllListeners : function(){
8016 E.purgeElement(this.dom);
8020 relayEvent : function(eventName, observable){
8021 this.on(eventName, function(e){
8022 observable.fireEvent(eventName, e);
8027 * Set the opacity of the element
8028 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8029 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setOpacity : function(opacity, animate){
8034 var s = this.dom.style;
8037 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8038 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8040 s.opacity = opacity;
8043 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8049 * Gets the left X coordinate
8050 * @param {Boolean} local True to get the local css position instead of page coordinate
8053 getLeft : function(local){
8057 return parseInt(this.getStyle("left"), 10) || 0;
8062 * Gets the right X coordinate of the element (element X position + element width)
8063 * @param {Boolean} local True to get the local css position instead of page coordinate
8066 getRight : function(local){
8068 return this.getX() + this.getWidth();
8070 return (this.getLeft(true) + this.getWidth()) || 0;
8075 * Gets the top Y coordinate
8076 * @param {Boolean} local True to get the local css position instead of page coordinate
8079 getTop : function(local) {
8083 return parseInt(this.getStyle("top"), 10) || 0;
8088 * Gets the bottom Y coordinate of the element (element Y position + element height)
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getBottom : function(local){
8094 return this.getY() + this.getHeight();
8096 return (this.getTop(true) + this.getHeight()) || 0;
8101 * Initializes positioning on this element. If a desired position is not passed, it will make the
8102 * the element positioned relative IF it is not already positioned.
8103 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8104 * @param {Number} zIndex (optional) The zIndex to apply
8105 * @param {Number} x (optional) Set the page X position
8106 * @param {Number} y (optional) Set the page Y position
8108 position : function(pos, zIndex, x, y){
8110 if(this.getStyle('position') == 'static'){
8111 this.setStyle('position', 'relative');
8114 this.setStyle("position", pos);
8117 this.setStyle("z-index", zIndex);
8119 if(x !== undefined && y !== undefined){
8121 }else if(x !== undefined){
8123 }else if(y !== undefined){
8129 * Clear positioning back to the default when the document was loaded
8130 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8131 * @return {Roo.Element} this
8133 clearPositioning : function(value){
8141 "position" : "static"
8147 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8148 * snapshot before performing an update and then restoring the element.
8151 getPositioning : function(){
8152 var l = this.getStyle("left");
8153 var t = this.getStyle("top");
8155 "position" : this.getStyle("position"),
8157 "right" : l ? "" : this.getStyle("right"),
8159 "bottom" : t ? "" : this.getStyle("bottom"),
8160 "z-index" : this.getStyle("z-index")
8165 * Gets the width of the border(s) for the specified side(s)
8166 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167 * passing lr would get the border (l)eft width + the border (r)ight width.
8168 * @return {Number} The width of the sides passed added together
8170 getBorderWidth : function(side){
8171 return this.addStyles(side, El.borders);
8175 * Gets the width of the padding(s) for the specified side(s)
8176 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8177 * passing lr would get the padding (l)eft + the padding (r)ight.
8178 * @return {Number} The padding of the sides passed added together
8180 getPadding : function(side){
8181 return this.addStyles(side, El.paddings);
8185 * Set positioning with an object returned by getPositioning().
8186 * @param {Object} posCfg
8187 * @return {Roo.Element} this
8189 setPositioning : function(pc){
8190 this.applyStyles(pc);
8191 if(pc.right == "auto"){
8192 this.dom.style.right = "";
8194 if(pc.bottom == "auto"){
8195 this.dom.style.bottom = "";
8201 fixDisplay : function(){
8202 if(this.getStyle("display") == "none"){
8203 this.setStyle("visibility", "hidden");
8204 this.setStyle("display", this.originalDisplay); // first try reverting to default
8205 if(this.getStyle("display") == "none"){ // if that fails, default to block
8206 this.setStyle("display", "block");
8212 * Quick set left and top adding default units
8213 * @param {String} left The left CSS property value
8214 * @param {String} top The top CSS property value
8215 * @return {Roo.Element} this
8217 setLeftTop : function(left, top){
8218 this.dom.style.left = this.addUnits(left);
8219 this.dom.style.top = this.addUnits(top);
8224 * Move this element relative to its current position.
8225 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8226 * @param {Number} distance How far to move the element in pixels
8227 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8228 * @return {Roo.Element} this
8230 move : function(direction, distance, animate){
8231 var xy = this.getXY();
8232 direction = direction.toLowerCase();
8236 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8245 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8250 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8257 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8258 * @return {Roo.Element} this
8261 if(!this.isClipped){
8262 this.isClipped = true;
8263 this.originalClip = {
8264 "o": this.getStyle("overflow"),
8265 "x": this.getStyle("overflow-x"),
8266 "y": this.getStyle("overflow-y")
8268 this.setStyle("overflow", "hidden");
8269 this.setStyle("overflow-x", "hidden");
8270 this.setStyle("overflow-y", "hidden");
8276 * Return clipping (overflow) to original clipping before clip() was called
8277 * @return {Roo.Element} this
8279 unclip : function(){
8281 this.isClipped = false;
8282 var o = this.originalClip;
8283 if(o.o){this.setStyle("overflow", o.o);}
8284 if(o.x){this.setStyle("overflow-x", o.x);}
8285 if(o.y){this.setStyle("overflow-y", o.y);}
8292 * Gets the x,y coordinates specified by the anchor position on the element.
8293 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8294 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8295 * {width: (target width), height: (target height)} (defaults to the element's current size)
8296 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8297 * @return {Array} [x, y] An array containing the element's x and y coordinates
8299 getAnchorXY : function(anchor, local, s){
8300 //Passing a different size is useful for pre-calculating anchors,
8301 //especially for anchored animations that change the el size.
8303 var w, h, vp = false;
8306 if(d == document.body || d == document){
8308 w = D.getViewWidth(); h = D.getViewHeight();
8310 w = this.getWidth(); h = this.getHeight();
8313 w = s.width; h = s.height;
8315 var x = 0, y = 0, r = Math.round;
8316 switch((anchor || "tl").toLowerCase()){
8358 var sc = this.getScroll();
8359 return [x + sc.left, y + sc.top];
8361 //Add the element's offset xy
8362 var o = this.getXY();
8363 return [x+o[0], y+o[1]];
8367 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8368 * supported position values.
8369 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8370 * @param {String} position The position to align to.
8371 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8372 * @return {Array} [x, y]
8374 getAlignToXY : function(el, p, o){
8378 throw "Element.alignTo with an element that doesn't exist";
8380 var c = false; //constrain to viewport
8381 var p1 = "", p2 = "";
8388 }else if(p.indexOf("-") == -1){
8391 p = p.toLowerCase();
8392 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8394 throw "Element.alignTo with an invalid alignment " + p;
8396 p1 = m[1]; p2 = m[2]; c = !!m[3];
8398 //Subtract the aligned el's internal xy from the target's offset xy
8399 //plus custom offset to get the aligned el's new offset xy
8400 var a1 = this.getAnchorXY(p1, true);
8401 var a2 = el.getAnchorXY(p2, false);
8402 var x = a2[0] - a1[0] + o[0];
8403 var y = a2[1] - a1[1] + o[1];
8405 //constrain the aligned el to viewport if necessary
8406 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8407 // 5px of margin for ie
8408 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8410 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8411 //perpendicular to the vp border, allow the aligned el to slide on that border,
8412 //otherwise swap the aligned el to the opposite border of the target.
8413 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8414 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8415 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8416 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8419 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8420 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8422 if((x+w) > dw + scrollX){
8423 x = swapX ? r.left-w : dw+scrollX-w;
8426 x = swapX ? r.right : scrollX;
8428 if((y+h) > dh + scrollY){
8429 y = swapY ? r.top-h : dh+scrollY-h;
8432 y = swapY ? r.bottom : scrollY;
8439 getConstrainToXY : function(){
8440 var os = {top:0, left:0, bottom:0, right: 0};
8442 return function(el, local, offsets, proposedXY){
8444 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8446 var vw, vh, vx = 0, vy = 0;
8447 if(el.dom == document.body || el.dom == document){
8448 vw = Roo.lib.Dom.getViewWidth();
8449 vh = Roo.lib.Dom.getViewHeight();
8451 vw = el.dom.clientWidth;
8452 vh = el.dom.clientHeight;
8454 var vxy = el.getXY();
8460 var s = el.getScroll();
8462 vx += offsets.left + s.left;
8463 vy += offsets.top + s.top;
8465 vw -= offsets.right;
8466 vh -= offsets.bottom;
8471 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8472 var x = xy[0], y = xy[1];
8473 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8475 // only move it if it needs it
8478 // first validate right/bottom
8487 // then make sure top/left isn't negative
8496 return moved ? [x, y] : false;
8501 adjustForConstraints : function(xy, parent, offsets){
8502 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8506 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8507 * document it aligns it to the viewport.
8508 * The position parameter is optional, and can be specified in any one of the following formats:
8510 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8511 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8512 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8513 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8514 * <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
8515 * element's anchor point, and the second value is used as the target's anchor point.</li>
8517 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8518 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8519 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8520 * that specified in order to enforce the viewport constraints.
8521 * Following are all of the supported anchor positions:
8524 ----- -----------------------------
8525 tl The top left corner (default)
8526 t The center of the top edge
8527 tr The top right corner
8528 l The center of the left edge
8529 c In the center of the element
8530 r The center of the right edge
8531 bl The bottom left corner
8532 b The center of the bottom edge
8533 br The bottom right corner
8537 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8538 el.alignTo("other-el");
8540 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8541 el.alignTo("other-el", "tr?");
8543 // align the bottom right corner of el with the center left edge of other-el
8544 el.alignTo("other-el", "br-l?");
8546 // align the center of el with the bottom left corner of other-el and
8547 // adjust the x position by -6 pixels (and the y position by 0)
8548 el.alignTo("other-el", "c-bl", [-6, 0]);
8550 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8551 * @param {String} position The position to align to.
8552 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8553 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8554 * @return {Roo.Element} this
8556 alignTo : function(element, position, offsets, animate){
8557 var xy = this.getAlignToXY(element, position, offsets);
8558 this.setXY(xy, this.preanim(arguments, 3));
8563 * Anchors an element to another element and realigns it when the window is resized.
8564 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8565 * @param {String} position The position to align to.
8566 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8567 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8568 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8569 * is a number, it is used as the buffer delay (defaults to 50ms).
8570 * @param {Function} callback The function to call after the animation finishes
8571 * @return {Roo.Element} this
8573 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8574 var action = function(){
8575 this.alignTo(el, alignment, offsets, animate);
8576 Roo.callback(callback, this);
8578 Roo.EventManager.onWindowResize(action, this);
8579 var tm = typeof monitorScroll;
8580 if(tm != 'undefined'){
8581 Roo.EventManager.on(window, 'scroll', action, this,
8582 {buffer: tm == 'number' ? monitorScroll : 50});
8584 action.call(this); // align immediately
8588 * Clears any opacity settings from this element. Required in some cases for IE.
8589 * @return {Roo.Element} this
8591 clearOpacity : function(){
8592 if (window.ActiveXObject) {
8593 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8594 this.dom.style.filter = "";
8597 this.dom.style.opacity = "";
8598 this.dom.style["-moz-opacity"] = "";
8599 this.dom.style["-khtml-opacity"] = "";
8605 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 hide : function(animate){
8610 this.setVisible(false, this.preanim(arguments, 0));
8615 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8616 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8617 * @return {Roo.Element} this
8619 show : function(animate){
8620 this.setVisible(true, this.preanim(arguments, 0));
8625 * @private Test if size has a unit, otherwise appends the default
8627 addUnits : function(size){
8628 return Roo.Element.addUnits(size, this.defaultUnit);
8632 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8633 * @return {Roo.Element} this
8635 beginMeasure : function(){
8637 if(el.offsetWidth || el.offsetHeight){
8638 return this; // offsets work already
8641 var p = this.dom, b = document.body; // start with this element
8642 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8643 var pe = Roo.get(p);
8644 if(pe.getStyle('display') == 'none'){
8645 changed.push({el: p, visibility: pe.getStyle("visibility")});
8646 p.style.visibility = "hidden";
8647 p.style.display = "block";
8651 this._measureChanged = changed;
8657 * Restores displays to before beginMeasure was called
8658 * @return {Roo.Element} this
8660 endMeasure : function(){
8661 var changed = this._measureChanged;
8663 for(var i = 0, len = changed.length; i < len; i++) {
8665 r.el.style.visibility = r.visibility;
8666 r.el.style.display = "none";
8668 this._measureChanged = null;
8674 * Update the innerHTML of this element, optionally searching for and processing scripts
8675 * @param {String} html The new HTML
8676 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8677 * @param {Function} callback For async script loading you can be noticed when the update completes
8678 * @return {Roo.Element} this
8680 update : function(html, loadScripts, callback){
8681 if(typeof html == "undefined"){
8684 if(loadScripts !== true){
8685 this.dom.innerHTML = html;
8686 if(typeof callback == "function"){
8694 html += '<span id="' + id + '"></span>';
8696 E.onAvailable(id, function(){
8697 var hd = document.getElementsByTagName("head")[0];
8698 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8699 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8700 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8703 while(match = re.exec(html)){
8704 var attrs = match[1];
8705 var srcMatch = attrs ? attrs.match(srcRe) : false;
8706 if(srcMatch && srcMatch[2]){
8707 var s = document.createElement("script");
8708 s.src = srcMatch[2];
8709 var typeMatch = attrs.match(typeRe);
8710 if(typeMatch && typeMatch[2]){
8711 s.type = typeMatch[2];
8714 }else if(match[2] && match[2].length > 0){
8715 if(window.execScript) {
8716 window.execScript(match[2]);
8724 window.eval(match[2]);
8728 var el = document.getElementById(id);
8729 if(el){el.parentNode.removeChild(el);}
8730 if(typeof callback == "function"){
8734 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8739 * Direct access to the UpdateManager update() method (takes the same parameters).
8740 * @param {String/Function} url The url for this request or a function to call to get the url
8741 * @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}
8742 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8743 * @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.
8744 * @return {Roo.Element} this
8747 var um = this.getUpdateManager();
8748 um.update.apply(um, arguments);
8753 * Gets this element's UpdateManager
8754 * @return {Roo.UpdateManager} The UpdateManager
8756 getUpdateManager : function(){
8757 if(!this.updateManager){
8758 this.updateManager = new Roo.UpdateManager(this);
8760 return this.updateManager;
8764 * Disables text selection for this element (normalized across browsers)
8765 * @return {Roo.Element} this
8767 unselectable : function(){
8768 this.dom.unselectable = "on";
8769 this.swallowEvent("selectstart", true);
8770 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8771 this.addClass("x-unselectable");
8776 * Calculates the x, y to center this element on the screen
8777 * @return {Array} The x, y values [x, y]
8779 getCenterXY : function(){
8780 return this.getAlignToXY(document, 'c-c');
8784 * Centers the Element in either the viewport, or another Element.
8785 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8787 center : function(centerIn){
8788 this.alignTo(centerIn || document, 'c-c');
8793 * Tests various css rules/browsers to determine if this element uses a border box
8796 isBorderBox : function(){
8797 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801 * Return a box {x, y, width, height} that can be used to set another elements
8802 * size/location to match this element.
8803 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8804 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8805 * @return {Object} box An object in the format {x, y, width, height}
8807 getBox : function(contentBox, local){
8812 var left = parseInt(this.getStyle("left"), 10) || 0;
8813 var top = parseInt(this.getStyle("top"), 10) || 0;
8816 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8818 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8820 var l = this.getBorderWidth("l")+this.getPadding("l");
8821 var r = this.getBorderWidth("r")+this.getPadding("r");
8822 var t = this.getBorderWidth("t")+this.getPadding("t");
8823 var b = this.getBorderWidth("b")+this.getPadding("b");
8824 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)};
8826 bx.right = bx.x + bx.width;
8827 bx.bottom = bx.y + bx.height;
8832 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8833 for more information about the sides.
8834 * @param {String} sides
8837 getFrameWidth : function(sides, onlyContentBox){
8838 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842 * 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.
8843 * @param {Object} box The box to fill {x, y, width, height}
8844 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8845 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8846 * @return {Roo.Element} this
8848 setBox : function(box, adjust, animate){
8849 var w = box.width, h = box.height;
8850 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8851 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8852 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8854 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8859 * Forces the browser to repaint this element
8860 * @return {Roo.Element} this
8862 repaint : function(){
8864 this.addClass("x-repaint");
8865 setTimeout(function(){
8866 Roo.get(dom).removeClass("x-repaint");
8872 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8873 * then it returns the calculated width of the sides (see getPadding)
8874 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8875 * @return {Object/Number}
8877 getMargins : function(side){
8880 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8881 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8882 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8883 right: parseInt(this.getStyle("margin-right"), 10) || 0
8886 return this.addStyles(side, El.margins);
8891 addStyles : function(sides, styles){
8893 for(var i = 0, len = sides.length; i < len; i++){
8894 v = this.getStyle(styles[sides.charAt(i)]);
8896 w = parseInt(v, 10);
8904 * Creates a proxy element of this element
8905 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8906 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8907 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8908 * @return {Roo.Element} The new proxy element
8910 createProxy : function(config, renderTo, matchBox){
8912 renderTo = Roo.getDom(renderTo);
8914 renderTo = document.body;
8916 config = typeof config == "object" ?
8917 config : {tag : "div", cls: config};
8918 var proxy = Roo.DomHelper.append(renderTo, config, true);
8920 proxy.setBox(this.getBox());
8926 * Puts a mask over this element to disable user interaction. Requires core.css.
8927 * This method can only be applied to elements which accept child nodes.
8928 * @param {String} msg (optional) A message to display in the mask
8929 * @param {String} msgCls (optional) A css class to apply to the msg element
8930 * @return {Element} The mask element
8932 mask : function(msg, msgCls)
8934 if(this.getStyle("position") == "static"){
8935 this.setStyle("position", "relative");
8938 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8940 this.addClass("x-masked");
8941 this._mask.setDisplayed(true);
8946 while (dom && dom.style) {
8947 if (!isNaN(parseInt(dom.style.zIndex))) {
8948 z = Math.max(z, parseInt(dom.style.zIndex));
8950 dom = dom.parentNode;
8952 // if we are masking the body - then it hides everything..
8953 if (this.dom == document.body) {
8955 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8956 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8959 if(typeof msg == 'string'){
8961 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8963 var mm = this._maskMsg;
8964 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8965 mm.dom.firstChild.innerHTML = msg;
8966 mm.setDisplayed(true);
8968 mm.setStyle('z-index', z + 102);
8970 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8971 this._mask.setHeight(this.getHeight());
8973 this._mask.setStyle('z-index', z + 100);
8979 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8980 * it is cached for reuse.
8982 unmask : function(removeEl){
8984 if(removeEl === true){
8985 this._mask.remove();
8988 this._maskMsg.remove();
8989 delete this._maskMsg;
8992 this._mask.setDisplayed(false);
8994 this._maskMsg.setDisplayed(false);
8998 this.removeClass("x-masked");
9002 * Returns true if this element is masked
9005 isMasked : function(){
9006 return this._mask && this._mask.isVisible();
9010 * Creates an iframe shim for this element to keep selects and other windowed objects from
9012 * @return {Roo.Element} The new shim element
9014 createShim : function(){
9015 var el = document.createElement('iframe');
9016 el.frameBorder = 'no';
9017 el.className = 'roo-shim';
9018 if(Roo.isIE && Roo.isSecure){
9019 el.src = Roo.SSL_SECURE_URL;
9021 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9022 shim.autoBoxAdjust = false;
9027 * Removes this element from the DOM and deletes it from the cache
9029 remove : function(){
9030 if(this.dom.parentNode){
9031 this.dom.parentNode.removeChild(this.dom);
9033 delete El.cache[this.dom.id];
9037 * Sets up event handlers to add and remove a css class when the mouse is over this element
9038 * @param {String} className
9039 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9040 * mouseout events for children elements
9041 * @return {Roo.Element} this
9043 addClassOnOver : function(className, preventFlicker){
9044 this.on("mouseover", function(){
9045 Roo.fly(this, '_internal').addClass(className);
9047 var removeFn = function(e){
9048 if(preventFlicker !== true || !e.within(this, true)){
9049 Roo.fly(this, '_internal').removeClass(className);
9052 this.on("mouseout", removeFn, this.dom);
9057 * Sets up event handlers to add and remove a css class when this element has the focus
9058 * @param {String} className
9059 * @return {Roo.Element} this
9061 addClassOnFocus : function(className){
9062 this.on("focus", function(){
9063 Roo.fly(this, '_internal').addClass(className);
9065 this.on("blur", function(){
9066 Roo.fly(this, '_internal').removeClass(className);
9071 * 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)
9072 * @param {String} className
9073 * @return {Roo.Element} this
9075 addClassOnClick : function(className){
9077 this.on("mousedown", function(){
9078 Roo.fly(dom, '_internal').addClass(className);
9079 var d = Roo.get(document);
9080 var fn = function(){
9081 Roo.fly(dom, '_internal').removeClass(className);
9082 d.removeListener("mouseup", fn);
9084 d.on("mouseup", fn);
9090 * Stops the specified event from bubbling and optionally prevents the default action
9091 * @param {String} eventName
9092 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9093 * @return {Roo.Element} this
9095 swallowEvent : function(eventName, preventDefault){
9096 var fn = function(e){
9097 e.stopPropagation();
9102 if(eventName instanceof Array){
9103 for(var i = 0, len = eventName.length; i < len; i++){
9104 this.on(eventName[i], fn);
9108 this.on(eventName, fn);
9115 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9118 * Sizes this element to its parent element's dimensions performing
9119 * neccessary box adjustments.
9120 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9121 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9122 * @return {Roo.Element} this
9124 fitToParent : function(monitorResize, targetParent) {
9125 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9126 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9127 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9130 var p = Roo.get(targetParent || this.dom.parentNode);
9131 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9132 if (monitorResize === true) {
9133 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9134 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9140 * Gets the next sibling, skipping text nodes
9141 * @return {HTMLElement} The next sibling or null
9143 getNextSibling : function(){
9144 var n = this.dom.nextSibling;
9145 while(n && n.nodeType != 1){
9152 * Gets the previous sibling, skipping text nodes
9153 * @return {HTMLElement} The previous sibling or null
9155 getPrevSibling : function(){
9156 var n = this.dom.previousSibling;
9157 while(n && n.nodeType != 1){
9158 n = n.previousSibling;
9165 * Appends the passed element(s) to this element
9166 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9167 * @return {Roo.Element} this
9169 appendChild: function(el){
9176 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9177 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9178 * automatically generated with the specified attributes.
9179 * @param {HTMLElement} insertBefore (optional) a child element of this element
9180 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9181 * @return {Roo.Element} The new child element
9183 createChild: function(config, insertBefore, returnDom){
9184 config = config || {tag:'div'};
9186 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9188 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9192 * Appends this element to the passed element
9193 * @param {String/HTMLElement/Element} el The new parent element
9194 * @return {Roo.Element} this
9196 appendTo: function(el){
9197 el = Roo.getDom(el);
9198 el.appendChild(this.dom);
9203 * Inserts this element before the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert before
9205 * @return {Roo.Element} this
9207 insertBefore: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el);
9214 * Inserts this element after the passed element in the DOM
9215 * @param {String/HTMLElement/Element} el The element to insert after
9216 * @return {Roo.Element} this
9218 insertAfter: function(el){
9219 el = Roo.getDom(el);
9220 el.parentNode.insertBefore(this.dom, el.nextSibling);
9225 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9226 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9227 * @return {Roo.Element} The new child
9229 insertFirst: function(el, returnDom){
9231 if(typeof el == 'object' && !el.nodeType){ // dh config
9232 return this.createChild(el, this.dom.firstChild, returnDom);
9234 el = Roo.getDom(el);
9235 this.dom.insertBefore(el, this.dom.firstChild);
9236 return !returnDom ? Roo.get(el) : el;
9241 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9242 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9243 * @param {String} where (optional) 'before' or 'after' defaults to before
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {Roo.Element} the inserted Element
9247 insertSibling: function(el, where, returnDom){
9248 where = where ? where.toLowerCase() : 'before';
9250 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9252 if(typeof el == 'object' && !el.nodeType){ // dh config
9253 if(where == 'after' && !this.dom.nextSibling){
9254 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9256 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9261 where == 'before' ? this.dom : this.dom.nextSibling);
9270 * Creates and wraps this element with another element
9271 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9272 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9273 * @return {HTMLElement/Element} The newly created wrapper element
9275 wrap: function(config, returnDom){
9277 config = {tag: "div"};
9279 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9280 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9285 * Replaces the passed element with this element
9286 * @param {String/HTMLElement/Element} el The element to replace
9287 * @return {Roo.Element} this
9289 replace: function(el){
9291 this.insertBefore(el);
9297 * Inserts an html fragment into this element
9298 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9299 * @param {String} html The HTML fragment
9300 * @param {Boolean} returnEl True to return an Roo.Element
9301 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9303 insertHtml : function(where, html, returnEl){
9304 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9305 return returnEl ? Roo.get(el) : el;
9309 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9310 * @param {Object} o The object with the attributes
9311 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9312 * @return {Roo.Element} this
9314 set : function(o, useSet){
9316 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9318 if(attr == "style" || typeof o[attr] == "function") continue;
9320 el.className = o["cls"];
9322 if(useSet) el.setAttribute(attr, o[attr]);
9323 else el[attr] = o[attr];
9327 Roo.DomHelper.applyStyles(el, o.style);
9333 * Convenience method for constructing a KeyMap
9334 * @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:
9335 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9336 * @param {Function} fn The function to call
9337 * @param {Object} scope (optional) The scope of the function
9338 * @return {Roo.KeyMap} The KeyMap created
9340 addKeyListener : function(key, fn, scope){
9342 if(typeof key != "object" || key instanceof Array){
9358 return new Roo.KeyMap(this, config);
9362 * Creates a KeyMap for this element
9363 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9364 * @return {Roo.KeyMap} The KeyMap created
9366 addKeyMap : function(config){
9367 return new Roo.KeyMap(this, config);
9371 * Returns true if this element is scrollable.
9374 isScrollable : function(){
9376 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380 * 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().
9381 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9382 * @param {Number} value The new scroll value
9383 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9384 * @return {Element} this
9387 scrollTo : function(side, value, animate){
9388 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9390 this.dom[prop] = value;
9392 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9393 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9399 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9400 * within this element's scrollable range.
9401 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9402 * @param {Number} distance How far to scroll the element in pixels
9403 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9404 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9405 * was scrolled as far as it could go.
9407 scroll : function(direction, distance, animate){
9408 if(!this.isScrollable()){
9412 var l = el.scrollLeft, t = el.scrollTop;
9413 var w = el.scrollWidth, h = el.scrollHeight;
9414 var cw = el.clientWidth, ch = el.clientHeight;
9415 direction = direction.toLowerCase();
9416 var scrolled = false;
9417 var a = this.preanim(arguments, 2);
9422 var v = Math.min(l + distance, w-cw);
9423 this.scrollTo("left", v, a);
9430 var v = Math.max(l - distance, 0);
9431 this.scrollTo("left", v, a);
9439 var v = Math.max(t - distance, 0);
9440 this.scrollTo("top", v, a);
9448 var v = Math.min(t + distance, h-ch);
9449 this.scrollTo("top", v, a);
9458 * Translates the passed page coordinates into left/top css values for this element
9459 * @param {Number/Array} x The page x or an array containing [x, y]
9460 * @param {Number} y The page y
9461 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9463 translatePoints : function(x, y){
9464 if(typeof x == 'object' || x instanceof Array){
9467 var p = this.getStyle('position');
9468 var o = this.getXY();
9470 var l = parseInt(this.getStyle('left'), 10);
9471 var t = parseInt(this.getStyle('top'), 10);
9474 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9477 t = (p == "relative") ? 0 : this.dom.offsetTop;
9480 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484 * Returns the current scroll position of the element.
9485 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9487 getScroll : function(){
9488 var d = this.dom, doc = document;
9489 if(d == doc || d == doc.body){
9490 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9491 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9492 return {left: l, top: t};
9494 return {left: d.scrollLeft, top: d.scrollTop};
9499 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9500 * are convert to standard 6 digit hex color.
9501 * @param {String} attr The css attribute
9502 * @param {String} defaultValue The default value to use when a valid color isn't found
9503 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9506 getColor : function(attr, defaultValue, prefix){
9507 var v = this.getStyle(attr);
9508 if(!v || v == "transparent" || v == "inherit") {
9509 return defaultValue;
9511 var color = typeof prefix == "undefined" ? "#" : prefix;
9512 if(v.substr(0, 4) == "rgb("){
9513 var rvs = v.slice(4, v.length -1).split(",");
9514 for(var i = 0; i < 3; i++){
9515 var h = parseInt(rvs[i]).toString(16);
9522 if(v.substr(0, 1) == "#"){
9524 for(var i = 1; i < 4; i++){
9525 var c = v.charAt(i);
9528 }else if(v.length == 7){
9529 color += v.substr(1);
9533 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9538 * gradient background, rounded corners and a 4-way shadow.
9539 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9540 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9541 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9542 * @return {Roo.Element} this
9544 boxWrap : function(cls){
9545 cls = cls || 'x-box';
9546 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9547 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9552 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9553 * @param {String} namespace The namespace in which to look for the attribute
9554 * @param {String} name The attribute name
9555 * @return {String} The attribute value
9557 getAttributeNS : Roo.isIE ? function(ns, name){
9559 var type = typeof d[ns+":"+name];
9560 if(type != 'undefined' && type != 'unknown'){
9561 return d[ns+":"+name];
9564 } : function(ns, name){
9566 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9571 * Sets or Returns the value the dom attribute value
9572 * @param {String} name The attribute name
9573 * @param {String} value (optional) The value to set the attribute to
9574 * @return {String} The attribute value
9576 attr : function(name){
9577 if (arguments.length > 1) {
9578 this.dom.setAttribute(name, arguments[1]);
9579 return arguments[1];
9581 if (!this.dom.hasAttribute(name)) {
9584 return this.dom.getAttribute(name);
9591 var ep = El.prototype;
9594 * Appends an event handler (Shorthand for addListener)
9595 * @param {String} eventName The type of event to append
9596 * @param {Function} fn The method the event invokes
9597 * @param {Object} scope (optional) The scope (this object) of the fn
9598 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9601 ep.on = ep.addListener;
9603 ep.mon = ep.addListener;
9606 * Removes an event handler from this element (shorthand for removeListener)
9607 * @param {String} eventName the type of event to remove
9608 * @param {Function} fn the method the event invokes
9609 * @return {Roo.Element} this
9612 ep.un = ep.removeListener;
9615 * true to automatically adjust width and height settings for box-model issues (default to true)
9617 ep.autoBoxAdjust = true;
9620 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9623 El.addUnits = function(v, defaultUnit){
9624 if(v === "" || v == "auto"){
9627 if(v === undefined){
9630 if(typeof v == "number" || !El.unitPattern.test(v)){
9631 return v + (defaultUnit || 'px');
9636 // special markup used throughout Roo when box wrapping elements
9637 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>';
9639 * Visibility mode constant - Use visibility to hide element
9645 * Visibility mode constant - Use display to hide element
9651 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9652 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9653 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9665 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9666 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9667 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9668 * @return {Element} The Element object
9671 El.get = function(el){
9673 if(!el){ return null; }
9674 if(typeof el == "string"){ // element id
9675 if(!(elm = document.getElementById(el))){
9678 if(ex = El.cache[el]){
9681 ex = El.cache[el] = new El(elm);
9684 }else if(el.tagName){ // dom element
9688 if(ex = El.cache[id]){
9691 ex = El.cache[id] = new El(el);
9694 }else if(el instanceof El){
9696 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9697 // catch case where it hasn't been appended
9698 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9701 }else if(el.isComposite){
9703 }else if(el instanceof Array){
9704 return El.select(el);
9705 }else if(el == document){
9706 // create a bogus element object representing the document object
9708 var f = function(){};
9709 f.prototype = El.prototype;
9711 docEl.dom = document;
9719 El.uncache = function(el){
9720 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9722 delete El.cache[a[i].id || a[i]];
9728 // Garbage collection - uncache elements/purge listeners on orphaned elements
9729 // so we don't hold a reference and cause the browser to retain them
9730 El.garbageCollect = function(){
9731 if(!Roo.enableGarbageCollector){
9732 clearInterval(El.collectorThread);
9735 for(var eid in El.cache){
9736 var el = El.cache[eid], d = el.dom;
9737 // -------------------------------------------------------
9738 // Determining what is garbage:
9739 // -------------------------------------------------------
9741 // dom node is null, definitely garbage
9742 // -------------------------------------------------------
9744 // no parentNode == direct orphan, definitely garbage
9745 // -------------------------------------------------------
9746 // !d.offsetParent && !document.getElementById(eid)
9747 // display none elements have no offsetParent so we will
9748 // also try to look it up by it's id. However, check
9749 // offsetParent first so we don't do unneeded lookups.
9750 // This enables collection of elements that are not orphans
9751 // directly, but somewhere up the line they have an orphan
9753 // -------------------------------------------------------
9754 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9755 delete El.cache[eid];
9756 if(d && Roo.enableListenerCollection){
9762 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9766 El.Flyweight = function(dom){
9769 El.Flyweight.prototype = El.prototype;
9771 El._flyweights = {};
9773 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9774 * the dom node can be overwritten by other code.
9775 * @param {String/HTMLElement} el The dom node or id
9776 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9777 * prevent conflicts (e.g. internally Roo uses "_internal")
9779 * @return {Element} The shared Element object
9781 El.fly = function(el, named){
9782 named = named || '_global';
9783 el = Roo.getDom(el);
9787 if(!El._flyweights[named]){
9788 El._flyweights[named] = new El.Flyweight();
9790 El._flyweights[named].dom = el;
9791 return El._flyweights[named];
9795 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9796 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9797 * Shorthand of {@link Roo.Element#get}
9798 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9799 * @return {Element} The Element object
9805 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9806 * the dom node can be overwritten by other code.
9807 * Shorthand of {@link Roo.Element#fly}
9808 * @param {String/HTMLElement} el The dom node or id
9809 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9810 * prevent conflicts (e.g. internally Roo uses "_internal")
9812 * @return {Element} The shared Element object
9818 // speedy lookup for elements never to box adjust
9819 var noBoxAdjust = Roo.isStrict ? {
9822 input:1, select:1, textarea:1
9824 if(Roo.isIE || Roo.isGecko){
9825 noBoxAdjust['button'] = 1;
9829 Roo.EventManager.on(window, 'unload', function(){
9831 delete El._flyweights;
9839 Roo.Element.selectorFunction = Roo.DomQuery.select;
9842 Roo.Element.select = function(selector, unique, root){
9844 if(typeof selector == "string"){
9845 els = Roo.Element.selectorFunction(selector, root);
9846 }else if(selector.length !== undefined){
9849 throw "Invalid selector";
9851 if(unique === true){
9852 return new Roo.CompositeElement(els);
9854 return new Roo.CompositeElementLite(els);
9858 * Selects elements based on the passed CSS selector to enable working on them as 1.
9859 * @param {String/Array} selector The CSS selector or an array of elements
9860 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9861 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9862 * @return {CompositeElementLite/CompositeElement}
9866 Roo.select = Roo.Element.select;
9883 * Ext JS Library 1.1.1
9884 * Copyright(c) 2006-2007, Ext JS, LLC.
9886 * Originally Released Under LGPL - original licence link has changed is not relivant.
9889 * <script type="text/javascript">
9894 //Notifies Element that fx methods are available
9895 Roo.enableFx = true;
9899 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9900 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9901 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9902 * Element effects to work.</p><br/>
9904 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9905 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9906 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9907 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9908 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9909 * expected results and should be done with care.</p><br/>
9911 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9912 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9915 ----- -----------------------------
9916 tl The top left corner
9917 t The center of the top edge
9918 tr The top right corner
9919 l The center of the left edge
9920 r The center of the right edge
9921 bl The bottom left corner
9922 b The center of the bottom edge
9923 br The bottom right corner
9925 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9926 * below are common options that can be passed to any Fx method.</b>
9927 * @cfg {Function} callback A function called when the effect is finished
9928 * @cfg {Object} scope The scope of the effect function
9929 * @cfg {String} easing A valid Easing value for the effect
9930 * @cfg {String} afterCls A css class to apply after the effect
9931 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9932 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9933 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9934 * effects that end with the element being visually hidden, ignored otherwise)
9935 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9936 * a function which returns such a specification that will be applied to the Element after the effect finishes
9937 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9938 * @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
9939 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9943 * Slides the element into view. An anchor point can be optionally passed to set the point of
9944 * origin for the slide effect. This function automatically handles wrapping the element with
9945 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9948 // default: slide the element in from the top
9951 // custom: slide the element in from the right with a 2-second duration
9952 el.slideIn('r', { duration: 2 });
9954 // common config options shown with default values
9960 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9961 * @param {Object} options (optional) Object literal with any of the Fx config options
9962 * @return {Roo.Element} The Element
9964 slideIn : function(anchor, o){
9965 var el = this.getFxEl();
9968 el.queueFx(o, function(){
9970 anchor = anchor || "t";
9972 // fix display to visibility
9975 // restore values after effect
9976 var r = this.getFxRestore();
9977 var b = this.getBox();
9978 // fixed size for slide
9982 var wrap = this.fxWrap(r.pos, o, "hidden");
9984 var st = this.dom.style;
9985 st.visibility = "visible";
9986 st.position = "absolute";
9988 // clear out temp styles after slide and unwrap
9989 var after = function(){
9990 el.fxUnwrap(wrap, r.pos, o);
9992 st.height = r.height;
9995 // time to calc the positions
9996 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
9998 switch(anchor.toLowerCase()){
10000 wrap.setSize(b.width, 0);
10001 st.left = st.bottom = "0";
10005 wrap.setSize(0, b.height);
10006 st.right = st.top = "0";
10010 wrap.setSize(0, b.height);
10011 wrap.setX(b.right);
10012 st.left = st.top = "0";
10013 a = {width: bw, points: pt};
10016 wrap.setSize(b.width, 0);
10017 wrap.setY(b.bottom);
10018 st.left = st.top = "0";
10019 a = {height: bh, points: pt};
10022 wrap.setSize(0, 0);
10023 st.right = st.bottom = "0";
10024 a = {width: bw, height: bh};
10027 wrap.setSize(0, 0);
10028 wrap.setY(b.y+b.height);
10029 st.right = st.top = "0";
10030 a = {width: bw, height: bh, points: pt};
10033 wrap.setSize(0, 0);
10034 wrap.setXY([b.right, b.bottom]);
10035 st.left = st.top = "0";
10036 a = {width: bw, height: bh, points: pt};
10039 wrap.setSize(0, 0);
10040 wrap.setX(b.x+b.width);
10041 st.left = st.bottom = "0";
10042 a = {width: bw, height: bh, points: pt};
10045 this.dom.style.visibility = "visible";
10048 arguments.callee.anim = wrap.fxanim(a,
10058 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10059 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10060 * 'hidden') but block elements will still take up space in the document. The element must be removed
10061 * from the DOM using the 'remove' config option if desired. This function automatically handles
10062 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10065 // default: slide the element out to the top
10068 // custom: slide the element out to the right with a 2-second duration
10069 el.slideOut('r', { duration: 2 });
10071 // common config options shown with default values
10079 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10080 * @param {Object} options (optional) Object literal with any of the Fx config options
10081 * @return {Roo.Element} The Element
10083 slideOut : function(anchor, o){
10084 var el = this.getFxEl();
10087 el.queueFx(o, function(){
10089 anchor = anchor || "t";
10091 // restore values after effect
10092 var r = this.getFxRestore();
10094 var b = this.getBox();
10095 // fixed size for slide
10099 var wrap = this.fxWrap(r.pos, o, "visible");
10101 var st = this.dom.style;
10102 st.visibility = "visible";
10103 st.position = "absolute";
10107 var after = function(){
10109 el.setDisplayed(false);
10114 el.fxUnwrap(wrap, r.pos, o);
10116 st.width = r.width;
10117 st.height = r.height;
10122 var a, zero = {to: 0};
10123 switch(anchor.toLowerCase()){
10125 st.left = st.bottom = "0";
10126 a = {height: zero};
10129 st.right = st.top = "0";
10133 st.left = st.top = "0";
10134 a = {width: zero, points: {to:[b.right, b.y]}};
10137 st.left = st.top = "0";
10138 a = {height: zero, points: {to:[b.x, b.bottom]}};
10141 st.right = st.bottom = "0";
10142 a = {width: zero, height: zero};
10145 st.right = st.top = "0";
10146 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10149 st.left = st.top = "0";
10150 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10153 st.left = st.bottom = "0";
10154 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10158 arguments.callee.anim = wrap.fxanim(a,
10168 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10169 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10170 * The element must be removed from the DOM using the 'remove' config option if desired.
10176 // common config options shown with default values
10184 * @param {Object} options (optional) Object literal with any of the Fx config options
10185 * @return {Roo.Element} The Element
10187 puff : function(o){
10188 var el = this.getFxEl();
10191 el.queueFx(o, function(){
10192 this.clearOpacity();
10195 // restore values after effect
10196 var r = this.getFxRestore();
10197 var st = this.dom.style;
10199 var after = function(){
10201 el.setDisplayed(false);
10208 el.setPositioning(r.pos);
10209 st.width = r.width;
10210 st.height = r.height;
10215 var width = this.getWidth();
10216 var height = this.getHeight();
10218 arguments.callee.anim = this.fxanim({
10219 width : {to: this.adjustWidth(width * 2)},
10220 height : {to: this.adjustHeight(height * 2)},
10221 points : {by: [-(width * .5), -(height * .5)]},
10223 fontSize: {to:200, unit: "%"}
10234 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10235 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10236 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10242 // all 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 switchOff : 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);
10273 el.setPositioning(r.pos);
10274 st.width = r.width;
10275 st.height = r.height;
10280 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10281 this.clearOpacity();
10285 points:{by:[0, this.getHeight() * .5]}
10286 }, o, 'motion', 0.3, 'easeIn', after);
10287 }).defer(100, this);
10294 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10295 * changed using the "attr" config option) and then fading back to the original color. If no original
10296 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10299 // default: highlight background to yellow
10302 // custom: highlight foreground text to blue for 2 seconds
10303 el.highlight("0000ff", { attr: 'color', duration: 2 });
10305 // common config options shown with default values
10306 el.highlight("ffff9c", {
10307 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10308 endColor: (current color) or "ffffff",
10313 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10314 * @param {Object} options (optional) Object literal with any of the Fx config options
10315 * @return {Roo.Element} The Element
10317 highlight : function(color, o){
10318 var el = this.getFxEl();
10321 el.queueFx(o, function(){
10322 color = color || "ffff9c";
10323 attr = o.attr || "backgroundColor";
10325 this.clearOpacity();
10328 var origColor = this.getColor(attr);
10329 var restoreColor = this.dom.style[attr];
10330 endColor = (o.endColor || origColor) || "ffffff";
10332 var after = function(){
10333 el.dom.style[attr] = restoreColor;
10338 a[attr] = {from: color, to: endColor};
10339 arguments.callee.anim = this.fxanim(a,
10349 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10352 // default: a single light blue ripple
10355 // custom: 3 red ripples lasting 3 seconds total
10356 el.frame("ff0000", 3, { duration: 3 });
10358 // common config options shown with default values
10359 el.frame("C3DAF9", 1, {
10360 duration: 1 //duration of entire animation (not each individual ripple)
10361 // Note: Easing is not configurable and will be ignored if included
10364 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10365 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10366 * @param {Object} options (optional) Object literal with any of the Fx config options
10367 * @return {Roo.Element} The Element
10369 frame : function(color, count, o){
10370 var el = this.getFxEl();
10373 el.queueFx(o, function(){
10374 color = color || "#C3DAF9";
10375 if(color.length == 6){
10376 color = "#" + color;
10378 count = count || 1;
10379 duration = o.duration || 1;
10382 var b = this.getBox();
10383 var animFn = function(){
10384 var proxy = this.createProxy({
10387 visbility:"hidden",
10388 position:"absolute",
10389 "z-index":"35000", // yee haw
10390 border:"0px solid " + color
10393 var scale = Roo.isBorderBox ? 2 : 1;
10395 top:{from:b.y, to:b.y - 20},
10396 left:{from:b.x, to:b.x - 20},
10397 borderWidth:{from:0, to:10},
10398 opacity:{from:1, to:0},
10399 height:{from:b.height, to:(b.height + (20*scale))},
10400 width:{from:b.width, to:(b.width + (20*scale))}
10401 }, duration, function(){
10405 animFn.defer((duration/2)*1000, this);
10416 * Creates a pause before any subsequent queued effects begin. If there are
10417 * no effects queued after the pause it will have no effect.
10422 * @param {Number} seconds The length of time to pause (in seconds)
10423 * @return {Roo.Element} The Element
10425 pause : function(seconds){
10426 var el = this.getFxEl();
10429 el.queueFx(o, function(){
10430 setTimeout(function(){
10432 }, seconds * 1000);
10438 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10439 * using the "endOpacity" config option.
10442 // default: fade in from opacity 0 to 100%
10445 // custom: fade in from opacity 0 to 75% over 2 seconds
10446 el.fadeIn({ endOpacity: .75, duration: 2});
10448 // common config options shown with default values
10450 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10455 * @param {Object} options (optional) Object literal with any of the Fx config options
10456 * @return {Roo.Element} The Element
10458 fadeIn : function(o){
10459 var el = this.getFxEl();
10461 el.queueFx(o, function(){
10462 this.setOpacity(0);
10464 this.dom.style.visibility = 'visible';
10465 var to = o.endOpacity || 1;
10466 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10467 o, null, .5, "easeOut", function(){
10469 this.clearOpacity();
10478 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10479 * using the "endOpacity" config option.
10482 // default: fade out from the element's current opacity to 0
10485 // custom: fade out from the element's current opacity to 25% over 2 seconds
10486 el.fadeOut({ endOpacity: .25, duration: 2});
10488 // common config options shown with default values
10490 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10497 * @param {Object} options (optional) Object literal with any of the Fx config options
10498 * @return {Roo.Element} The Element
10500 fadeOut : function(o){
10501 var el = this.getFxEl();
10503 el.queueFx(o, function(){
10504 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10505 o, null, .5, "easeOut", function(){
10506 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10507 this.dom.style.display = "none";
10509 this.dom.style.visibility = "hidden";
10511 this.clearOpacity();
10519 * Animates the transition of an element's dimensions from a starting height/width
10520 * to an ending height/width.
10523 // change height and width to 100x100 pixels
10524 el.scale(100, 100);
10526 // common config options shown with default values. The height and width will default to
10527 // the element's existing values if passed as null.
10530 [element's height], {
10535 * @param {Number} width The new width (pass undefined to keep the original width)
10536 * @param {Number} height The new height (pass undefined to keep the original height)
10537 * @param {Object} options (optional) Object literal with any of the Fx config options
10538 * @return {Roo.Element} The Element
10540 scale : function(w, h, o){
10541 this.shift(Roo.apply({}, o, {
10549 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10550 * Any of these properties not specified in the config object will not be changed. This effect
10551 * requires that at least one new dimension, position or opacity setting must be passed in on
10552 * the config object in order for the function to have any effect.
10555 // slide the element horizontally to x position 200 while changing the height and opacity
10556 el.shift({ x: 200, height: 50, opacity: .8 });
10558 // common config options shown with default values.
10560 width: [element's width],
10561 height: [element's height],
10562 x: [element's x position],
10563 y: [element's y position],
10564 opacity: [element's opacity],
10569 * @param {Object} options Object literal with any of the Fx config options
10570 * @return {Roo.Element} The Element
10572 shift : function(o){
10573 var el = this.getFxEl();
10575 el.queueFx(o, function(){
10576 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10577 if(w !== undefined){
10578 a.width = {to: this.adjustWidth(w)};
10580 if(h !== undefined){
10581 a.height = {to: this.adjustHeight(h)};
10583 if(x !== undefined || y !== undefined){
10585 x !== undefined ? x : this.getX(),
10586 y !== undefined ? y : this.getY()
10589 if(op !== undefined){
10590 a.opacity = {to: op};
10592 if(o.xy !== undefined){
10593 a.points = {to: o.xy};
10595 arguments.callee.anim = this.fxanim(a,
10596 o, 'motion', .35, "easeOut", function(){
10604 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10605 * ending point of the effect.
10608 // default: slide the element downward while fading out
10611 // custom: slide the element out to the right with a 2-second duration
10612 el.ghost('r', { duration: 2 });
10614 // common config options shown with default values
10622 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10623 * @param {Object} options (optional) Object literal with any of the Fx config options
10624 * @return {Roo.Element} The Element
10626 ghost : function(anchor, o){
10627 var el = this.getFxEl();
10630 el.queueFx(o, function(){
10631 anchor = anchor || "b";
10633 // restore values after effect
10634 var r = this.getFxRestore();
10635 var w = this.getWidth(),
10636 h = this.getHeight();
10638 var st = this.dom.style;
10640 var after = function(){
10642 el.setDisplayed(false);
10648 el.setPositioning(r.pos);
10649 st.width = r.width;
10650 st.height = r.height;
10655 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10656 switch(anchor.toLowerCase()){
10683 arguments.callee.anim = this.fxanim(a,
10693 * Ensures that all effects queued after syncFx is called on the element are
10694 * run concurrently. This is the opposite of {@link #sequenceFx}.
10695 * @return {Roo.Element} The Element
10697 syncFx : function(){
10698 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10707 * Ensures that all effects queued after sequenceFx is called on the element are
10708 * run in sequence. This is the opposite of {@link #syncFx}.
10709 * @return {Roo.Element} The Element
10711 sequenceFx : function(){
10712 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10714 concurrent : false,
10721 nextFx : function(){
10722 var ef = this.fxQueue[0];
10729 * Returns true if the element has any effects actively running or queued, else returns false.
10730 * @return {Boolean} True if element has active effects, else false
10732 hasActiveFx : function(){
10733 return this.fxQueue && this.fxQueue[0];
10737 * Stops any running effects and clears the element's internal effects queue if it contains
10738 * any additional effects that haven't started yet.
10739 * @return {Roo.Element} The Element
10741 stopFx : function(){
10742 if(this.hasActiveFx()){
10743 var cur = this.fxQueue[0];
10744 if(cur && cur.anim && cur.anim.isAnimated()){
10745 this.fxQueue = [cur]; // clear out others
10746 cur.anim.stop(true);
10753 beforeFx : function(o){
10754 if(this.hasActiveFx() && !o.concurrent){
10765 * Returns true if the element is currently blocking so that no other effect can be queued
10766 * until this effect is finished, else returns false if blocking is not set. This is commonly
10767 * used to ensure that an effect initiated by a user action runs to completion prior to the
10768 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10769 * @return {Boolean} True if blocking, else false
10771 hasFxBlock : function(){
10772 var q = this.fxQueue;
10773 return q && q[0] && q[0].block;
10777 queueFx : function(o, fn){
10781 if(!this.hasFxBlock()){
10782 Roo.applyIf(o, this.fxDefaults);
10784 var run = this.beforeFx(o);
10785 fn.block = o.block;
10786 this.fxQueue.push(fn);
10798 fxWrap : function(pos, o, vis){
10800 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10803 wrapXY = this.getXY();
10805 var div = document.createElement("div");
10806 div.style.visibility = vis;
10807 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10808 wrap.setPositioning(pos);
10809 if(wrap.getStyle("position") == "static"){
10810 wrap.position("relative");
10812 this.clearPositioning('auto');
10814 wrap.dom.appendChild(this.dom);
10816 wrap.setXY(wrapXY);
10823 fxUnwrap : function(wrap, pos, o){
10824 this.clearPositioning();
10825 this.setPositioning(pos);
10827 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10833 getFxRestore : function(){
10834 var st = this.dom.style;
10835 return {pos: this.getPositioning(), width: st.width, height : st.height};
10839 afterFx : function(o){
10841 this.applyStyles(o.afterStyle);
10844 this.addClass(o.afterCls);
10846 if(o.remove === true){
10849 Roo.callback(o.callback, o.scope, [this]);
10851 this.fxQueue.shift();
10857 getFxEl : function(){ // support for composite element fx
10858 return Roo.get(this.dom);
10862 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10863 animType = animType || 'run';
10865 var anim = Roo.lib.Anim[animType](
10867 (opt.duration || defaultDur) || .35,
10868 (opt.easing || defaultEase) || 'easeOut',
10870 Roo.callback(cb, this);
10879 // backwords compat
10880 Roo.Fx.resize = Roo.Fx.scale;
10882 //When included, Roo.Fx is automatically applied to Element so that all basic
10883 //effects are available directly via the Element API
10884 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10886 * Ext JS Library 1.1.1
10887 * Copyright(c) 2006-2007, Ext JS, LLC.
10889 * Originally Released Under LGPL - original licence link has changed is not relivant.
10892 * <script type="text/javascript">
10897 * @class Roo.CompositeElement
10898 * Standard composite class. Creates a Roo.Element for every element in the collection.
10900 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10901 * actions will be performed on all the elements in this collection.</b>
10903 * All methods return <i>this</i> and can be chained.
10905 var els = Roo.select("#some-el div.some-class", true);
10906 // or select directly from an existing element
10907 var el = Roo.get('some-el');
10908 el.select('div.some-class', true);
10910 els.setWidth(100); // all elements become 100 width
10911 els.hide(true); // all elements fade out and hide
10913 els.setWidth(100).hide(true);
10916 Roo.CompositeElement = function(els){
10917 this.elements = [];
10918 this.addElements(els);
10920 Roo.CompositeElement.prototype = {
10922 addElements : function(els){
10923 if(!els) return this;
10924 if(typeof els == "string"){
10925 els = Roo.Element.selectorFunction(els);
10927 var yels = this.elements;
10928 var index = yels.length-1;
10929 for(var i = 0, len = els.length; i < len; i++) {
10930 yels[++index] = Roo.get(els[i]);
10936 * Clears this composite and adds the elements returned by the passed selector.
10937 * @param {String/Array} els A string CSS selector, an array of elements or an element
10938 * @return {CompositeElement} this
10940 fill : function(els){
10941 this.elements = [];
10947 * Filters this composite to only elements that match the passed selector.
10948 * @param {String} selector A string CSS selector
10949 * @return {CompositeElement} this
10951 filter : function(selector){
10953 this.each(function(el){
10954 if(el.is(selector)){
10955 els[els.length] = el.dom;
10962 invoke : function(fn, args){
10963 var els = this.elements;
10964 for(var i = 0, len = els.length; i < len; i++) {
10965 Roo.Element.prototype[fn].apply(els[i], args);
10970 * Adds elements to this composite.
10971 * @param {String/Array} els A string CSS selector, an array of elements or an element
10972 * @return {CompositeElement} this
10974 add : function(els){
10975 if(typeof els == "string"){
10976 this.addElements(Roo.Element.selectorFunction(els));
10977 }else if(els.length !== undefined){
10978 this.addElements(els);
10980 this.addElements([els]);
10985 * Calls the passed function passing (el, this, index) for each element in this composite.
10986 * @param {Function} fn The function to call
10987 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10988 * @return {CompositeElement} this
10990 each : function(fn, scope){
10991 var els = this.elements;
10992 for(var i = 0, len = els.length; i < len; i++){
10993 if(fn.call(scope || els[i], els[i], this, i) === false) {
11001 * Returns the Element object at the specified index
11002 * @param {Number} index
11003 * @return {Roo.Element}
11005 item : function(index){
11006 return this.elements[index] || null;
11010 * Returns the first Element
11011 * @return {Roo.Element}
11013 first : function(){
11014 return this.item(0);
11018 * Returns the last Element
11019 * @return {Roo.Element}
11022 return this.item(this.elements.length-1);
11026 * Returns the number of elements in this composite
11029 getCount : function(){
11030 return this.elements.length;
11034 * Returns true if this composite contains the passed element
11037 contains : function(el){
11038 return this.indexOf(el) !== -1;
11042 * Returns true if this composite contains the passed element
11045 indexOf : function(el){
11046 return this.elements.indexOf(Roo.get(el));
11051 * Removes the specified element(s).
11052 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11053 * or an array of any of those.
11054 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11055 * @return {CompositeElement} this
11057 removeElement : function(el, removeDom){
11058 if(el instanceof Array){
11059 for(var i = 0, len = el.length; i < len; i++){
11060 this.removeElement(el[i]);
11064 var index = typeof el == 'number' ? el : this.indexOf(el);
11067 var d = this.elements[index];
11071 d.parentNode.removeChild(d);
11074 this.elements.splice(index, 1);
11080 * Replaces the specified element with the passed element.
11081 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11083 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11084 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11085 * @return {CompositeElement} this
11087 replaceElement : function(el, replacement, domReplace){
11088 var index = typeof el == 'number' ? el : this.indexOf(el);
11091 this.elements[index].replaceWith(replacement);
11093 this.elements.splice(index, 1, Roo.get(replacement))
11100 * Removes all elements.
11102 clear : function(){
11103 this.elements = [];
11107 Roo.CompositeElement.createCall = function(proto, fnName){
11108 if(!proto[fnName]){
11109 proto[fnName] = function(){
11110 return this.invoke(fnName, arguments);
11114 for(var fnName in Roo.Element.prototype){
11115 if(typeof Roo.Element.prototype[fnName] == "function"){
11116 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11122 * Ext JS Library 1.1.1
11123 * Copyright(c) 2006-2007, Ext JS, LLC.
11125 * Originally Released Under LGPL - original licence link has changed is not relivant.
11128 * <script type="text/javascript">
11132 * @class Roo.CompositeElementLite
11133 * @extends Roo.CompositeElement
11134 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11136 var els = Roo.select("#some-el div.some-class");
11137 // or select directly from an existing element
11138 var el = Roo.get('some-el');
11139 el.select('div.some-class');
11141 els.setWidth(100); // all elements become 100 width
11142 els.hide(true); // all elements fade out and hide
11144 els.setWidth(100).hide(true);
11145 </code></pre><br><br>
11146 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11147 * actions will be performed on all the elements in this collection.</b>
11149 Roo.CompositeElementLite = function(els){
11150 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11151 this.el = new Roo.Element.Flyweight();
11153 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11154 addElements : function(els){
11156 if(els instanceof Array){
11157 this.elements = this.elements.concat(els);
11159 var yels = this.elements;
11160 var index = yels.length-1;
11161 for(var i = 0, len = els.length; i < len; i++) {
11162 yels[++index] = els[i];
11168 invoke : function(fn, args){
11169 var els = this.elements;
11171 for(var i = 0, len = els.length; i < len; i++) {
11173 Roo.Element.prototype[fn].apply(el, args);
11178 * Returns a flyweight Element of the dom element object at the specified index
11179 * @param {Number} index
11180 * @return {Roo.Element}
11182 item : function(index){
11183 if(!this.elements[index]){
11186 this.el.dom = this.elements[index];
11190 // fixes scope with flyweight
11191 addListener : function(eventName, handler, scope, opt){
11192 var els = this.elements;
11193 for(var i = 0, len = els.length; i < len; i++) {
11194 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11200 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11201 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11202 * a reference to the dom node, use el.dom.</b>
11203 * @param {Function} fn The function to call
11204 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11205 * @return {CompositeElement} this
11207 each : function(fn, scope){
11208 var els = this.elements;
11210 for(var i = 0, len = els.length; i < len; i++){
11212 if(fn.call(scope || el, el, this, i) === false){
11219 indexOf : function(el){
11220 return this.elements.indexOf(Roo.getDom(el));
11223 replaceElement : function(el, replacement, domReplace){
11224 var index = typeof el == 'number' ? el : this.indexOf(el);
11226 replacement = Roo.getDom(replacement);
11228 var d = this.elements[index];
11229 d.parentNode.insertBefore(replacement, d);
11230 d.parentNode.removeChild(d);
11232 this.elements.splice(index, 1, replacement);
11237 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11241 * Ext JS Library 1.1.1
11242 * Copyright(c) 2006-2007, Ext JS, LLC.
11244 * Originally Released Under LGPL - original licence link has changed is not relivant.
11247 * <script type="text/javascript">
11253 * @class Roo.data.Connection
11254 * @extends Roo.util.Observable
11255 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11256 * either to a configured URL, or to a URL specified at request time.<br><br>
11258 * Requests made by this class are asynchronous, and will return immediately. No data from
11259 * the server will be available to the statement immediately following the {@link #request} call.
11260 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11262 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11263 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11264 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11265 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11266 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11267 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11268 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11269 * standard DOM methods.
11271 * @param {Object} config a configuration object.
11273 Roo.data.Connection = function(config){
11274 Roo.apply(this, config);
11277 * @event beforerequest
11278 * Fires before a network request is made to retrieve a data object.
11279 * @param {Connection} conn This Connection object.
11280 * @param {Object} options The options config object passed to the {@link #request} method.
11282 "beforerequest" : true,
11284 * @event requestcomplete
11285 * Fires if the request was successfully completed.
11286 * @param {Connection} conn This Connection object.
11287 * @param {Object} response The XHR object containing the response data.
11288 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11289 * @param {Object} options The options config object passed to the {@link #request} method.
11291 "requestcomplete" : true,
11293 * @event requestexception
11294 * Fires if an error HTTP status was returned from the server.
11295 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11296 * @param {Connection} conn This Connection object.
11297 * @param {Object} response The XHR object containing the response data.
11298 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11299 * @param {Object} options The options config object passed to the {@link #request} method.
11301 "requestexception" : true
11303 Roo.data.Connection.superclass.constructor.call(this);
11306 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11308 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11311 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11312 * extra parameters to each request made by this object. (defaults to undefined)
11315 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11316 * to each request made by this object. (defaults to undefined)
11319 * @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)
11322 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11326 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11332 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11335 disableCaching: true,
11338 * Sends an HTTP request to a remote server.
11339 * @param {Object} options An object which may contain the following properties:<ul>
11340 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11341 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11342 * request, a url encoded string or a function to call to get either.</li>
11343 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11344 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11345 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11346 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11347 * <li>options {Object} The parameter to the request call.</li>
11348 * <li>success {Boolean} True if the request succeeded.</li>
11349 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11351 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11352 * The callback is passed the following parameters:<ul>
11353 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11354 * <li>options {Object} The parameter to the request call.</li>
11356 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11357 * The callback is passed the following parameters:<ul>
11358 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11359 * <li>options {Object} The parameter to the request call.</li>
11361 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11362 * for the callback function. Defaults to the browser window.</li>
11363 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11364 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11365 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11366 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11367 * params for the post data. Any params will be appended to the URL.</li>
11368 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11370 * @return {Number} transactionId
11372 request : function(o){
11373 if(this.fireEvent("beforerequest", this, o) !== false){
11376 if(typeof p == "function"){
11377 p = p.call(o.scope||window, o);
11379 if(typeof p == "object"){
11380 p = Roo.urlEncode(o.params);
11382 if(this.extraParams){
11383 var extras = Roo.urlEncode(this.extraParams);
11384 p = p ? (p + '&' + extras) : extras;
11387 var url = o.url || this.url;
11388 if(typeof url == 'function'){
11389 url = url.call(o.scope||window, o);
11393 var form = Roo.getDom(o.form);
11394 url = url || form.action;
11396 var enctype = form.getAttribute("enctype");
11397 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11398 return this.doFormUpload(o, p, url);
11400 var f = Roo.lib.Ajax.serializeForm(form);
11401 p = p ? (p + '&' + f) : f;
11404 var hs = o.headers;
11405 if(this.defaultHeaders){
11406 hs = Roo.apply(hs || {}, this.defaultHeaders);
11413 success: this.handleResponse,
11414 failure: this.handleFailure,
11416 argument: {options: o},
11417 timeout : o.timeout || this.timeout
11420 var method = o.method||this.method||(p ? "POST" : "GET");
11422 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11423 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11426 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11430 }else if(this.autoAbort !== false){
11434 if((method == 'GET' && p) || o.xmlData){
11435 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11438 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11439 return this.transId;
11441 Roo.callback(o.callback, o.scope, [o, null, null]);
11447 * Determine whether this object has a request outstanding.
11448 * @param {Number} transactionId (Optional) defaults to the last transaction
11449 * @return {Boolean} True if there is an outstanding request.
11451 isLoading : function(transId){
11453 return Roo.lib.Ajax.isCallInProgress(transId);
11455 return this.transId ? true : false;
11460 * Aborts any outstanding request.
11461 * @param {Number} transactionId (Optional) defaults to the last transaction
11463 abort : function(transId){
11464 if(transId || this.isLoading()){
11465 Roo.lib.Ajax.abort(transId || this.transId);
11470 handleResponse : function(response){
11471 this.transId = false;
11472 var options = response.argument.options;
11473 response.argument = options ? options.argument : null;
11474 this.fireEvent("requestcomplete", this, response, options);
11475 Roo.callback(options.success, options.scope, [response, options]);
11476 Roo.callback(options.callback, options.scope, [options, true, response]);
11480 handleFailure : function(response, e){
11481 this.transId = false;
11482 var options = response.argument.options;
11483 response.argument = options ? options.argument : null;
11484 this.fireEvent("requestexception", this, response, options, e);
11485 Roo.callback(options.failure, options.scope, [response, options]);
11486 Roo.callback(options.callback, options.scope, [options, false, response]);
11490 doFormUpload : function(o, ps, url){
11492 var frame = document.createElement('iframe');
11495 frame.className = 'x-hidden';
11497 frame.src = Roo.SSL_SECURE_URL;
11499 document.body.appendChild(frame);
11502 document.frames[id].name = id;
11505 var form = Roo.getDom(o.form);
11507 form.method = 'POST';
11508 form.enctype = form.encoding = 'multipart/form-data';
11514 if(ps){ // add dynamic params
11516 ps = Roo.urlDecode(ps, false);
11518 if(ps.hasOwnProperty(k)){
11519 hd = document.createElement('input');
11520 hd.type = 'hidden';
11523 form.appendChild(hd);
11530 var r = { // bogus response object
11535 r.argument = o ? o.argument : null;
11540 doc = frame.contentWindow.document;
11542 doc = (frame.contentDocument || window.frames[id].document);
11544 if(doc && doc.body){
11545 r.responseText = doc.body.innerHTML;
11547 if(doc && doc.XMLDocument){
11548 r.responseXML = doc.XMLDocument;
11550 r.responseXML = doc;
11557 Roo.EventManager.removeListener(frame, 'load', cb, this);
11559 this.fireEvent("requestcomplete", this, r, o);
11560 Roo.callback(o.success, o.scope, [r, o]);
11561 Roo.callback(o.callback, o.scope, [o, true, r]);
11563 setTimeout(function(){document.body.removeChild(frame);}, 100);
11566 Roo.EventManager.on(frame, 'load', cb, this);
11569 if(hiddens){ // remove dynamic params
11570 for(var i = 0, len = hiddens.length; i < len; i++){
11571 form.removeChild(hiddens[i]);
11578 * Ext JS Library 1.1.1
11579 * Copyright(c) 2006-2007, Ext JS, LLC.
11581 * Originally Released Under LGPL - original licence link has changed is not relivant.
11584 * <script type="text/javascript">
11588 * Global Ajax request class.
11591 * @extends Roo.data.Connection
11594 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11595 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11596 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11597 * @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)
11598 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11599 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11600 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11602 Roo.Ajax = new Roo.data.Connection({
11611 * Serialize the passed form into a url encoded string
11613 * @param {String/HTMLElement} form
11616 serializeForm : function(form){
11617 return Roo.lib.Ajax.serializeForm(form);
11621 * Ext JS Library 1.1.1
11622 * Copyright(c) 2006-2007, Ext JS, LLC.
11624 * Originally Released Under LGPL - original licence link has changed is not relivant.
11627 * <script type="text/javascript">
11632 * @class Roo.UpdateManager
11633 * @extends Roo.util.Observable
11634 * Provides AJAX-style update for Element object.<br><br>
11637 * // Get it from a Roo.Element object
11638 * var el = Roo.get("foo");
11639 * var mgr = el.getUpdateManager();
11640 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11642 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11644 * // or directly (returns the same UpdateManager instance)
11645 * var mgr = new Roo.UpdateManager("myElementId");
11646 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11647 * mgr.on("update", myFcnNeedsToKnow);
11649 // short handed call directly from the element object
11650 Roo.get("foo").load({
11654 text: "Loading Foo..."
11658 * Create new UpdateManager directly.
11659 * @param {String/HTMLElement/Roo.Element} el The element to update
11660 * @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).
11662 Roo.UpdateManager = function(el, forceNew){
11664 if(!forceNew && el.updateManager){
11665 return el.updateManager;
11668 * The Element object
11669 * @type Roo.Element
11673 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11676 this.defaultUrl = null;
11680 * @event beforeupdate
11681 * Fired before an update is made, return false from your handler and the update is cancelled.
11682 * @param {Roo.Element} el
11683 * @param {String/Object/Function} url
11684 * @param {String/Object} params
11686 "beforeupdate": true,
11689 * Fired after successful update is made.
11690 * @param {Roo.Element} el
11691 * @param {Object} oResponseObject The response Object
11696 * Fired on update failure.
11697 * @param {Roo.Element} el
11698 * @param {Object} oResponseObject The response Object
11702 var d = Roo.UpdateManager.defaults;
11704 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11707 this.sslBlankUrl = d.sslBlankUrl;
11709 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11712 this.disableCaching = d.disableCaching;
11714 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11717 this.indicatorText = d.indicatorText;
11719 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11722 this.showLoadIndicator = d.showLoadIndicator;
11724 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11727 this.timeout = d.timeout;
11730 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11733 this.loadScripts = d.loadScripts;
11736 * Transaction object of current executing transaction
11738 this.transaction = null;
11743 this.autoRefreshProcId = null;
11745 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11748 this.refreshDelegate = this.refresh.createDelegate(this);
11750 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11753 this.updateDelegate = this.update.createDelegate(this);
11755 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11758 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11762 this.successDelegate = this.processSuccess.createDelegate(this);
11766 this.failureDelegate = this.processFailure.createDelegate(this);
11768 if(!this.renderer){
11770 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11772 this.renderer = new Roo.UpdateManager.BasicRenderer();
11775 Roo.UpdateManager.superclass.constructor.call(this);
11778 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11780 * Get the Element this UpdateManager is bound to
11781 * @return {Roo.Element} The element
11783 getEl : function(){
11787 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11788 * @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:
11791 url: "your-url.php",<br/>
11792 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11793 callback: yourFunction,<br/>
11794 scope: yourObject, //(optional scope) <br/>
11795 discardUrl: false, <br/>
11796 nocache: false,<br/>
11797 text: "Loading...",<br/>
11799 scripts: false<br/>
11802 * The only required property is url. The optional properties nocache, text and scripts
11803 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11804 * @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}
11805 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11806 * @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.
11808 update : function(url, params, callback, discardUrl){
11809 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11810 var method = this.method,
11812 if(typeof url == "object"){ // must be config object
11815 params = params || cfg.params;
11816 callback = callback || cfg.callback;
11817 discardUrl = discardUrl || cfg.discardUrl;
11818 if(callback && cfg.scope){
11819 callback = callback.createDelegate(cfg.scope);
11821 if(typeof cfg.method != "undefined"){method = cfg.method;};
11822 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11823 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11824 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11825 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11827 this.showLoading();
11829 this.defaultUrl = url;
11831 if(typeof url == "function"){
11832 url = url.call(this);
11835 method = method || (params ? "POST" : "GET");
11836 if(method == "GET"){
11837 url = this.prepareUrl(url);
11840 var o = Roo.apply(cfg ||{}, {
11843 success: this.successDelegate,
11844 failure: this.failureDelegate,
11845 callback: undefined,
11846 timeout: (this.timeout*1000),
11847 argument: {"url": url, "form": null, "callback": callback, "params": params}
11849 Roo.log("updated manager called with timeout of " + o.timeout);
11850 this.transaction = Roo.Ajax.request(o);
11855 * 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.
11856 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11857 * @param {String/HTMLElement} form The form Id or form element
11858 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11859 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11860 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11862 formUpdate : function(form, url, reset, callback){
11863 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11864 if(typeof url == "function"){
11865 url = url.call(this);
11867 form = Roo.getDom(form);
11868 this.transaction = Roo.Ajax.request({
11871 success: this.successDelegate,
11872 failure: this.failureDelegate,
11873 timeout: (this.timeout*1000),
11874 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11876 this.showLoading.defer(1, this);
11881 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11882 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11884 refresh : function(callback){
11885 if(this.defaultUrl == null){
11888 this.update(this.defaultUrl, null, callback, true);
11892 * Set this element to auto refresh.
11893 * @param {Number} interval How often to update (in seconds).
11894 * @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)
11895 * @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}
11896 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11897 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11899 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11901 this.update(url || this.defaultUrl, params, callback, true);
11903 if(this.autoRefreshProcId){
11904 clearInterval(this.autoRefreshProcId);
11906 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11910 * Stop auto refresh on this element.
11912 stopAutoRefresh : function(){
11913 if(this.autoRefreshProcId){
11914 clearInterval(this.autoRefreshProcId);
11915 delete this.autoRefreshProcId;
11919 isAutoRefreshing : function(){
11920 return this.autoRefreshProcId ? true : false;
11923 * Called to update the element to "Loading" state. Override to perform custom action.
11925 showLoading : function(){
11926 if(this.showLoadIndicator){
11927 this.el.update(this.indicatorText);
11932 * Adds unique parameter to query string if disableCaching = true
11935 prepareUrl : function(url){
11936 if(this.disableCaching){
11937 var append = "_dc=" + (new Date().getTime());
11938 if(url.indexOf("?") !== -1){
11939 url += "&" + append;
11941 url += "?" + append;
11950 processSuccess : function(response){
11951 this.transaction = null;
11952 if(response.argument.form && response.argument.reset){
11953 try{ // put in try/catch since some older FF releases had problems with this
11954 response.argument.form.reset();
11957 if(this.loadScripts){
11958 this.renderer.render(this.el, response, this,
11959 this.updateComplete.createDelegate(this, [response]));
11961 this.renderer.render(this.el, response, this);
11962 this.updateComplete(response);
11966 updateComplete : function(response){
11967 this.fireEvent("update", this.el, response);
11968 if(typeof response.argument.callback == "function"){
11969 response.argument.callback(this.el, true, response);
11976 processFailure : function(response){
11977 this.transaction = null;
11978 this.fireEvent("failure", this.el, response);
11979 if(typeof response.argument.callback == "function"){
11980 response.argument.callback(this.el, false, response);
11985 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11986 * @param {Object} renderer The object implementing the render() method
11988 setRenderer : function(renderer){
11989 this.renderer = renderer;
11992 getRenderer : function(){
11993 return this.renderer;
11997 * Set the defaultUrl used for updates
11998 * @param {String/Function} defaultUrl The url or a function to call to get the url
12000 setDefaultUrl : function(defaultUrl){
12001 this.defaultUrl = defaultUrl;
12005 * Aborts the executing transaction
12007 abort : function(){
12008 if(this.transaction){
12009 Roo.Ajax.abort(this.transaction);
12014 * Returns true if an update is in progress
12015 * @return {Boolean}
12017 isUpdating : function(){
12018 if(this.transaction){
12019 return Roo.Ajax.isLoading(this.transaction);
12026 * @class Roo.UpdateManager.defaults
12027 * @static (not really - but it helps the doc tool)
12028 * The defaults collection enables customizing the default properties of UpdateManager
12030 Roo.UpdateManager.defaults = {
12032 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12038 * True to process scripts by default (Defaults to false).
12041 loadScripts : false,
12044 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12047 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12049 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12052 disableCaching : false,
12054 * Whether to show indicatorText when loading (Defaults to true).
12057 showLoadIndicator : true,
12059 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12062 indicatorText : '<div class="loading-indicator">Loading...</div>'
12066 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12068 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12069 * @param {String/HTMLElement/Roo.Element} el The element to update
12070 * @param {String} url The url
12071 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12072 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12075 * @member Roo.UpdateManager
12077 Roo.UpdateManager.updateElement = function(el, url, params, options){
12078 var um = Roo.get(el, true).getUpdateManager();
12079 Roo.apply(um, options);
12080 um.update(url, params, options ? options.callback : null);
12082 // alias for backwards compat
12083 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12085 * @class Roo.UpdateManager.BasicRenderer
12086 * Default Content renderer. Updates the elements innerHTML with the responseText.
12088 Roo.UpdateManager.BasicRenderer = function(){};
12090 Roo.UpdateManager.BasicRenderer.prototype = {
12092 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12093 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12094 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12095 * @param {Roo.Element} el The element being rendered
12096 * @param {Object} response The YUI Connect response object
12097 * @param {UpdateManager} updateManager The calling update manager
12098 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12100 render : function(el, response, updateManager, callback){
12101 el.update(response.responseText, updateManager.loadScripts, callback);
12107 * (c)) Alan Knowles
12113 * @class Roo.DomTemplate
12114 * @extends Roo.Template
12115 * An effort at a dom based template engine..
12117 * Similar to XTemplate, except it uses dom parsing to create the template..
12119 * Supported features:
12124 {a_variable} - output encoded.
12125 {a_variable.format:("Y-m-d")} - call a method on the variable
12126 {a_variable:raw} - unencoded output
12127 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12128 {a_variable:this.method_on_template(...)} - call a method on the template object.
12133 <div roo-for="a_variable or condition.."></div>
12134 <div roo-if="a_variable or condition"></div>
12135 <div roo-exec="some javascript"></div>
12136 <div roo-name="named_template"></div>
12141 Roo.DomTemplate = function()
12143 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12150 Roo.extend(Roo.DomTemplate, Roo.Template, {
12152 * id counter for sub templates.
12156 * flag to indicate if dom parser is inside a pre,
12157 * it will strip whitespace if not.
12162 * The various sub templates
12170 * basic tag replacing syntax
12173 * // you can fake an object call by doing this
12177 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12178 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12180 iterChild : function (node, method) {
12182 var oldPre = this.inPre;
12183 if (node.tagName == 'PRE') {
12186 for( var i = 0; i < node.childNodes.length; i++) {
12187 method.call(this, node.childNodes[i]);
12189 this.inPre = oldPre;
12195 * compile the template
12197 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12200 compile: function()
12204 // covert the html into DOM...
12208 doc = document.implementation.createHTMLDocument("");
12209 doc.documentElement.innerHTML = this.html ;
12210 div = doc.documentElement;
12212 // old IE... - nasty -- it causes all sorts of issues.. with
12213 // images getting pulled from server..
12214 div = document.createElement('div');
12215 div.innerHTML = this.html;
12217 //doc.documentElement.innerHTML = htmlBody
12223 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12225 var tpls = this.tpls;
12227 // create a top level template from the snippet..
12229 //Roo.log(div.innerHTML);
12236 body : div.innerHTML,
12249 Roo.each(tpls, function(tp){
12250 this.compileTpl(tp);
12251 this.tpls[tp.id] = tp;
12254 this.master = tpls[0];
12260 compileNode : function(node, istop) {
12265 // skip anything not a tag..
12266 if (node.nodeType != 1) {
12267 if (node.nodeType == 3 && !this.inPre) {
12268 // reduce white space..
12269 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12292 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12293 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12294 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12295 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12301 // just itterate children..
12302 this.iterChild(node,this.compileNode);
12305 tpl.uid = this.id++;
12306 tpl.value = node.getAttribute('roo-' + tpl.attr);
12307 node.removeAttribute('roo-'+ tpl.attr);
12308 if (tpl.attr != 'name') {
12309 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12310 node.parentNode.replaceChild(placeholder, node);
12313 var placeholder = document.createElement('span');
12314 placeholder.className = 'roo-tpl-' + tpl.value;
12315 node.parentNode.replaceChild(placeholder, node);
12318 // parent now sees '{domtplXXXX}
12319 this.iterChild(node,this.compileNode);
12321 // we should now have node body...
12322 var div = document.createElement('div');
12323 div.appendChild(node);
12325 // this has the unfortunate side effect of converting tagged attributes
12326 // eg. href="{...}" into %7C...%7D
12327 // this has been fixed by searching for those combo's although it's a bit hacky..
12330 tpl.body = div.innerHTML;
12337 switch (tpl.value) {
12338 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12339 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12340 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12345 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12349 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12353 tpl.id = tpl.value; // replace non characters???
12359 this.tpls.push(tpl);
12369 * Compile a segment of the template into a 'sub-template'
12375 compileTpl : function(tpl)
12377 var fm = Roo.util.Format;
12378 var useF = this.disableFormats !== true;
12380 var sep = Roo.isGecko ? "+\n" : ",\n";
12382 var undef = function(str) {
12383 Roo.debug && Roo.log("Property not found :" + str);
12387 //Roo.log(tpl.body);
12391 var fn = function(m, lbrace, name, format, args)
12394 //Roo.log(arguments);
12395 args = args ? args.replace(/\\'/g,"'") : args;
12396 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12397 if (typeof(format) == 'undefined') {
12398 format = 'htmlEncode';
12400 if (format == 'raw' ) {
12404 if(name.substr(0, 6) == 'domtpl'){
12405 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12408 // build an array of options to determine if value is undefined..
12410 // basically get 'xxxx.yyyy' then do
12411 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12412 // (function () { Roo.log("Property not found"); return ''; })() :
12417 Roo.each(name.split('.'), function(st) {
12418 lookfor += (lookfor.length ? '.': '') + st;
12419 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12422 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12425 if(format && useF){
12427 args = args ? ',' + args : "";
12429 if(format.substr(0, 5) != "this."){
12430 format = "fm." + format + '(';
12432 format = 'this.call("'+ format.substr(5) + '", ';
12436 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12439 if (args && args.length) {
12440 // called with xxyx.yuu:(test,test)
12442 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12444 // raw.. - :raw modifier..
12445 return "'"+ sep + udef_st + name + ")"+sep+"'";
12449 // branched to use + in gecko and [].join() in others
12451 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12452 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12455 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12456 body.push(tpl.body.replace(/(\r\n|\n)/g,
12457 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12458 body.push("'].join('');};};");
12459 body = body.join('');
12462 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12464 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12471 * same as applyTemplate, except it's done to one of the subTemplates
12472 * when using named templates, you can do:
12474 * var str = pl.applySubTemplate('your-name', values);
12477 * @param {Number} id of the template
12478 * @param {Object} values to apply to template
12479 * @param {Object} parent (normaly the instance of this object)
12481 applySubTemplate : function(id, values, parent)
12485 var t = this.tpls[id];
12489 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12490 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12494 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12501 if(t.execCall && t.execCall.call(this, values, parent)){
12505 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12511 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12512 parent = t.target ? values : parent;
12513 if(t.forCall && vs instanceof Array){
12515 for(var i = 0, len = vs.length; i < len; i++){
12517 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12519 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12521 //Roo.log(t.compiled);
12525 return buf.join('');
12528 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12533 return t.compiled.call(this, vs, parent);
12535 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12537 //Roo.log(t.compiled);
12545 applyTemplate : function(values){
12546 return this.master.compiled.call(this, values, {});
12547 //var s = this.subs;
12550 apply : function(){
12551 return this.applyTemplate.apply(this, arguments);
12556 Roo.DomTemplate.from = function(el){
12557 el = Roo.getDom(el);
12558 return new Roo.Domtemplate(el.value || el.innerHTML);
12561 * Ext JS Library 1.1.1
12562 * Copyright(c) 2006-2007, Ext JS, LLC.
12564 * Originally Released Under LGPL - original licence link has changed is not relivant.
12567 * <script type="text/javascript">
12571 * @class Roo.util.DelayedTask
12572 * Provides a convenient method of performing setTimeout where a new
12573 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12574 * You can use this class to buffer
12575 * the keypress events for a certain number of milliseconds, and perform only if they stop
12576 * for that amount of time.
12577 * @constructor The parameters to this constructor serve as defaults and are not required.
12578 * @param {Function} fn (optional) The default function to timeout
12579 * @param {Object} scope (optional) The default scope of that timeout
12580 * @param {Array} args (optional) The default Array of arguments
12582 Roo.util.DelayedTask = function(fn, scope, args){
12583 var id = null, d, t;
12585 var call = function(){
12586 var now = new Date().getTime();
12590 fn.apply(scope, args || []);
12594 * Cancels any pending timeout and queues a new one
12595 * @param {Number} delay The milliseconds to delay
12596 * @param {Function} newFn (optional) Overrides function passed to constructor
12597 * @param {Object} newScope (optional) Overrides scope passed to constructor
12598 * @param {Array} newArgs (optional) Overrides args passed to constructor
12600 this.delay = function(delay, newFn, newScope, newArgs){
12601 if(id && delay != d){
12605 t = new Date().getTime();
12607 scope = newScope || scope;
12608 args = newArgs || args;
12610 id = setInterval(call, d);
12615 * Cancel the last queued timeout
12617 this.cancel = function(){
12625 * Ext JS Library 1.1.1
12626 * Copyright(c) 2006-2007, Ext JS, LLC.
12628 * Originally Released Under LGPL - original licence link has changed is not relivant.
12631 * <script type="text/javascript">
12635 Roo.util.TaskRunner = function(interval){
12636 interval = interval || 10;
12637 var tasks = [], removeQueue = [];
12639 var running = false;
12641 var stopThread = function(){
12647 var startThread = function(){
12650 id = setInterval(runTasks, interval);
12654 var removeTask = function(task){
12655 removeQueue.push(task);
12661 var runTasks = function(){
12662 if(removeQueue.length > 0){
12663 for(var i = 0, len = removeQueue.length; i < len; i++){
12664 tasks.remove(removeQueue[i]);
12667 if(tasks.length < 1){
12672 var now = new Date().getTime();
12673 for(var i = 0, len = tasks.length; i < len; ++i){
12675 var itime = now - t.taskRunTime;
12676 if(t.interval <= itime){
12677 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12678 t.taskRunTime = now;
12679 if(rt === false || t.taskRunCount === t.repeat){
12684 if(t.duration && t.duration <= (now - t.taskStartTime)){
12691 * Queues a new task.
12692 * @param {Object} task
12694 this.start = function(task){
12696 task.taskStartTime = new Date().getTime();
12697 task.taskRunTime = 0;
12698 task.taskRunCount = 0;
12703 this.stop = function(task){
12708 this.stopAll = function(){
12710 for(var i = 0, len = tasks.length; i < len; i++){
12711 if(tasks[i].onStop){
12720 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12722 * Ext JS Library 1.1.1
12723 * Copyright(c) 2006-2007, Ext JS, LLC.
12725 * Originally Released Under LGPL - original licence link has changed is not relivant.
12728 * <script type="text/javascript">
12733 * @class Roo.util.MixedCollection
12734 * @extends Roo.util.Observable
12735 * A Collection class that maintains both numeric indexes and keys and exposes events.
12737 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12738 * collection (defaults to false)
12739 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12740 * and return the key value for that item. This is used when available to look up the key on items that
12741 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12742 * equivalent to providing an implementation for the {@link #getKey} method.
12744 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12752 * Fires when the collection is cleared.
12757 * Fires when an item is added to the collection.
12758 * @param {Number} index The index at which the item was added.
12759 * @param {Object} o The item added.
12760 * @param {String} key The key associated with the added item.
12765 * Fires when an item is replaced in the collection.
12766 * @param {String} key he key associated with the new added.
12767 * @param {Object} old The item being replaced.
12768 * @param {Object} new The new item.
12773 * Fires when an item is removed from the collection.
12774 * @param {Object} o The item being removed.
12775 * @param {String} key (optional) The key associated with the removed item.
12780 this.allowFunctions = allowFunctions === true;
12782 this.getKey = keyFn;
12784 Roo.util.MixedCollection.superclass.constructor.call(this);
12787 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12788 allowFunctions : false,
12791 * Adds an item to the collection.
12792 * @param {String} key The key to associate with the item
12793 * @param {Object} o The item to add.
12794 * @return {Object} The item added.
12796 add : function(key, o){
12797 if(arguments.length == 1){
12799 key = this.getKey(o);
12801 if(typeof key == "undefined" || key === null){
12803 this.items.push(o);
12804 this.keys.push(null);
12806 var old = this.map[key];
12808 return this.replace(key, o);
12811 this.items.push(o);
12813 this.keys.push(key);
12815 this.fireEvent("add", this.length-1, o, key);
12820 * MixedCollection has a generic way to fetch keys if you implement getKey.
12823 var mc = new Roo.util.MixedCollection();
12824 mc.add(someEl.dom.id, someEl);
12825 mc.add(otherEl.dom.id, otherEl);
12829 var mc = new Roo.util.MixedCollection();
12830 mc.getKey = function(el){
12836 // or via the constructor
12837 var mc = new Roo.util.MixedCollection(false, function(el){
12843 * @param o {Object} The item for which to find the key.
12844 * @return {Object} The key for the passed item.
12846 getKey : function(o){
12851 * Replaces an item in the collection.
12852 * @param {String} key The key associated with the item to replace, or the item to replace.
12853 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12854 * @return {Object} The new item.
12856 replace : function(key, o){
12857 if(arguments.length == 1){
12859 key = this.getKey(o);
12861 var old = this.item(key);
12862 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12863 return this.add(key, o);
12865 var index = this.indexOfKey(key);
12866 this.items[index] = o;
12868 this.fireEvent("replace", key, old, o);
12873 * Adds all elements of an Array or an Object to the collection.
12874 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12875 * an Array of values, each of which are added to the collection.
12877 addAll : function(objs){
12878 if(arguments.length > 1 || objs instanceof Array){
12879 var args = arguments.length > 1 ? arguments : objs;
12880 for(var i = 0, len = args.length; i < len; i++){
12884 for(var key in objs){
12885 if(this.allowFunctions || typeof objs[key] != "function"){
12886 this.add(key, objs[key]);
12893 * Executes the specified function once for every item in the collection, passing each
12894 * item as the first and only parameter. returning false from the function will stop the iteration.
12895 * @param {Function} fn The function to execute for each item.
12896 * @param {Object} scope (optional) The scope in which to execute the function.
12898 each : function(fn, scope){
12899 var items = [].concat(this.items); // each safe for removal
12900 for(var i = 0, len = items.length; i < len; i++){
12901 if(fn.call(scope || items[i], items[i], i, len) === false){
12908 * Executes the specified function once for every key in the collection, passing each
12909 * key, and its associated item as the first two parameters.
12910 * @param {Function} fn The function to execute for each item.
12911 * @param {Object} scope (optional) The scope in which to execute the function.
12913 eachKey : function(fn, scope){
12914 for(var i = 0, len = this.keys.length; i < len; i++){
12915 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12920 * Returns the first item in the collection which elicits a true return value from the
12921 * passed selection function.
12922 * @param {Function} fn The selection function to execute for each item.
12923 * @param {Object} scope (optional) The scope in which to execute the function.
12924 * @return {Object} The first item in the collection which returned true from the selection function.
12926 find : function(fn, scope){
12927 for(var i = 0, len = this.items.length; i < len; i++){
12928 if(fn.call(scope || window, this.items[i], this.keys[i])){
12929 return this.items[i];
12936 * Inserts an item at the specified index in the collection.
12937 * @param {Number} index The index to insert the item at.
12938 * @param {String} key The key to associate with the new item, or the item itself.
12939 * @param {Object} o (optional) If the second parameter was a key, the new item.
12940 * @return {Object} The item inserted.
12942 insert : function(index, key, o){
12943 if(arguments.length == 2){
12945 key = this.getKey(o);
12947 if(index >= this.length){
12948 return this.add(key, o);
12951 this.items.splice(index, 0, o);
12952 if(typeof key != "undefined" && key != null){
12955 this.keys.splice(index, 0, key);
12956 this.fireEvent("add", index, o, key);
12961 * Removed an item from the collection.
12962 * @param {Object} o The item to remove.
12963 * @return {Object} The item removed.
12965 remove : function(o){
12966 return this.removeAt(this.indexOf(o));
12970 * Remove an item from a specified index in the collection.
12971 * @param {Number} index The index within the collection of the item to remove.
12973 removeAt : function(index){
12974 if(index < this.length && index >= 0){
12976 var o = this.items[index];
12977 this.items.splice(index, 1);
12978 var key = this.keys[index];
12979 if(typeof key != "undefined"){
12980 delete this.map[key];
12982 this.keys.splice(index, 1);
12983 this.fireEvent("remove", o, key);
12988 * Removed an item associated with the passed key fom the collection.
12989 * @param {String} key The key of the item to remove.
12991 removeKey : function(key){
12992 return this.removeAt(this.indexOfKey(key));
12996 * Returns the number of items in the collection.
12997 * @return {Number} the number of items in the collection.
12999 getCount : function(){
13000 return this.length;
13004 * Returns index within the collection of the passed Object.
13005 * @param {Object} o The item to find the index of.
13006 * @return {Number} index of the item.
13008 indexOf : function(o){
13009 if(!this.items.indexOf){
13010 for(var i = 0, len = this.items.length; i < len; i++){
13011 if(this.items[i] == o) return i;
13015 return this.items.indexOf(o);
13020 * Returns index within the collection of the passed key.
13021 * @param {String} key The key to find the index of.
13022 * @return {Number} index of the key.
13024 indexOfKey : function(key){
13025 if(!this.keys.indexOf){
13026 for(var i = 0, len = this.keys.length; i < len; i++){
13027 if(this.keys[i] == key) return i;
13031 return this.keys.indexOf(key);
13036 * Returns the item associated with the passed key OR index. Key has priority over index.
13037 * @param {String/Number} key The key or index of the item.
13038 * @return {Object} The item associated with the passed key.
13040 item : function(key){
13041 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13042 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13046 * Returns the item at the specified index.
13047 * @param {Number} index The index of the item.
13050 itemAt : function(index){
13051 return this.items[index];
13055 * Returns the item associated with the passed key.
13056 * @param {String/Number} key The key of the item.
13057 * @return {Object} The item associated with the passed key.
13059 key : function(key){
13060 return this.map[key];
13064 * Returns true if the collection contains the passed Object as an item.
13065 * @param {Object} o The Object to look for in the collection.
13066 * @return {Boolean} True if the collection contains the Object as an item.
13068 contains : function(o){
13069 return this.indexOf(o) != -1;
13073 * Returns true if the collection contains the passed Object as a key.
13074 * @param {String} key The key to look for in the collection.
13075 * @return {Boolean} True if the collection contains the Object as a key.
13077 containsKey : function(key){
13078 return typeof this.map[key] != "undefined";
13082 * Removes all items from the collection.
13084 clear : function(){
13089 this.fireEvent("clear");
13093 * Returns the first item in the collection.
13094 * @return {Object} the first item in the collection..
13096 first : function(){
13097 return this.items[0];
13101 * Returns the last item in the collection.
13102 * @return {Object} the last item in the collection..
13105 return this.items[this.length-1];
13108 _sort : function(property, dir, fn){
13109 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13110 fn = fn || function(a, b){
13113 var c = [], k = this.keys, items = this.items;
13114 for(var i = 0, len = items.length; i < len; i++){
13115 c[c.length] = {key: k[i], value: items[i], index: i};
13117 c.sort(function(a, b){
13118 var v = fn(a[property], b[property]) * dsc;
13120 v = (a.index < b.index ? -1 : 1);
13124 for(var i = 0, len = c.length; i < len; i++){
13125 items[i] = c[i].value;
13128 this.fireEvent("sort", this);
13132 * Sorts this collection with the passed comparison function
13133 * @param {String} direction (optional) "ASC" or "DESC"
13134 * @param {Function} fn (optional) comparison function
13136 sort : function(dir, fn){
13137 this._sort("value", dir, fn);
13141 * Sorts this collection by keys
13142 * @param {String} direction (optional) "ASC" or "DESC"
13143 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13145 keySort : function(dir, fn){
13146 this._sort("key", dir, fn || function(a, b){
13147 return String(a).toUpperCase()-String(b).toUpperCase();
13152 * Returns a range of items in this collection
13153 * @param {Number} startIndex (optional) defaults to 0
13154 * @param {Number} endIndex (optional) default to the last item
13155 * @return {Array} An array of items
13157 getRange : function(start, end){
13158 var items = this.items;
13159 if(items.length < 1){
13162 start = start || 0;
13163 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13166 for(var i = start; i <= end; i++) {
13167 r[r.length] = items[i];
13170 for(var i = start; i >= end; i--) {
13171 r[r.length] = items[i];
13178 * Filter the <i>objects</i> in this collection by a specific property.
13179 * Returns a new collection that has been filtered.
13180 * @param {String} property A property on your objects
13181 * @param {String/RegExp} value Either string that the property values
13182 * should start with or a RegExp to test against the property
13183 * @return {MixedCollection} The new filtered collection
13185 filter : function(property, value){
13186 if(!value.exec){ // not a regex
13187 value = String(value);
13188 if(value.length == 0){
13189 return this.clone();
13191 value = new RegExp("^" + Roo.escapeRe(value), "i");
13193 return this.filterBy(function(o){
13194 return o && value.test(o[property]);
13199 * Filter by a function. * Returns a new collection that has been filtered.
13200 * The passed function will be called with each
13201 * object in the collection. If the function returns true, the value is included
13202 * otherwise it is filtered.
13203 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13204 * @param {Object} scope (optional) The scope of the function (defaults to this)
13205 * @return {MixedCollection} The new filtered collection
13207 filterBy : function(fn, scope){
13208 var r = new Roo.util.MixedCollection();
13209 r.getKey = this.getKey;
13210 var k = this.keys, it = this.items;
13211 for(var i = 0, len = it.length; i < len; i++){
13212 if(fn.call(scope||this, it[i], k[i])){
13213 r.add(k[i], it[i]);
13220 * Creates a duplicate of this collection
13221 * @return {MixedCollection}
13223 clone : function(){
13224 var r = new Roo.util.MixedCollection();
13225 var k = this.keys, it = this.items;
13226 for(var i = 0, len = it.length; i < len; i++){
13227 r.add(k[i], it[i]);
13229 r.getKey = this.getKey;
13234 * Returns the item associated with the passed key or index.
13236 * @param {String/Number} key The key or index of the item.
13237 * @return {Object} The item associated with the passed key.
13239 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13241 * Ext JS Library 1.1.1
13242 * Copyright(c) 2006-2007, Ext JS, LLC.
13244 * Originally Released Under LGPL - original licence link has changed is not relivant.
13247 * <script type="text/javascript">
13250 * @class Roo.util.JSON
13251 * Modified version of Douglas Crockford"s json.js that doesn"t
13252 * mess with the Object prototype
13253 * http://www.json.org/js.html
13256 Roo.util.JSON = new (function(){
13257 var useHasOwn = {}.hasOwnProperty ? true : false;
13259 // crashes Safari in some instances
13260 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13262 var pad = function(n) {
13263 return n < 10 ? "0" + n : n;
13276 var encodeString = function(s){
13277 if (/["\\\x00-\x1f]/.test(s)) {
13278 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13283 c = b.charCodeAt();
13285 Math.floor(c / 16).toString(16) +
13286 (c % 16).toString(16);
13289 return '"' + s + '"';
13292 var encodeArray = function(o){
13293 var a = ["["], b, i, l = o.length, v;
13294 for (i = 0; i < l; i += 1) {
13296 switch (typeof v) {
13305 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13313 var encodeDate = function(o){
13314 return '"' + o.getFullYear() + "-" +
13315 pad(o.getMonth() + 1) + "-" +
13316 pad(o.getDate()) + "T" +
13317 pad(o.getHours()) + ":" +
13318 pad(o.getMinutes()) + ":" +
13319 pad(o.getSeconds()) + '"';
13323 * Encodes an Object, Array or other value
13324 * @param {Mixed} o The variable to encode
13325 * @return {String} The JSON string
13327 this.encode = function(o)
13329 // should this be extended to fully wrap stringify..
13331 if(typeof o == "undefined" || o === null){
13333 }else if(o instanceof Array){
13334 return encodeArray(o);
13335 }else if(o instanceof Date){
13336 return encodeDate(o);
13337 }else if(typeof o == "string"){
13338 return encodeString(o);
13339 }else if(typeof o == "number"){
13340 return isFinite(o) ? String(o) : "null";
13341 }else if(typeof o == "boolean"){
13344 var a = ["{"], b, i, v;
13346 if(!useHasOwn || o.hasOwnProperty(i)) {
13348 switch (typeof v) {
13357 a.push(this.encode(i), ":",
13358 v === null ? "null" : this.encode(v));
13369 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13370 * @param {String} json The JSON string
13371 * @return {Object} The resulting object
13373 this.decode = function(json){
13375 return /** eval:var:json */ eval("(" + json + ')');
13379 * Shorthand for {@link Roo.util.JSON#encode}
13380 * @member Roo encode
13382 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13384 * Shorthand for {@link Roo.util.JSON#decode}
13385 * @member Roo decode
13387 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13390 * Ext JS Library 1.1.1
13391 * Copyright(c) 2006-2007, Ext JS, LLC.
13393 * Originally Released Under LGPL - original licence link has changed is not relivant.
13396 * <script type="text/javascript">
13400 * @class Roo.util.Format
13401 * Reusable data formatting functions
13404 Roo.util.Format = function(){
13405 var trimRe = /^\s+|\s+$/g;
13408 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13409 * @param {String} value The string to truncate
13410 * @param {Number} length The maximum length to allow before truncating
13411 * @return {String} The converted text
13413 ellipsis : function(value, len){
13414 if(value && value.length > len){
13415 return value.substr(0, len-3)+"...";
13421 * Checks a reference and converts it to empty string if it is undefined
13422 * @param {Mixed} value Reference to check
13423 * @return {Mixed} Empty string if converted, otherwise the original value
13425 undef : function(value){
13426 return typeof value != "undefined" ? value : "";
13430 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13431 * @param {String} value The string to encode
13432 * @return {String} The encoded text
13434 htmlEncode : function(value){
13435 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13439 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13440 * @param {String} value The string to decode
13441 * @return {String} The decoded text
13443 htmlDecode : function(value){
13444 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13448 * Trims any whitespace from either side of a string
13449 * @param {String} value The text to trim
13450 * @return {String} The trimmed text
13452 trim : function(value){
13453 return String(value).replace(trimRe, "");
13457 * Returns a substring from within an original string
13458 * @param {String} value The original text
13459 * @param {Number} start The start index of the substring
13460 * @param {Number} length The length of the substring
13461 * @return {String} The substring
13463 substr : function(value, start, length){
13464 return String(value).substr(start, length);
13468 * Converts a string to all lower case letters
13469 * @param {String} value The text to convert
13470 * @return {String} The converted text
13472 lowercase : function(value){
13473 return String(value).toLowerCase();
13477 * Converts a string to all upper case letters
13478 * @param {String} value The text to convert
13479 * @return {String} The converted text
13481 uppercase : function(value){
13482 return String(value).toUpperCase();
13486 * Converts the first character only of a string to upper case
13487 * @param {String} value The text to convert
13488 * @return {String} The converted text
13490 capitalize : function(value){
13491 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13495 call : function(value, fn){
13496 if(arguments.length > 2){
13497 var args = Array.prototype.slice.call(arguments, 2);
13498 args.unshift(value);
13500 return /** eval:var:value */ eval(fn).apply(window, args);
13502 /** eval:var:value */
13503 return /** eval:var:value */ eval(fn).call(window, value);
13509 * safer version of Math.toFixed..??/
13510 * @param {Number/String} value The numeric value to format
13511 * @param {Number/String} value Decimal places
13512 * @return {String} The formatted currency string
13514 toFixed : function(v, n)
13516 // why not use to fixed - precision is buggered???
13518 return Math.round(v-0);
13520 var fact = Math.pow(10,n+1);
13521 v = (Math.round((v-0)*fact))/fact;
13522 var z = (''+fact).substring(2);
13523 if (v == Math.floor(v)) {
13524 return Math.floor(v) + '.' + z;
13527 // now just padd decimals..
13528 var ps = String(v).split('.');
13529 var fd = (ps[1] + z);
13530 var r = fd.substring(0,n);
13531 var rm = fd.substring(n);
13533 return ps[0] + '.' + r;
13535 r*=1; // turn it into a number;
13537 if (String(r).length != n) {
13540 r = String(r).substring(1); // chop the end off.
13543 return ps[0] + '.' + r;
13548 * Format a number as US currency
13549 * @param {Number/String} value The numeric value to format
13550 * @return {String} The formatted currency string
13552 usMoney : function(v){
13553 return '$' + Roo.util.Format.number(v);
13558 * eventually this should probably emulate php's number_format
13559 * @param {Number/String} value The numeric value to format
13560 * @param {Number} decimals number of decimal places
13561 * @return {String} The formatted currency string
13563 number : function(v,decimals)
13565 // multiply and round.
13566 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13567 var mul = Math.pow(10, decimals);
13568 var zero = String(mul).substring(1);
13569 v = (Math.round((v-0)*mul))/mul;
13571 // if it's '0' number.. then
13573 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13575 var ps = v.split('.');
13579 var r = /(\d+)(\d{3})/;
13581 while (r.test(whole)) {
13582 whole = whole.replace(r, '$1' + ',' + '$2');
13588 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13589 // does not have decimals
13590 (decimals ? ('.' + zero) : '');
13593 return whole + sub ;
13597 * Parse a value into a formatted date using the specified format pattern.
13598 * @param {Mixed} value The value to format
13599 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13600 * @return {String} The formatted date string
13602 date : function(v, format){
13606 if(!(v instanceof Date)){
13607 v = new Date(Date.parse(v));
13609 return v.dateFormat(format || Roo.util.Format.defaults.date);
13613 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13614 * @param {String} format Any valid date format string
13615 * @return {Function} The date formatting function
13617 dateRenderer : function(format){
13618 return function(v){
13619 return Roo.util.Format.date(v, format);
13624 stripTagsRE : /<\/?[^>]+>/gi,
13627 * Strips all HTML tags
13628 * @param {Mixed} value The text from which to strip tags
13629 * @return {String} The stripped text
13631 stripTags : function(v){
13632 return !v ? v : String(v).replace(this.stripTagsRE, "");
13636 Roo.util.Format.defaults = {
13640 * Ext JS Library 1.1.1
13641 * Copyright(c) 2006-2007, Ext JS, LLC.
13643 * Originally Released Under LGPL - original licence link has changed is not relivant.
13646 * <script type="text/javascript">
13653 * @class Roo.MasterTemplate
13654 * @extends Roo.Template
13655 * Provides a template that can have child templates. The syntax is:
13657 var t = new Roo.MasterTemplate(
13658 '<select name="{name}">',
13659 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13662 t.add('options', {value: 'foo', text: 'bar'});
13663 // or you can add multiple child elements in one shot
13664 t.addAll('options', [
13665 {value: 'foo', text: 'bar'},
13666 {value: 'foo2', text: 'bar2'},
13667 {value: 'foo3', text: 'bar3'}
13669 // then append, applying the master template values
13670 t.append('my-form', {name: 'my-select'});
13672 * A name attribute for the child template is not required if you have only one child
13673 * template or you want to refer to them by index.
13675 Roo.MasterTemplate = function(){
13676 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13677 this.originalHtml = this.html;
13679 var m, re = this.subTemplateRe;
13682 while(m = re.exec(this.html)){
13683 var name = m[1], content = m[2];
13688 tpl : new Roo.Template(content)
13691 st[name] = st[subIndex];
13693 st[subIndex].tpl.compile();
13694 st[subIndex].tpl.call = this.call.createDelegate(this);
13697 this.subCount = subIndex;
13700 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13702 * The regular expression used to match sub templates
13706 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13709 * Applies the passed values to a child template.
13710 * @param {String/Number} name (optional) The name or index of the child template
13711 * @param {Array/Object} values The values to be applied to the template
13712 * @return {MasterTemplate} this
13714 add : function(name, values){
13715 if(arguments.length == 1){
13716 values = arguments[0];
13719 var s = this.subs[name];
13720 s.buffer[s.buffer.length] = s.tpl.apply(values);
13725 * Applies all the passed values to a child template.
13726 * @param {String/Number} name (optional) The name or index of the child template
13727 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13728 * @param {Boolean} reset (optional) True to reset the template first
13729 * @return {MasterTemplate} this
13731 fill : function(name, values, reset){
13733 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13741 for(var i = 0, len = values.length; i < len; i++){
13742 this.add(name, values[i]);
13748 * Resets the template for reuse
13749 * @return {MasterTemplate} this
13751 reset : function(){
13753 for(var i = 0; i < this.subCount; i++){
13759 applyTemplate : function(values){
13761 var replaceIndex = -1;
13762 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13763 return s[++replaceIndex].buffer.join("");
13765 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13768 apply : function(){
13769 return this.applyTemplate.apply(this, arguments);
13772 compile : function(){return this;}
13776 * Alias for fill().
13779 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13781 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13782 * var tpl = Roo.MasterTemplate.from('element-id');
13783 * @param {String/HTMLElement} el
13784 * @param {Object} config
13787 Roo.MasterTemplate.from = function(el, config){
13788 el = Roo.getDom(el);
13789 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13792 * Ext JS Library 1.1.1
13793 * Copyright(c) 2006-2007, Ext JS, LLC.
13795 * Originally Released Under LGPL - original licence link has changed is not relivant.
13798 * <script type="text/javascript">
13803 * @class Roo.util.CSS
13804 * Utility class for manipulating CSS rules
13807 Roo.util.CSS = function(){
13809 var doc = document;
13811 var camelRe = /(-[a-z])/gi;
13812 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13816 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13817 * tag and appended to the HEAD of the document.
13818 * @param {String|Object} cssText The text containing the css rules
13819 * @param {String} id An id to add to the stylesheet for later removal
13820 * @return {StyleSheet}
13822 createStyleSheet : function(cssText, id){
13824 var head = doc.getElementsByTagName("head")[0];
13825 var nrules = doc.createElement("style");
13826 nrules.setAttribute("type", "text/css");
13828 nrules.setAttribute("id", id);
13830 if (typeof(cssText) != 'string') {
13831 // support object maps..
13832 // not sure if this a good idea..
13833 // perhaps it should be merged with the general css handling
13834 // and handle js style props.
13835 var cssTextNew = [];
13836 for(var n in cssText) {
13838 for(var k in cssText[n]) {
13839 citems.push( k + ' : ' +cssText[n][k] + ';' );
13841 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13844 cssText = cssTextNew.join("\n");
13850 head.appendChild(nrules);
13851 ss = nrules.styleSheet;
13852 ss.cssText = cssText;
13855 nrules.appendChild(doc.createTextNode(cssText));
13857 nrules.cssText = cssText;
13859 head.appendChild(nrules);
13860 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13862 this.cacheStyleSheet(ss);
13867 * Removes a style or link tag by id
13868 * @param {String} id The id of the tag
13870 removeStyleSheet : function(id){
13871 var existing = doc.getElementById(id);
13873 existing.parentNode.removeChild(existing);
13878 * Dynamically swaps an existing stylesheet reference for a new one
13879 * @param {String} id The id of an existing link tag to remove
13880 * @param {String} url The href of the new stylesheet to include
13882 swapStyleSheet : function(id, url){
13883 this.removeStyleSheet(id);
13884 var ss = doc.createElement("link");
13885 ss.setAttribute("rel", "stylesheet");
13886 ss.setAttribute("type", "text/css");
13887 ss.setAttribute("id", id);
13888 ss.setAttribute("href", url);
13889 doc.getElementsByTagName("head")[0].appendChild(ss);
13893 * Refresh the rule cache if you have dynamically added stylesheets
13894 * @return {Object} An object (hash) of rules indexed by selector
13896 refreshCache : function(){
13897 return this.getRules(true);
13901 cacheStyleSheet : function(stylesheet){
13905 try{// try catch for cross domain access issue
13906 var ssRules = stylesheet.cssRules || stylesheet.rules;
13907 for(var j = ssRules.length-1; j >= 0; --j){
13908 rules[ssRules[j].selectorText] = ssRules[j];
13914 * Gets all css rules for the document
13915 * @param {Boolean} refreshCache true to refresh the internal cache
13916 * @return {Object} An object (hash) of rules indexed by selector
13918 getRules : function(refreshCache){
13919 if(rules == null || refreshCache){
13921 var ds = doc.styleSheets;
13922 for(var i =0, len = ds.length; i < len; i++){
13924 this.cacheStyleSheet(ds[i]);
13932 * Gets an an individual CSS rule by selector(s)
13933 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13934 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13935 * @return {CSSRule} The CSS rule or null if one is not found
13937 getRule : function(selector, refreshCache){
13938 var rs = this.getRules(refreshCache);
13939 if(!(selector instanceof Array)){
13940 return rs[selector];
13942 for(var i = 0; i < selector.length; i++){
13943 if(rs[selector[i]]){
13944 return rs[selector[i]];
13952 * Updates a rule property
13953 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13954 * @param {String} property The css property
13955 * @param {String} value The new value for the property
13956 * @return {Boolean} true If a rule was found and updated
13958 updateRule : function(selector, property, value){
13959 if(!(selector instanceof Array)){
13960 var rule = this.getRule(selector);
13962 rule.style[property.replace(camelRe, camelFn)] = value;
13966 for(var i = 0; i < selector.length; i++){
13967 if(this.updateRule(selector[i], property, value)){
13977 * Ext JS Library 1.1.1
13978 * Copyright(c) 2006-2007, Ext JS, LLC.
13980 * Originally Released Under LGPL - original licence link has changed is not relivant.
13983 * <script type="text/javascript">
13989 * @class Roo.util.ClickRepeater
13990 * @extends Roo.util.Observable
13992 * A wrapper class which can be applied to any element. Fires a "click" event while the
13993 * mouse is pressed. The interval between firings may be specified in the config but
13994 * defaults to 10 milliseconds.
13996 * Optionally, a CSS class may be applied to the element during the time it is pressed.
13998 * @cfg {String/HTMLElement/Element} el The element to act as a button.
13999 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14000 * Similar to an autorepeat key delay.
14001 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14002 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14003 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14004 * "interval" and "delay" are ignored. "immediate" is honored.
14005 * @cfg {Boolean} preventDefault True to prevent the default click event
14006 * @cfg {Boolean} stopDefault True to stop the default click event
14009 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14010 * 2007-02-02 jvs Renamed to ClickRepeater
14011 * 2007-02-03 jvs Modifications for FF Mac and Safari
14014 * @param {String/HTMLElement/Element} el The element to listen on
14015 * @param {Object} config
14017 Roo.util.ClickRepeater = function(el, config)
14019 this.el = Roo.get(el);
14020 this.el.unselectable();
14022 Roo.apply(this, config);
14027 * Fires when the mouse button is depressed.
14028 * @param {Roo.util.ClickRepeater} this
14030 "mousedown" : true,
14033 * Fires on a specified interval during the time the element is pressed.
14034 * @param {Roo.util.ClickRepeater} this
14039 * Fires when the mouse key is released.
14040 * @param {Roo.util.ClickRepeater} this
14045 this.el.on("mousedown", this.handleMouseDown, this);
14046 if(this.preventDefault || this.stopDefault){
14047 this.el.on("click", function(e){
14048 if(this.preventDefault){
14049 e.preventDefault();
14051 if(this.stopDefault){
14057 // allow inline handler
14059 this.on("click", this.handler, this.scope || this);
14062 Roo.util.ClickRepeater.superclass.constructor.call(this);
14065 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14068 preventDefault : true,
14069 stopDefault : false,
14073 handleMouseDown : function(){
14074 clearTimeout(this.timer);
14076 if(this.pressClass){
14077 this.el.addClass(this.pressClass);
14079 this.mousedownTime = new Date();
14081 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14082 this.el.on("mouseout", this.handleMouseOut, this);
14084 this.fireEvent("mousedown", this);
14085 this.fireEvent("click", this);
14087 this.timer = this.click.defer(this.delay || this.interval, this);
14091 click : function(){
14092 this.fireEvent("click", this);
14093 this.timer = this.click.defer(this.getInterval(), this);
14097 getInterval: function(){
14098 if(!this.accelerate){
14099 return this.interval;
14101 var pressTime = this.mousedownTime.getElapsed();
14102 if(pressTime < 500){
14104 }else if(pressTime < 1700){
14106 }else if(pressTime < 2600){
14108 }else if(pressTime < 3500){
14110 }else if(pressTime < 4400){
14112 }else if(pressTime < 5300){
14114 }else if(pressTime < 6200){
14122 handleMouseOut : function(){
14123 clearTimeout(this.timer);
14124 if(this.pressClass){
14125 this.el.removeClass(this.pressClass);
14127 this.el.on("mouseover", this.handleMouseReturn, this);
14131 handleMouseReturn : function(){
14132 this.el.un("mouseover", this.handleMouseReturn);
14133 if(this.pressClass){
14134 this.el.addClass(this.pressClass);
14140 handleMouseUp : function(){
14141 clearTimeout(this.timer);
14142 this.el.un("mouseover", this.handleMouseReturn);
14143 this.el.un("mouseout", this.handleMouseOut);
14144 Roo.get(document).un("mouseup", this.handleMouseUp);
14145 this.el.removeClass(this.pressClass);
14146 this.fireEvent("mouseup", this);
14150 * Ext JS Library 1.1.1
14151 * Copyright(c) 2006-2007, Ext JS, LLC.
14153 * Originally Released Under LGPL - original licence link has changed is not relivant.
14156 * <script type="text/javascript">
14161 * @class Roo.KeyNav
14162 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14163 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14164 * way to implement custom navigation schemes for any UI component.</p>
14165 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14166 * pageUp, pageDown, del, home, end. Usage:</p>
14168 var nav = new Roo.KeyNav("my-element", {
14169 "left" : function(e){
14170 this.moveLeft(e.ctrlKey);
14172 "right" : function(e){
14173 this.moveRight(e.ctrlKey);
14175 "enter" : function(e){
14182 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14183 * @param {Object} config The config
14185 Roo.KeyNav = function(el, config){
14186 this.el = Roo.get(el);
14187 Roo.apply(this, config);
14188 if(!this.disabled){
14189 this.disabled = true;
14194 Roo.KeyNav.prototype = {
14196 * @cfg {Boolean} disabled
14197 * True to disable this KeyNav instance (defaults to false)
14201 * @cfg {String} defaultEventAction
14202 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14203 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14204 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14206 defaultEventAction: "stopEvent",
14208 * @cfg {Boolean} forceKeyDown
14209 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14210 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14211 * handle keydown instead of keypress.
14213 forceKeyDown : false,
14216 prepareEvent : function(e){
14217 var k = e.getKey();
14218 var h = this.keyToHandler[k];
14219 //if(h && this[h]){
14220 // e.stopPropagation();
14222 if(Roo.isSafari && h && k >= 37 && k <= 40){
14228 relay : function(e){
14229 var k = e.getKey();
14230 var h = this.keyToHandler[k];
14232 if(this.doRelay(e, this[h], h) !== true){
14233 e[this.defaultEventAction]();
14239 doRelay : function(e, h, hname){
14240 return h.call(this.scope || this, e);
14243 // possible handlers
14257 // quick lookup hash
14274 * Enable this KeyNav
14276 enable: function(){
14278 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14279 // the EventObject will normalize Safari automatically
14280 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14281 this.el.on("keydown", this.relay, this);
14283 this.el.on("keydown", this.prepareEvent, this);
14284 this.el.on("keypress", this.relay, this);
14286 this.disabled = false;
14291 * Disable this KeyNav
14293 disable: function(){
14294 if(!this.disabled){
14295 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14296 this.el.un("keydown", this.relay);
14298 this.el.un("keydown", this.prepareEvent);
14299 this.el.un("keypress", this.relay);
14301 this.disabled = true;
14306 * Ext JS Library 1.1.1
14307 * Copyright(c) 2006-2007, Ext JS, LLC.
14309 * Originally Released Under LGPL - original licence link has changed is not relivant.
14312 * <script type="text/javascript">
14317 * @class Roo.KeyMap
14318 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14319 * The constructor accepts the same config object as defined by {@link #addBinding}.
14320 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14321 * combination it will call the function with this signature (if the match is a multi-key
14322 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14323 * A KeyMap can also handle a string representation of keys.<br />
14326 // map one key by key code
14327 var map = new Roo.KeyMap("my-element", {
14328 key: 13, // or Roo.EventObject.ENTER
14333 // map multiple keys to one action by string
14334 var map = new Roo.KeyMap("my-element", {
14340 // map multiple keys to multiple actions by strings and array of codes
14341 var map = new Roo.KeyMap("my-element", [
14344 fn: function(){ alert("Return was pressed"); }
14347 fn: function(){ alert('a, b or c was pressed'); }
14352 fn: function(){ alert('Control + shift + tab was pressed.'); }
14356 * <b>Note: A KeyMap starts enabled</b>
14358 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14359 * @param {Object} config The config (see {@link #addBinding})
14360 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14362 Roo.KeyMap = function(el, config, eventName){
14363 this.el = Roo.get(el);
14364 this.eventName = eventName || "keydown";
14365 this.bindings = [];
14367 this.addBinding(config);
14372 Roo.KeyMap.prototype = {
14374 * True to stop the event from bubbling and prevent the default browser action if the
14375 * key was handled by the KeyMap (defaults to false)
14381 * Add a new binding to this KeyMap. The following config object properties are supported:
14383 Property Type Description
14384 ---------- --------------- ----------------------------------------------------------------------
14385 key String/Array A single keycode or an array of keycodes to handle
14386 shift Boolean True to handle key only when shift is pressed (defaults to false)
14387 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14388 alt Boolean True to handle key only when alt is pressed (defaults to false)
14389 fn Function The function to call when KeyMap finds the expected key combination
14390 scope Object The scope of the callback function
14396 var map = new Roo.KeyMap(document, {
14397 key: Roo.EventObject.ENTER,
14402 //Add a new binding to the existing KeyMap later
14410 * @param {Object/Array} config A single KeyMap config or an array of configs
14412 addBinding : function(config){
14413 if(config instanceof Array){
14414 for(var i = 0, len = config.length; i < len; i++){
14415 this.addBinding(config[i]);
14419 var keyCode = config.key,
14420 shift = config.shift,
14421 ctrl = config.ctrl,
14424 scope = config.scope;
14425 if(typeof keyCode == "string"){
14427 var keyString = keyCode.toUpperCase();
14428 for(var j = 0, len = keyString.length; j < len; j++){
14429 ks.push(keyString.charCodeAt(j));
14433 var keyArray = keyCode instanceof Array;
14434 var handler = function(e){
14435 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14436 var k = e.getKey();
14438 for(var i = 0, len = keyCode.length; i < len; i++){
14439 if(keyCode[i] == k){
14440 if(this.stopEvent){
14443 fn.call(scope || window, k, e);
14449 if(this.stopEvent){
14452 fn.call(scope || window, k, e);
14457 this.bindings.push(handler);
14461 * Shorthand for adding a single key listener
14462 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14463 * following options:
14464 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14465 * @param {Function} fn The function to call
14466 * @param {Object} scope (optional) The scope of the function
14468 on : function(key, fn, scope){
14469 var keyCode, shift, ctrl, alt;
14470 if(typeof key == "object" && !(key instanceof Array)){
14489 handleKeyDown : function(e){
14490 if(this.enabled){ //just in case
14491 var b = this.bindings;
14492 for(var i = 0, len = b.length; i < len; i++){
14493 b[i].call(this, e);
14499 * Returns true if this KeyMap is enabled
14500 * @return {Boolean}
14502 isEnabled : function(){
14503 return this.enabled;
14507 * Enables this KeyMap
14509 enable: function(){
14511 this.el.on(this.eventName, this.handleKeyDown, this);
14512 this.enabled = true;
14517 * Disable this KeyMap
14519 disable: function(){
14521 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14522 this.enabled = false;
14527 * Ext JS Library 1.1.1
14528 * Copyright(c) 2006-2007, Ext JS, LLC.
14530 * Originally Released Under LGPL - original licence link has changed is not relivant.
14533 * <script type="text/javascript">
14538 * @class Roo.util.TextMetrics
14539 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14540 * wide, in pixels, a given block of text will be.
14543 Roo.util.TextMetrics = function(){
14547 * Measures the size of the specified text
14548 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14549 * that can affect the size of the rendered text
14550 * @param {String} text The text to measure
14551 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14552 * in order to accurately measure the text height
14553 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14555 measure : function(el, text, fixedWidth){
14557 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14560 shared.setFixedWidth(fixedWidth || 'auto');
14561 return shared.getSize(text);
14565 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14566 * the overhead of multiple calls to initialize the style properties on each measurement.
14567 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14568 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14569 * in order to accurately measure the text height
14570 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14572 createInstance : function(el, fixedWidth){
14573 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14580 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14581 var ml = new Roo.Element(document.createElement('div'));
14582 document.body.appendChild(ml.dom);
14583 ml.position('absolute');
14584 ml.setLeftTop(-1000, -1000);
14588 ml.setWidth(fixedWidth);
14593 * Returns the size of the specified text based on the internal element's style and width properties
14594 * @memberOf Roo.util.TextMetrics.Instance#
14595 * @param {String} text The text to measure
14596 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14598 getSize : function(text){
14600 var s = ml.getSize();
14606 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14607 * that can affect the size of the rendered text
14608 * @memberOf Roo.util.TextMetrics.Instance#
14609 * @param {String/HTMLElement} el The element, dom node or id
14611 bind : function(el){
14613 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14618 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14619 * to set a fixed width in order to accurately measure the text height.
14620 * @memberOf Roo.util.TextMetrics.Instance#
14621 * @param {Number} width The width to set on the element
14623 setFixedWidth : function(width){
14624 ml.setWidth(width);
14628 * Returns the measured width of the specified text
14629 * @memberOf Roo.util.TextMetrics.Instance#
14630 * @param {String} text The text to measure
14631 * @return {Number} width The width in pixels
14633 getWidth : function(text){
14634 ml.dom.style.width = 'auto';
14635 return this.getSize(text).width;
14639 * Returns the measured height of the specified text. For multiline text, be sure to call
14640 * {@link #setFixedWidth} if necessary.
14641 * @memberOf Roo.util.TextMetrics.Instance#
14642 * @param {String} text The text to measure
14643 * @return {Number} height The height in pixels
14645 getHeight : function(text){
14646 return this.getSize(text).height;
14650 instance.bind(bindTo);
14655 // backwards compat
14656 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14658 * Ext JS Library 1.1.1
14659 * Copyright(c) 2006-2007, Ext JS, LLC.
14661 * Originally Released Under LGPL - original licence link has changed is not relivant.
14664 * <script type="text/javascript">
14668 * @class Roo.state.Provider
14669 * Abstract base class for state provider implementations. This class provides methods
14670 * for encoding and decoding <b>typed</b> variables including dates and defines the
14671 * Provider interface.
14673 Roo.state.Provider = function(){
14675 * @event statechange
14676 * Fires when a state change occurs.
14677 * @param {Provider} this This state provider
14678 * @param {String} key The state key which was changed
14679 * @param {String} value The encoded value for the state
14682 "statechange": true
14685 Roo.state.Provider.superclass.constructor.call(this);
14687 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14689 * Returns the current value for a key
14690 * @param {String} name The key name
14691 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14692 * @return {Mixed} The state data
14694 get : function(name, defaultValue){
14695 return typeof this.state[name] == "undefined" ?
14696 defaultValue : this.state[name];
14700 * Clears a value from the state
14701 * @param {String} name The key name
14703 clear : function(name){
14704 delete this.state[name];
14705 this.fireEvent("statechange", this, name, null);
14709 * Sets the value for a key
14710 * @param {String} name The key name
14711 * @param {Mixed} value The value to set
14713 set : function(name, value){
14714 this.state[name] = value;
14715 this.fireEvent("statechange", this, name, value);
14719 * Decodes a string previously encoded with {@link #encodeValue}.
14720 * @param {String} value The value to decode
14721 * @return {Mixed} The decoded value
14723 decodeValue : function(cookie){
14724 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14725 var matches = re.exec(unescape(cookie));
14726 if(!matches || !matches[1]) return; // non state cookie
14727 var type = matches[1];
14728 var v = matches[2];
14731 return parseFloat(v);
14733 return new Date(Date.parse(v));
14738 var values = v.split("^");
14739 for(var i = 0, len = values.length; i < len; i++){
14740 all.push(this.decodeValue(values[i]));
14745 var values = v.split("^");
14746 for(var i = 0, len = values.length; i < len; i++){
14747 var kv = values[i].split("=");
14748 all[kv[0]] = this.decodeValue(kv[1]);
14757 * Encodes a value including type information. Decode with {@link #decodeValue}.
14758 * @param {Mixed} value The value to encode
14759 * @return {String} The encoded value
14761 encodeValue : function(v){
14763 if(typeof v == "number"){
14765 }else if(typeof v == "boolean"){
14766 enc = "b:" + (v ? "1" : "0");
14767 }else if(v instanceof Date){
14768 enc = "d:" + v.toGMTString();
14769 }else if(v instanceof Array){
14771 for(var i = 0, len = v.length; i < len; i++){
14772 flat += this.encodeValue(v[i]);
14773 if(i != len-1) flat += "^";
14776 }else if(typeof v == "object"){
14779 if(typeof v[key] != "function"){
14780 flat += key + "=" + this.encodeValue(v[key]) + "^";
14783 enc = "o:" + flat.substring(0, flat.length-1);
14787 return escape(enc);
14793 * Ext JS Library 1.1.1
14794 * Copyright(c) 2006-2007, Ext JS, LLC.
14796 * Originally Released Under LGPL - original licence link has changed is not relivant.
14799 * <script type="text/javascript">
14802 * @class Roo.state.Manager
14803 * This is the global state manager. By default all components that are "state aware" check this class
14804 * for state information if you don't pass them a custom state provider. In order for this class
14805 * to be useful, it must be initialized with a provider when your application initializes.
14807 // in your initialization function
14809 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14811 // supposed you have a {@link Roo.BorderLayout}
14812 var layout = new Roo.BorderLayout(...);
14813 layout.restoreState();
14814 // or a {Roo.BasicDialog}
14815 var dialog = new Roo.BasicDialog(...);
14816 dialog.restoreState();
14820 Roo.state.Manager = function(){
14821 var provider = new Roo.state.Provider();
14825 * Configures the default state provider for your application
14826 * @param {Provider} stateProvider The state provider to set
14828 setProvider : function(stateProvider){
14829 provider = stateProvider;
14833 * Returns the current value for a key
14834 * @param {String} name The key name
14835 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14836 * @return {Mixed} The state data
14838 get : function(key, defaultValue){
14839 return provider.get(key, defaultValue);
14843 * Sets the value for a key
14844 * @param {String} name The key name
14845 * @param {Mixed} value The state data
14847 set : function(key, value){
14848 provider.set(key, value);
14852 * Clears a value from the state
14853 * @param {String} name The key name
14855 clear : function(key){
14856 provider.clear(key);
14860 * Gets the currently configured state provider
14861 * @return {Provider} The state provider
14863 getProvider : function(){
14870 * Ext JS Library 1.1.1
14871 * Copyright(c) 2006-2007, Ext JS, LLC.
14873 * Originally Released Under LGPL - original licence link has changed is not relivant.
14876 * <script type="text/javascript">
14879 * @class Roo.state.CookieProvider
14880 * @extends Roo.state.Provider
14881 * The default Provider implementation which saves state via cookies.
14884 var cp = new Roo.state.CookieProvider({
14886 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14887 domain: "roojs.com"
14889 Roo.state.Manager.setProvider(cp);
14891 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14892 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14893 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14894 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14895 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14896 * domain the page is running on including the 'www' like 'www.roojs.com')
14897 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14899 * Create a new CookieProvider
14900 * @param {Object} config The configuration object
14902 Roo.state.CookieProvider = function(config){
14903 Roo.state.CookieProvider.superclass.constructor.call(this);
14905 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14906 this.domain = null;
14907 this.secure = false;
14908 Roo.apply(this, config);
14909 this.state = this.readCookies();
14912 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14914 set : function(name, value){
14915 if(typeof value == "undefined" || value === null){
14919 this.setCookie(name, value);
14920 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14924 clear : function(name){
14925 this.clearCookie(name);
14926 Roo.state.CookieProvider.superclass.clear.call(this, name);
14930 readCookies : function(){
14932 var c = document.cookie + ";";
14933 var re = /\s?(.*?)=(.*?);/g;
14935 while((matches = re.exec(c)) != null){
14936 var name = matches[1];
14937 var value = matches[2];
14938 if(name && name.substring(0,3) == "ys-"){
14939 cookies[name.substr(3)] = this.decodeValue(value);
14946 setCookie : function(name, value){
14947 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14948 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14949 ((this.path == null) ? "" : ("; path=" + this.path)) +
14950 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14951 ((this.secure == true) ? "; secure" : "");
14955 clearCookie : function(name){
14956 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14957 ((this.path == null) ? "" : ("; path=" + this.path)) +
14958 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14959 ((this.secure == true) ? "; secure" : "");
14963 * Ext JS Library 1.1.1
14964 * Copyright(c) 2006-2007, Ext JS, LLC.
14966 * Originally Released Under LGPL - original licence link has changed is not relivant.
14969 * <script type="text/javascript">
14974 * @class Roo.ComponentMgr
14975 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14978 Roo.ComponentMgr = function(){
14979 var all = new Roo.util.MixedCollection();
14983 * Registers a component.
14984 * @param {Roo.Component} c The component
14986 register : function(c){
14991 * Unregisters a component.
14992 * @param {Roo.Component} c The component
14994 unregister : function(c){
14999 * Returns a component by id
15000 * @param {String} id The component id
15002 get : function(id){
15003 return all.get(id);
15007 * Registers a function that will be called when a specified component is added to ComponentMgr
15008 * @param {String} id The component id
15009 * @param {Funtction} fn The callback function
15010 * @param {Object} scope The scope of the callback
15012 onAvailable : function(id, fn, scope){
15013 all.on("add", function(index, o){
15015 fn.call(scope || o, o);
15016 all.un("add", fn, scope);
15023 * Ext JS Library 1.1.1
15024 * Copyright(c) 2006-2007, Ext JS, LLC.
15026 * Originally Released Under LGPL - original licence link has changed is not relivant.
15029 * <script type="text/javascript">
15033 * @class Roo.Component
15034 * @extends Roo.util.Observable
15035 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15036 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15037 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15038 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15039 * All visual components (widgets) that require rendering into a layout should subclass Component.
15041 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15042 * 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
15043 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15045 Roo.Component = function(config){
15046 config = config || {};
15047 if(config.tagName || config.dom || typeof config == "string"){ // element object
15048 config = {el: config, id: config.id || config};
15050 this.initialConfig = config;
15052 Roo.apply(this, config);
15056 * Fires after the component is disabled.
15057 * @param {Roo.Component} this
15062 * Fires after the component is enabled.
15063 * @param {Roo.Component} this
15067 * @event beforeshow
15068 * Fires before the component is shown. Return false to stop the show.
15069 * @param {Roo.Component} this
15074 * Fires after the component is shown.
15075 * @param {Roo.Component} this
15079 * @event beforehide
15080 * Fires before the component is hidden. Return false to stop the hide.
15081 * @param {Roo.Component} this
15086 * Fires after the component is hidden.
15087 * @param {Roo.Component} this
15091 * @event beforerender
15092 * Fires before the component is rendered. Return false to stop the render.
15093 * @param {Roo.Component} this
15095 beforerender : true,
15098 * Fires after the component is rendered.
15099 * @param {Roo.Component} this
15103 * @event beforedestroy
15104 * Fires before the component is destroyed. Return false to stop the destroy.
15105 * @param {Roo.Component} this
15107 beforedestroy : true,
15110 * Fires after the component is destroyed.
15111 * @param {Roo.Component} this
15116 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15118 Roo.ComponentMgr.register(this);
15119 Roo.Component.superclass.constructor.call(this);
15120 this.initComponent();
15121 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15122 this.render(this.renderTo);
15123 delete this.renderTo;
15128 Roo.Component.AUTO_ID = 1000;
15130 Roo.extend(Roo.Component, Roo.util.Observable, {
15132 * @scope Roo.Component.prototype
15134 * true if this component is hidden. Read-only.
15139 * true if this component is disabled. Read-only.
15144 * true if this component has been rendered. Read-only.
15148 /** @cfg {String} disableClass
15149 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15151 disabledClass : "x-item-disabled",
15152 /** @cfg {Boolean} allowDomMove
15153 * Whether the component can move the Dom node when rendering (defaults to true).
15155 allowDomMove : true,
15156 /** @cfg {String} hideMode
15157 * How this component should hidden. Supported values are
15158 * "visibility" (css visibility), "offsets" (negative offset position) and
15159 * "display" (css display) - defaults to "display".
15161 hideMode: 'display',
15164 ctype : "Roo.Component",
15167 * @cfg {String} actionMode
15168 * which property holds the element that used for hide() / show() / disable() / enable()
15174 getActionEl : function(){
15175 return this[this.actionMode];
15178 initComponent : Roo.emptyFn,
15180 * If this is a lazy rendering component, render it to its container element.
15181 * @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.
15183 render : function(container, position){
15184 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15185 if(!container && this.el){
15186 this.el = Roo.get(this.el);
15187 container = this.el.dom.parentNode;
15188 this.allowDomMove = false;
15190 this.container = Roo.get(container);
15191 this.rendered = true;
15192 if(position !== undefined){
15193 if(typeof position == 'number'){
15194 position = this.container.dom.childNodes[position];
15196 position = Roo.getDom(position);
15199 this.onRender(this.container, position || null);
15201 this.el.addClass(this.cls);
15205 this.el.applyStyles(this.style);
15208 this.fireEvent("render", this);
15209 this.afterRender(this.container);
15221 // default function is not really useful
15222 onRender : function(ct, position){
15224 this.el = Roo.get(this.el);
15225 if(this.allowDomMove !== false){
15226 ct.dom.insertBefore(this.el.dom, position);
15232 getAutoCreate : function(){
15233 var cfg = typeof this.autoCreate == "object" ?
15234 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15235 if(this.id && !cfg.id){
15242 afterRender : Roo.emptyFn,
15245 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15246 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15248 destroy : function(){
15249 if(this.fireEvent("beforedestroy", this) !== false){
15250 this.purgeListeners();
15251 this.beforeDestroy();
15253 this.el.removeAllListeners();
15255 if(this.actionMode == "container"){
15256 this.container.remove();
15260 Roo.ComponentMgr.unregister(this);
15261 this.fireEvent("destroy", this);
15266 beforeDestroy : function(){
15271 onDestroy : function(){
15276 * Returns the underlying {@link Roo.Element}.
15277 * @return {Roo.Element} The element
15279 getEl : function(){
15284 * Returns the id of this component.
15287 getId : function(){
15292 * Try to focus this component.
15293 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15294 * @return {Roo.Component} this
15296 focus : function(selectText){
15299 if(selectText === true){
15300 this.el.dom.select();
15315 * Disable this component.
15316 * @return {Roo.Component} this
15318 disable : function(){
15322 this.disabled = true;
15323 this.fireEvent("disable", this);
15328 onDisable : function(){
15329 this.getActionEl().addClass(this.disabledClass);
15330 this.el.dom.disabled = true;
15334 * Enable this component.
15335 * @return {Roo.Component} this
15337 enable : function(){
15341 this.disabled = false;
15342 this.fireEvent("enable", this);
15347 onEnable : function(){
15348 this.getActionEl().removeClass(this.disabledClass);
15349 this.el.dom.disabled = false;
15353 * Convenience function for setting disabled/enabled by boolean.
15354 * @param {Boolean} disabled
15356 setDisabled : function(disabled){
15357 this[disabled ? "disable" : "enable"]();
15361 * Show this component.
15362 * @return {Roo.Component} this
15365 if(this.fireEvent("beforeshow", this) !== false){
15366 this.hidden = false;
15370 this.fireEvent("show", this);
15376 onShow : function(){
15377 var ae = this.getActionEl();
15378 if(this.hideMode == 'visibility'){
15379 ae.dom.style.visibility = "visible";
15380 }else if(this.hideMode == 'offsets'){
15381 ae.removeClass('x-hidden');
15383 ae.dom.style.display = "";
15388 * Hide this component.
15389 * @return {Roo.Component} this
15392 if(this.fireEvent("beforehide", this) !== false){
15393 this.hidden = true;
15397 this.fireEvent("hide", this);
15403 onHide : function(){
15404 var ae = this.getActionEl();
15405 if(this.hideMode == 'visibility'){
15406 ae.dom.style.visibility = "hidden";
15407 }else if(this.hideMode == 'offsets'){
15408 ae.addClass('x-hidden');
15410 ae.dom.style.display = "none";
15415 * Convenience function to hide or show this component by boolean.
15416 * @param {Boolean} visible True to show, false to hide
15417 * @return {Roo.Component} this
15419 setVisible: function(visible){
15429 * Returns true if this component is visible.
15431 isVisible : function(){
15432 return this.getActionEl().isVisible();
15435 cloneConfig : function(overrides){
15436 overrides = overrides || {};
15437 var id = overrides.id || Roo.id();
15438 var cfg = Roo.applyIf(overrides, this.initialConfig);
15439 cfg.id = id; // prevent dup id
15440 return new this.constructor(cfg);
15444 * Ext JS Library 1.1.1
15445 * Copyright(c) 2006-2007, Ext JS, LLC.
15447 * Originally Released Under LGPL - original licence link has changed is not relivant.
15450 * <script type="text/javascript">
15454 * @class Roo.BoxComponent
15455 * @extends Roo.Component
15456 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15457 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15458 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15459 * layout containers.
15461 * @param {Roo.Element/String/Object} config The configuration options.
15463 Roo.BoxComponent = function(config){
15464 Roo.Component.call(this, config);
15468 * Fires after the component is resized.
15469 * @param {Roo.Component} this
15470 * @param {Number} adjWidth The box-adjusted width that was set
15471 * @param {Number} adjHeight The box-adjusted height that was set
15472 * @param {Number} rawWidth The width that was originally specified
15473 * @param {Number} rawHeight The height that was originally specified
15478 * Fires after the component is moved.
15479 * @param {Roo.Component} this
15480 * @param {Number} x The new x position
15481 * @param {Number} y The new y position
15487 Roo.extend(Roo.BoxComponent, Roo.Component, {
15488 // private, set in afterRender to signify that the component has been rendered
15490 // private, used to defer height settings to subclasses
15491 deferHeight: false,
15492 /** @cfg {Number} width
15493 * width (optional) size of component
15495 /** @cfg {Number} height
15496 * height (optional) size of component
15500 * Sets the width and height of the component. This method fires the resize event. This method can accept
15501 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15502 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15503 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15504 * @return {Roo.BoxComponent} this
15506 setSize : function(w, h){
15507 // support for standard size objects
15508 if(typeof w == 'object'){
15513 if(!this.boxReady){
15519 // prevent recalcs when not needed
15520 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15523 this.lastSize = {width: w, height: h};
15525 var adj = this.adjustSize(w, h);
15526 var aw = adj.width, ah = adj.height;
15527 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15528 var rz = this.getResizeEl();
15529 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15530 rz.setSize(aw, ah);
15531 }else if(!this.deferHeight && ah !== undefined){
15533 }else if(aw !== undefined){
15536 this.onResize(aw, ah, w, h);
15537 this.fireEvent('resize', this, aw, ah, w, h);
15543 * Gets the current size of the component's underlying element.
15544 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15546 getSize : function(){
15547 return this.el.getSize();
15551 * Gets the current XY position of the component's underlying element.
15552 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15553 * @return {Array} The XY position of the element (e.g., [100, 200])
15555 getPosition : function(local){
15556 if(local === true){
15557 return [this.el.getLeft(true), this.el.getTop(true)];
15559 return this.xy || this.el.getXY();
15563 * Gets the current box measurements of the component's underlying element.
15564 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15565 * @returns {Object} box An object in the format {x, y, width, height}
15567 getBox : function(local){
15568 var s = this.el.getSize();
15570 s.x = this.el.getLeft(true);
15571 s.y = this.el.getTop(true);
15573 var xy = this.xy || this.el.getXY();
15581 * Sets the current box measurements of the component's underlying element.
15582 * @param {Object} box An object in the format {x, y, width, height}
15583 * @returns {Roo.BoxComponent} this
15585 updateBox : function(box){
15586 this.setSize(box.width, box.height);
15587 this.setPagePosition(box.x, box.y);
15592 getResizeEl : function(){
15593 return this.resizeEl || this.el;
15597 getPositionEl : function(){
15598 return this.positionEl || this.el;
15602 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15603 * This method fires the move event.
15604 * @param {Number} left The new left
15605 * @param {Number} top The new top
15606 * @returns {Roo.BoxComponent} this
15608 setPosition : function(x, y){
15611 if(!this.boxReady){
15614 var adj = this.adjustPosition(x, y);
15615 var ax = adj.x, ay = adj.y;
15617 var el = this.getPositionEl();
15618 if(ax !== undefined || ay !== undefined){
15619 if(ax !== undefined && ay !== undefined){
15620 el.setLeftTop(ax, ay);
15621 }else if(ax !== undefined){
15623 }else if(ay !== undefined){
15626 this.onPosition(ax, ay);
15627 this.fireEvent('move', this, ax, ay);
15633 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15634 * This method fires the move event.
15635 * @param {Number} x The new x position
15636 * @param {Number} y The new y position
15637 * @returns {Roo.BoxComponent} this
15639 setPagePosition : function(x, y){
15642 if(!this.boxReady){
15645 if(x === undefined || y === undefined){ // cannot translate undefined points
15648 var p = this.el.translatePoints(x, y);
15649 this.setPosition(p.left, p.top);
15654 onRender : function(ct, position){
15655 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15657 this.resizeEl = Roo.get(this.resizeEl);
15659 if(this.positionEl){
15660 this.positionEl = Roo.get(this.positionEl);
15665 afterRender : function(){
15666 Roo.BoxComponent.superclass.afterRender.call(this);
15667 this.boxReady = true;
15668 this.setSize(this.width, this.height);
15669 if(this.x || this.y){
15670 this.setPosition(this.x, this.y);
15672 if(this.pageX || this.pageY){
15673 this.setPagePosition(this.pageX, this.pageY);
15678 * Force the component's size to recalculate based on the underlying element's current height and width.
15679 * @returns {Roo.BoxComponent} this
15681 syncSize : function(){
15682 delete this.lastSize;
15683 this.setSize(this.el.getWidth(), this.el.getHeight());
15688 * Called after the component is resized, this method is empty by default but can be implemented by any
15689 * subclass that needs to perform custom logic after a resize occurs.
15690 * @param {Number} adjWidth The box-adjusted width that was set
15691 * @param {Number} adjHeight The box-adjusted height that was set
15692 * @param {Number} rawWidth The width that was originally specified
15693 * @param {Number} rawHeight The height that was originally specified
15695 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15700 * Called after the component is moved, this method is empty by default but can be implemented by any
15701 * subclass that needs to perform custom logic after a move occurs.
15702 * @param {Number} x The new x position
15703 * @param {Number} y The new y position
15705 onPosition : function(x, y){
15710 adjustSize : function(w, h){
15711 if(this.autoWidth){
15714 if(this.autoHeight){
15717 return {width : w, height: h};
15721 adjustPosition : function(x, y){
15722 return {x : x, y: y};
15725 * Original code for Roojs - LGPL
15726 * <script type="text/javascript">
15730 * @class Roo.XComponent
15731 * A delayed Element creator...
15732 * Or a way to group chunks of interface together.
15734 * Mypart.xyx = new Roo.XComponent({
15736 parent : 'Mypart.xyz', // empty == document.element.!!
15740 disabled : function() {}
15742 tree : function() { // return an tree of xtype declared components
15746 xtype : 'NestedLayoutPanel',
15753 * It can be used to build a big heiracy, with parent etc.
15754 * or you can just use this to render a single compoent to a dom element
15755 * MYPART.render(Roo.Element | String(id) | dom_element )
15757 * @extends Roo.util.Observable
15759 * @param cfg {Object} configuration of component
15762 Roo.XComponent = function(cfg) {
15763 Roo.apply(this, cfg);
15767 * Fires when this the componnt is built
15768 * @param {Roo.XComponent} c the component
15773 this.region = this.region || 'center'; // default..
15774 Roo.XComponent.register(this);
15775 this.modules = false;
15776 this.el = false; // where the layout goes..
15780 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15783 * The created element (with Roo.factory())
15784 * @type {Roo.Layout}
15790 * for BC - use el in new code
15791 * @type {Roo.Layout}
15797 * for BC - use el in new code
15798 * @type {Roo.Layout}
15803 * @cfg {Function|boolean} disabled
15804 * If this module is disabled by some rule, return true from the funtion
15809 * @cfg {String} parent
15810 * Name of parent element which it get xtype added to..
15815 * @cfg {String} order
15816 * Used to set the order in which elements are created (usefull for multiple tabs)
15821 * @cfg {String} name
15822 * String to display while loading.
15826 * @cfg {String} region
15827 * Region to render component to (defaults to center)
15832 * @cfg {Array} items
15833 * A single item array - the first element is the root of the tree..
15834 * It's done this way to stay compatible with the Xtype system...
15840 * The method that retuns the tree of parts that make up this compoennt
15847 * render element to dom or tree
15848 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15851 render : function(el)
15855 var hp = this.parent ? 1 : 0;
15857 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15858 // if parent is a '#.....' string, then let's use that..
15859 var ename = this.parent.substr(1)
15860 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15861 el = Roo.get(ename);
15862 if (!el && !this.parent) {
15863 Roo.log("Warning - element can not be found :#" + ename );
15867 var tree = this._tree ? this._tree() : this.tree();
15870 if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15871 //el = Roo.get(document.body);
15872 this.parent = { el : true };
15877 if (!this.parent) {
15879 Roo.log("no parent - creating one");
15881 el = el ? Roo.get(el) : false;
15883 // it's a top level one..
15885 el : new Roo.BorderLayout(el || document.body, {
15891 tabPosition: 'top',
15892 //resizeTabs: true,
15893 alwaysShowTabs: el && hp? false : true,
15894 hideTabs: el || !hp ? true : false,
15901 if (!this.parent.el) {
15902 // probably an old style ctor, which has been disabled.
15906 // The 'tree' method is '_tree now'
15908 tree.region = tree.region || this.region;
15910 if (this.parent.el === true) {
15911 // bootstrap... - body..
15912 this.parent.el = Roo.factory(tree);
15915 this.el = this.parent.el.addxtype(tree);
15916 this.fireEvent('built', this);
15918 this.panel = this.el;
15919 this.layout = this.panel.layout;
15920 this.parentLayout = this.parent.layout || false;
15926 Roo.apply(Roo.XComponent, {
15928 * @property hideProgress
15929 * true to disable the building progress bar.. usefull on single page renders.
15932 hideProgress : false,
15934 * @property buildCompleted
15935 * True when the builder has completed building the interface.
15938 buildCompleted : false,
15941 * @property topModule
15942 * the upper most module - uses document.element as it's constructor.
15949 * @property modules
15950 * array of modules to be created by registration system.
15951 * @type {Array} of Roo.XComponent
15956 * @property elmodules
15957 * array of modules to be created by which use #ID
15958 * @type {Array} of Roo.XComponent
15964 * @property build_from_html
15965 * Build elements from html - used by bootstrap HTML stuff
15966 * - this is cleared after build is completed
15967 * @type {boolean} true (default false)
15970 build_from_html : false,
15973 * Register components to be built later.
15975 * This solves the following issues
15976 * - Building is not done on page load, but after an authentication process has occured.
15977 * - Interface elements are registered on page load
15978 * - Parent Interface elements may not be loaded before child, so this handles that..
15985 module : 'Pman.Tab.projectMgr',
15987 parent : 'Pman.layout',
15988 disabled : false, // or use a function..
15991 * * @param {Object} details about module
15993 register : function(obj) {
15995 Roo.XComponent.event.fireEvent('register', obj);
15996 switch(typeof(obj.disabled) ) {
16002 if ( obj.disabled() ) {
16008 if (obj.disabled) {
16014 this.modules.push(obj);
16018 * convert a string to an object..
16019 * eg. 'AAA.BBB' -> finds AAA.BBB
16023 toObject : function(str)
16025 if (!str || typeof(str) == 'object') {
16028 if (str.substring(0,1) == '#') {
16032 var ar = str.split('.');
16037 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16039 throw "Module not found : " + str;
16043 throw "Module not found : " + str;
16045 Roo.each(ar, function(e) {
16046 if (typeof(o[e]) == 'undefined') {
16047 throw "Module not found : " + str;
16058 * move modules into their correct place in the tree..
16061 preBuild : function ()
16064 Roo.each(this.modules , function (obj)
16066 Roo.XComponent.event.fireEvent('beforebuild', obj);
16068 var opar = obj.parent;
16070 obj.parent = this.toObject(opar);
16072 Roo.log("parent:toObject failed: " + e.toString());
16077 Roo.debug && Roo.log("GOT top level module");
16078 Roo.debug && Roo.log(obj);
16079 obj.modules = new Roo.util.MixedCollection(false,
16080 function(o) { return o.order + '' }
16082 this.topModule = obj;
16085 // parent is a string (usually a dom element name..)
16086 if (typeof(obj.parent) == 'string') {
16087 this.elmodules.push(obj);
16090 if (obj.parent.constructor != Roo.XComponent) {
16091 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16093 if (!obj.parent.modules) {
16094 obj.parent.modules = new Roo.util.MixedCollection(false,
16095 function(o) { return o.order + '' }
16098 if (obj.parent.disabled) {
16099 obj.disabled = true;
16101 obj.parent.modules.add(obj);
16106 * make a list of modules to build.
16107 * @return {Array} list of modules.
16110 buildOrder : function()
16113 var cmp = function(a,b) {
16114 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16116 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16117 throw "No top level modules to build";
16120 // make a flat list in order of modules to build.
16121 var mods = this.topModule ? [ this.topModule ] : [];
16124 // elmodules (is a list of DOM based modules )
16125 Roo.each(this.elmodules, function(e) {
16127 if (!this.topModule &&
16128 typeof(e.parent) == 'string' &&
16129 e.parent.substring(0,1) == '#' &&
16130 Roo.get(e.parent.substr(1))
16133 _this.topModule = e;
16139 // add modules to their parents..
16140 var addMod = function(m) {
16141 Roo.debug && Roo.log("build Order: add: " + m.name);
16144 if (m.modules && !m.disabled) {
16145 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16146 m.modules.keySort('ASC', cmp );
16147 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16149 m.modules.each(addMod);
16151 Roo.debug && Roo.log("build Order: no child modules");
16153 // not sure if this is used any more..
16155 m.finalize.name = m.name + " (clean up) ";
16156 mods.push(m.finalize);
16160 if (this.topModule && this.topModule.modules) {
16161 this.topModule.modules.keySort('ASC', cmp );
16162 this.topModule.modules.each(addMod);
16168 * Build the registered modules.
16169 * @param {Object} parent element.
16170 * @param {Function} optional method to call after module has been added.
16174 build : function(opts)
16177 if (typeof(opts) != 'undefined') {
16178 Roo.apply(this,opts);
16182 var mods = this.buildOrder();
16184 //this.allmods = mods;
16185 //Roo.debug && Roo.log(mods);
16187 if (!mods.length) { // should not happen
16188 throw "NO modules!!!";
16192 var msg = "Building Interface...";
16193 // flash it up as modal - so we store the mask!?
16194 if (!this.hideProgress && Roo.MessageBox) {
16195 Roo.MessageBox.show({ title: 'loading' });
16196 Roo.MessageBox.show({
16197 title: "Please wait...",
16206 var total = mods.length;
16209 var progressRun = function() {
16210 if (!mods.length) {
16211 Roo.debug && Roo.log('hide?');
16212 if (!this.hideProgress && Roo.MessageBox) {
16213 Roo.MessageBox.hide();
16215 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16217 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16223 var m = mods.shift();
16226 Roo.debug && Roo.log(m);
16227 // not sure if this is supported any more.. - modules that are are just function
16228 if (typeof(m) == 'function') {
16230 return progressRun.defer(10, _this);
16234 msg = "Building Interface " + (total - mods.length) +
16236 (m.name ? (' - ' + m.name) : '');
16237 Roo.debug && Roo.log(msg);
16238 if (!this.hideProgress && Roo.MessageBox) {
16239 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16243 // is the module disabled?
16244 var disabled = (typeof(m.disabled) == 'function') ?
16245 m.disabled.call(m.module.disabled) : m.disabled;
16249 return progressRun(); // we do not update the display!
16257 // it's 10 on top level, and 1 on others??? why...
16258 return progressRun.defer(10, _this);
16261 progressRun.defer(1, _this);
16275 * wrapper for event.on - aliased later..
16276 * Typically use to register a event handler for register:
16278 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16287 Roo.XComponent.event = new Roo.util.Observable({
16291 * Fires when an Component is registered,
16292 * set the disable property on the Component to stop registration.
16293 * @param {Roo.XComponent} c the component being registerd.
16298 * @event beforebuild
16299 * Fires before each Component is built
16300 * can be used to apply permissions.
16301 * @param {Roo.XComponent} c the component being registerd.
16304 'beforebuild' : true,
16306 * @event buildcomplete
16307 * Fires on the top level element when all elements have been built
16308 * @param {Roo.XComponent} the top level component.
16310 'buildcomplete' : true
16315 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16318 * Ext JS Library 1.1.1
16319 * Copyright(c) 2006-2007, Ext JS, LLC.
16321 * Originally Released Under LGPL - original licence link has changed is not relivant.
16324 * <script type="text/javascript">
16330 * These classes are derivatives of the similarly named classes in the YUI Library.
16331 * The original license:
16332 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16333 * Code licensed under the BSD License:
16334 * http://developer.yahoo.net/yui/license.txt
16339 var Event=Roo.EventManager;
16340 var Dom=Roo.lib.Dom;
16343 * @class Roo.dd.DragDrop
16344 * @extends Roo.util.Observable
16345 * Defines the interface and base operation of items that that can be
16346 * dragged or can be drop targets. It was designed to be extended, overriding
16347 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16348 * Up to three html elements can be associated with a DragDrop instance:
16350 * <li>linked element: the element that is passed into the constructor.
16351 * This is the element which defines the boundaries for interaction with
16352 * other DragDrop objects.</li>
16353 * <li>handle element(s): The drag operation only occurs if the element that
16354 * was clicked matches a handle element. By default this is the linked
16355 * element, but there are times that you will want only a portion of the
16356 * linked element to initiate the drag operation, and the setHandleElId()
16357 * method provides a way to define this.</li>
16358 * <li>drag element: this represents the element that would be moved along
16359 * with the cursor during a drag operation. By default, this is the linked
16360 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16361 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16364 * This class should not be instantiated until the onload event to ensure that
16365 * the associated elements are available.
16366 * The following would define a DragDrop obj that would interact with any
16367 * other DragDrop obj in the "group1" group:
16369 * dd = new Roo.dd.DragDrop("div1", "group1");
16371 * Since none of the event handlers have been implemented, nothing would
16372 * actually happen if you were to run the code above. Normally you would
16373 * override this class or one of the default implementations, but you can
16374 * also override the methods you want on an instance of the class...
16376 * dd.onDragDrop = function(e, id) {
16377 * alert("dd was dropped on " + id);
16381 * @param {String} id of the element that is linked to this instance
16382 * @param {String} sGroup the group of related DragDrop objects
16383 * @param {object} config an object containing configurable attributes
16384 * Valid properties for DragDrop:
16385 * padding, isTarget, maintainOffset, primaryButtonOnly
16387 Roo.dd.DragDrop = function(id, sGroup, config) {
16389 this.init(id, sGroup, config);
16394 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16397 * The id of the element associated with this object. This is what we
16398 * refer to as the "linked element" because the size and position of
16399 * this element is used to determine when the drag and drop objects have
16407 * Configuration attributes passed into the constructor
16414 * The id of the element that will be dragged. By default this is same
16415 * as the linked element , but could be changed to another element. Ex:
16417 * @property dragElId
16424 * the id of the element that initiates the drag operation. By default
16425 * this is the linked element, but could be changed to be a child of this
16426 * element. This lets us do things like only starting the drag when the
16427 * header element within the linked html element is clicked.
16428 * @property handleElId
16435 * An associative array of HTML tags that will be ignored if clicked.
16436 * @property invalidHandleTypes
16437 * @type {string: string}
16439 invalidHandleTypes: null,
16442 * An associative array of ids for elements that will be ignored if clicked
16443 * @property invalidHandleIds
16444 * @type {string: string}
16446 invalidHandleIds: null,
16449 * An indexted array of css class names for elements that will be ignored
16451 * @property invalidHandleClasses
16454 invalidHandleClasses: null,
16457 * The linked element's absolute X position at the time the drag was
16459 * @property startPageX
16466 * The linked element's absolute X position at the time the drag was
16468 * @property startPageY
16475 * The group defines a logical collection of DragDrop objects that are
16476 * related. Instances only get events when interacting with other
16477 * DragDrop object in the same group. This lets us define multiple
16478 * groups using a single DragDrop subclass if we want.
16480 * @type {string: string}
16485 * Individual drag/drop instances can be locked. This will prevent
16486 * onmousedown start drag.
16494 * Lock this instance
16497 lock: function() { this.locked = true; },
16500 * Unlock this instace
16503 unlock: function() { this.locked = false; },
16506 * By default, all insances can be a drop target. This can be disabled by
16507 * setting isTarget to false.
16514 * The padding configured for this drag and drop object for calculating
16515 * the drop zone intersection with this object.
16522 * Cached reference to the linked element
16523 * @property _domRef
16529 * Internal typeof flag
16530 * @property __ygDragDrop
16533 __ygDragDrop: true,
16536 * Set to true when horizontal contraints are applied
16537 * @property constrainX
16544 * Set to true when vertical contraints are applied
16545 * @property constrainY
16552 * The left constraint
16560 * The right constraint
16568 * The up constraint
16577 * The down constraint
16585 * Maintain offsets when we resetconstraints. Set to true when you want
16586 * the position of the element relative to its parent to stay the same
16587 * when the page changes
16589 * @property maintainOffset
16592 maintainOffset: false,
16595 * Array of pixel locations the element will snap to if we specified a
16596 * horizontal graduation/interval. This array is generated automatically
16597 * when you define a tick interval.
16604 * Array of pixel locations the element will snap to if we specified a
16605 * vertical graduation/interval. This array is generated automatically
16606 * when you define a tick interval.
16613 * By default the drag and drop instance will only respond to the primary
16614 * button click (left button for a right-handed mouse). Set to true to
16615 * allow drag and drop to start with any mouse click that is propogated
16617 * @property primaryButtonOnly
16620 primaryButtonOnly: true,
16623 * The availabe property is false until the linked dom element is accessible.
16624 * @property available
16630 * By default, drags can only be initiated if the mousedown occurs in the
16631 * region the linked element is. This is done in part to work around a
16632 * bug in some browsers that mis-report the mousedown if the previous
16633 * mouseup happened outside of the window. This property is set to true
16634 * if outer handles are defined.
16636 * @property hasOuterHandles
16640 hasOuterHandles: false,
16643 * Code that executes immediately before the startDrag event
16644 * @method b4StartDrag
16647 b4StartDrag: function(x, y) { },
16650 * Abstract method called after a drag/drop object is clicked
16651 * and the drag or mousedown time thresholds have beeen met.
16652 * @method startDrag
16653 * @param {int} X click location
16654 * @param {int} Y click location
16656 startDrag: function(x, y) { /* override this */ },
16659 * Code that executes immediately before the onDrag event
16663 b4Drag: function(e) { },
16666 * Abstract method called during the onMouseMove event while dragging an
16669 * @param {Event} e the mousemove event
16671 onDrag: function(e) { /* override this */ },
16674 * Abstract method called when this element fist begins hovering over
16675 * another DragDrop obj
16676 * @method onDragEnter
16677 * @param {Event} e the mousemove event
16678 * @param {String|DragDrop[]} id In POINT mode, the element
16679 * id this is hovering over. In INTERSECT mode, an array of one or more
16680 * dragdrop items being hovered over.
16682 onDragEnter: function(e, id) { /* override this */ },
16685 * Code that executes immediately before the onDragOver event
16686 * @method b4DragOver
16689 b4DragOver: function(e) { },
16692 * Abstract method called when this element is hovering over another
16694 * @method onDragOver
16695 * @param {Event} e the mousemove event
16696 * @param {String|DragDrop[]} id In POINT mode, the element
16697 * id this is hovering over. In INTERSECT mode, an array of dd items
16698 * being hovered over.
16700 onDragOver: function(e, id) { /* override this */ },
16703 * Code that executes immediately before the onDragOut event
16704 * @method b4DragOut
16707 b4DragOut: function(e) { },
16710 * Abstract method called when we are no longer hovering over an element
16711 * @method onDragOut
16712 * @param {Event} e the mousemove event
16713 * @param {String|DragDrop[]} id In POINT mode, the element
16714 * id this was hovering over. In INTERSECT mode, an array of dd items
16715 * that the mouse is no longer over.
16717 onDragOut: function(e, id) { /* override this */ },
16720 * Code that executes immediately before the onDragDrop event
16721 * @method b4DragDrop
16724 b4DragDrop: function(e) { },
16727 * Abstract method called when this item is dropped on another DragDrop
16729 * @method onDragDrop
16730 * @param {Event} e the mouseup event
16731 * @param {String|DragDrop[]} id In POINT mode, the element
16732 * id this was dropped on. In INTERSECT mode, an array of dd items this
16735 onDragDrop: function(e, id) { /* override this */ },
16738 * Abstract method called when this item is dropped on an area with no
16740 * @method onInvalidDrop
16741 * @param {Event} e the mouseup event
16743 onInvalidDrop: function(e) { /* override this */ },
16746 * Code that executes immediately before the endDrag event
16747 * @method b4EndDrag
16750 b4EndDrag: function(e) { },
16753 * Fired when we are done dragging the object
16755 * @param {Event} e the mouseup event
16757 endDrag: function(e) { /* override this */ },
16760 * Code executed immediately before the onMouseDown event
16761 * @method b4MouseDown
16762 * @param {Event} e the mousedown event
16765 b4MouseDown: function(e) { },
16768 * Event handler that fires when a drag/drop obj gets a mousedown
16769 * @method onMouseDown
16770 * @param {Event} e the mousedown event
16772 onMouseDown: function(e) { /* override this */ },
16775 * Event handler that fires when a drag/drop obj gets a mouseup
16776 * @method onMouseUp
16777 * @param {Event} e the mouseup event
16779 onMouseUp: function(e) { /* override this */ },
16782 * Override the onAvailable method to do what is needed after the initial
16783 * position was determined.
16784 * @method onAvailable
16786 onAvailable: function () {
16790 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16793 defaultPadding : {left:0, right:0, top:0, bottom:0},
16796 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16800 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16801 { dragElId: "existingProxyDiv" });
16802 dd.startDrag = function(){
16803 this.constrainTo("parent-id");
16806 * Or you can initalize it using the {@link Roo.Element} object:
16808 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16809 startDrag : function(){
16810 this.constrainTo("parent-id");
16814 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16815 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16816 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16817 * an object containing the sides to pad. For example: {right:10, bottom:10}
16818 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16820 constrainTo : function(constrainTo, pad, inContent){
16821 if(typeof pad == "number"){
16822 pad = {left: pad, right:pad, top:pad, bottom:pad};
16824 pad = pad || this.defaultPadding;
16825 var b = Roo.get(this.getEl()).getBox();
16826 var ce = Roo.get(constrainTo);
16827 var s = ce.getScroll();
16828 var c, cd = ce.dom;
16829 if(cd == document.body){
16830 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16833 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16837 var topSpace = b.y - c.y;
16838 var leftSpace = b.x - c.x;
16840 this.resetConstraints();
16841 this.setXConstraint(leftSpace - (pad.left||0), // left
16842 c.width - leftSpace - b.width - (pad.right||0) //right
16844 this.setYConstraint(topSpace - (pad.top||0), //top
16845 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16850 * Returns a reference to the linked element
16852 * @return {HTMLElement} the html element
16854 getEl: function() {
16855 if (!this._domRef) {
16856 this._domRef = Roo.getDom(this.id);
16859 return this._domRef;
16863 * Returns a reference to the actual element to drag. By default this is
16864 * the same as the html element, but it can be assigned to another
16865 * element. An example of this can be found in Roo.dd.DDProxy
16866 * @method getDragEl
16867 * @return {HTMLElement} the html element
16869 getDragEl: function() {
16870 return Roo.getDom(this.dragElId);
16874 * Sets up the DragDrop object. Must be called in the constructor of any
16875 * Roo.dd.DragDrop subclass
16877 * @param id the id of the linked element
16878 * @param {String} sGroup the group of related items
16879 * @param {object} config configuration attributes
16881 init: function(id, sGroup, config) {
16882 this.initTarget(id, sGroup, config);
16883 if (!Roo.isTouch) {
16884 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16886 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16887 // Event.on(this.id, "selectstart", Event.preventDefault);
16891 * Initializes Targeting functionality only... the object does not
16892 * get a mousedown handler.
16893 * @method initTarget
16894 * @param id the id of the linked element
16895 * @param {String} sGroup the group of related items
16896 * @param {object} config configuration attributes
16898 initTarget: function(id, sGroup, config) {
16900 // configuration attributes
16901 this.config = config || {};
16903 // create a local reference to the drag and drop manager
16904 this.DDM = Roo.dd.DDM;
16905 // initialize the groups array
16908 // assume that we have an element reference instead of an id if the
16909 // parameter is not a string
16910 if (typeof id !== "string") {
16917 // add to an interaction group
16918 this.addToGroup((sGroup) ? sGroup : "default");
16920 // We don't want to register this as the handle with the manager
16921 // so we just set the id rather than calling the setter.
16922 this.handleElId = id;
16924 // the linked element is the element that gets dragged by default
16925 this.setDragElId(id);
16927 // by default, clicked anchors will not start drag operations.
16928 this.invalidHandleTypes = { A: "A" };
16929 this.invalidHandleIds = {};
16930 this.invalidHandleClasses = [];
16932 this.applyConfig();
16934 this.handleOnAvailable();
16938 * Applies the configuration parameters that were passed into the constructor.
16939 * This is supposed to happen at each level through the inheritance chain. So
16940 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16941 * DragDrop in order to get all of the parameters that are available in
16943 * @method applyConfig
16945 applyConfig: function() {
16947 // configurable properties:
16948 // padding, isTarget, maintainOffset, primaryButtonOnly
16949 this.padding = this.config.padding || [0, 0, 0, 0];
16950 this.isTarget = (this.config.isTarget !== false);
16951 this.maintainOffset = (this.config.maintainOffset);
16952 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16957 * Executed when the linked element is available
16958 * @method handleOnAvailable
16961 handleOnAvailable: function() {
16962 this.available = true;
16963 this.resetConstraints();
16964 this.onAvailable();
16968 * Configures the padding for the target zone in px. Effectively expands
16969 * (or reduces) the virtual object size for targeting calculations.
16970 * Supports css-style shorthand; if only one parameter is passed, all sides
16971 * will have that padding, and if only two are passed, the top and bottom
16972 * will have the first param, the left and right the second.
16973 * @method setPadding
16974 * @param {int} iTop Top pad
16975 * @param {int} iRight Right pad
16976 * @param {int} iBot Bot pad
16977 * @param {int} iLeft Left pad
16979 setPadding: function(iTop, iRight, iBot, iLeft) {
16980 // this.padding = [iLeft, iRight, iTop, iBot];
16981 if (!iRight && 0 !== iRight) {
16982 this.padding = [iTop, iTop, iTop, iTop];
16983 } else if (!iBot && 0 !== iBot) {
16984 this.padding = [iTop, iRight, iTop, iRight];
16986 this.padding = [iTop, iRight, iBot, iLeft];
16991 * Stores the initial placement of the linked element.
16992 * @method setInitialPosition
16993 * @param {int} diffX the X offset, default 0
16994 * @param {int} diffY the Y offset, default 0
16996 setInitPosition: function(diffX, diffY) {
16997 var el = this.getEl();
16999 if (!this.DDM.verifyEl(el)) {
17003 var dx = diffX || 0;
17004 var dy = diffY || 0;
17006 var p = Dom.getXY( el );
17008 this.initPageX = p[0] - dx;
17009 this.initPageY = p[1] - dy;
17011 this.lastPageX = p[0];
17012 this.lastPageY = p[1];
17015 this.setStartPosition(p);
17019 * Sets the start position of the element. This is set when the obj
17020 * is initialized, the reset when a drag is started.
17021 * @method setStartPosition
17022 * @param pos current position (from previous lookup)
17025 setStartPosition: function(pos) {
17026 var p = pos || Dom.getXY( this.getEl() );
17027 this.deltaSetXY = null;
17029 this.startPageX = p[0];
17030 this.startPageY = p[1];
17034 * Add this instance to a group of related drag/drop objects. All
17035 * instances belong to at least one group, and can belong to as many
17036 * groups as needed.
17037 * @method addToGroup
17038 * @param sGroup {string} the name of the group
17040 addToGroup: function(sGroup) {
17041 this.groups[sGroup] = true;
17042 this.DDM.regDragDrop(this, sGroup);
17046 * Remove's this instance from the supplied interaction group
17047 * @method removeFromGroup
17048 * @param {string} sGroup The group to drop
17050 removeFromGroup: function(sGroup) {
17051 if (this.groups[sGroup]) {
17052 delete this.groups[sGroup];
17055 this.DDM.removeDDFromGroup(this, sGroup);
17059 * Allows you to specify that an element other than the linked element
17060 * will be moved with the cursor during a drag
17061 * @method setDragElId
17062 * @param id {string} the id of the element that will be used to initiate the drag
17064 setDragElId: function(id) {
17065 this.dragElId = id;
17069 * Allows you to specify a child of the linked element that should be
17070 * used to initiate the drag operation. An example of this would be if
17071 * you have a content div with text and links. Clicking anywhere in the
17072 * content area would normally start the drag operation. Use this method
17073 * to specify that an element inside of the content div is the element
17074 * that starts the drag operation.
17075 * @method setHandleElId
17076 * @param id {string} the id of the element that will be used to
17077 * initiate the drag.
17079 setHandleElId: function(id) {
17080 if (typeof id !== "string") {
17083 this.handleElId = id;
17084 this.DDM.regHandle(this.id, id);
17088 * Allows you to set an element outside of the linked element as a drag
17090 * @method setOuterHandleElId
17091 * @param id the id of the element that will be used to initiate the drag
17093 setOuterHandleElId: function(id) {
17094 if (typeof id !== "string") {
17097 Event.on(id, "mousedown",
17098 this.handleMouseDown, this);
17099 this.setHandleElId(id);
17101 this.hasOuterHandles = true;
17105 * Remove all drag and drop hooks for this element
17108 unreg: function() {
17109 Event.un(this.id, "mousedown",
17110 this.handleMouseDown);
17111 Event.un(this.id, "touchstart",
17112 this.handleMouseDown);
17113 this._domRef = null;
17114 this.DDM._remove(this);
17117 destroy : function(){
17122 * Returns true if this instance is locked, or the drag drop mgr is locked
17123 * (meaning that all drag/drop is disabled on the page.)
17125 * @return {boolean} true if this obj or all drag/drop is locked, else
17128 isLocked: function() {
17129 return (this.DDM.isLocked() || this.locked);
17133 * Fired when this object is clicked
17134 * @method handleMouseDown
17136 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17139 handleMouseDown: function(e, oDD){
17141 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17142 //Roo.log('not touch/ button !=0');
17145 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17146 return; // double touch..
17150 if (this.isLocked()) {
17151 //Roo.log('locked');
17155 this.DDM.refreshCache(this.groups);
17156 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17157 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17158 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17159 //Roo.log('no outer handes or not over target');
17162 // Roo.log('check validator');
17163 if (this.clickValidator(e)) {
17164 // Roo.log('validate success');
17165 // set the initial element position
17166 this.setStartPosition();
17169 this.b4MouseDown(e);
17170 this.onMouseDown(e);
17172 this.DDM.handleMouseDown(e, this);
17174 this.DDM.stopEvent(e);
17182 clickValidator: function(e) {
17183 var target = e.getTarget();
17184 return ( this.isValidHandleChild(target) &&
17185 (this.id == this.handleElId ||
17186 this.DDM.handleWasClicked(target, this.id)) );
17190 * Allows you to specify a tag name that should not start a drag operation
17191 * when clicked. This is designed to facilitate embedding links within a
17192 * drag handle that do something other than start the drag.
17193 * @method addInvalidHandleType
17194 * @param {string} tagName the type of element to exclude
17196 addInvalidHandleType: function(tagName) {
17197 var type = tagName.toUpperCase();
17198 this.invalidHandleTypes[type] = type;
17202 * Lets you to specify an element id for a child of a drag handle
17203 * that should not initiate a drag
17204 * @method addInvalidHandleId
17205 * @param {string} id the element id of the element you wish to ignore
17207 addInvalidHandleId: function(id) {
17208 if (typeof id !== "string") {
17211 this.invalidHandleIds[id] = id;
17215 * Lets you specify a css class of elements that will not initiate a drag
17216 * @method addInvalidHandleClass
17217 * @param {string} cssClass the class of the elements you wish to ignore
17219 addInvalidHandleClass: function(cssClass) {
17220 this.invalidHandleClasses.push(cssClass);
17224 * Unsets an excluded tag name set by addInvalidHandleType
17225 * @method removeInvalidHandleType
17226 * @param {string} tagName the type of element to unexclude
17228 removeInvalidHandleType: function(tagName) {
17229 var type = tagName.toUpperCase();
17230 // this.invalidHandleTypes[type] = null;
17231 delete this.invalidHandleTypes[type];
17235 * Unsets an invalid handle id
17236 * @method removeInvalidHandleId
17237 * @param {string} id the id of the element to re-enable
17239 removeInvalidHandleId: function(id) {
17240 if (typeof id !== "string") {
17243 delete this.invalidHandleIds[id];
17247 * Unsets an invalid css class
17248 * @method removeInvalidHandleClass
17249 * @param {string} cssClass the class of the element(s) you wish to
17252 removeInvalidHandleClass: function(cssClass) {
17253 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17254 if (this.invalidHandleClasses[i] == cssClass) {
17255 delete this.invalidHandleClasses[i];
17261 * Checks the tag exclusion list to see if this click should be ignored
17262 * @method isValidHandleChild
17263 * @param {HTMLElement} node the HTMLElement to evaluate
17264 * @return {boolean} true if this is a valid tag type, false if not
17266 isValidHandleChild: function(node) {
17269 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17272 nodeName = node.nodeName.toUpperCase();
17274 nodeName = node.nodeName;
17276 valid = valid && !this.invalidHandleTypes[nodeName];
17277 valid = valid && !this.invalidHandleIds[node.id];
17279 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17280 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17289 * Create the array of horizontal tick marks if an interval was specified
17290 * in setXConstraint().
17291 * @method setXTicks
17294 setXTicks: function(iStartX, iTickSize) {
17296 this.xTickSize = iTickSize;
17300 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17302 this.xTicks[this.xTicks.length] = i;
17307 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17309 this.xTicks[this.xTicks.length] = i;
17314 this.xTicks.sort(this.DDM.numericSort) ;
17318 * Create the array of vertical tick marks if an interval was specified in
17319 * setYConstraint().
17320 * @method setYTicks
17323 setYTicks: function(iStartY, iTickSize) {
17325 this.yTickSize = iTickSize;
17329 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17331 this.yTicks[this.yTicks.length] = i;
17336 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17338 this.yTicks[this.yTicks.length] = i;
17343 this.yTicks.sort(this.DDM.numericSort) ;
17347 * By default, the element can be dragged any place on the screen. Use
17348 * this method to limit the horizontal travel of the element. Pass in
17349 * 0,0 for the parameters if you want to lock the drag to the y axis.
17350 * @method setXConstraint
17351 * @param {int} iLeft the number of pixels the element can move to the left
17352 * @param {int} iRight the number of pixels the element can move to the
17354 * @param {int} iTickSize optional parameter for specifying that the
17356 * should move iTickSize pixels at a time.
17358 setXConstraint: function(iLeft, iRight, iTickSize) {
17359 this.leftConstraint = iLeft;
17360 this.rightConstraint = iRight;
17362 this.minX = this.initPageX - iLeft;
17363 this.maxX = this.initPageX + iRight;
17364 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17366 this.constrainX = true;
17370 * Clears any constraints applied to this instance. Also clears ticks
17371 * since they can't exist independent of a constraint at this time.
17372 * @method clearConstraints
17374 clearConstraints: function() {
17375 this.constrainX = false;
17376 this.constrainY = false;
17381 * Clears any tick interval defined for this instance
17382 * @method clearTicks
17384 clearTicks: function() {
17385 this.xTicks = null;
17386 this.yTicks = null;
17387 this.xTickSize = 0;
17388 this.yTickSize = 0;
17392 * By default, the element can be dragged any place on the screen. Set
17393 * this to limit the vertical travel of the element. Pass in 0,0 for the
17394 * parameters if you want to lock the drag to the x axis.
17395 * @method setYConstraint
17396 * @param {int} iUp the number of pixels the element can move up
17397 * @param {int} iDown the number of pixels the element can move down
17398 * @param {int} iTickSize optional parameter for specifying that the
17399 * element should move iTickSize pixels at a time.
17401 setYConstraint: function(iUp, iDown, iTickSize) {
17402 this.topConstraint = iUp;
17403 this.bottomConstraint = iDown;
17405 this.minY = this.initPageY - iUp;
17406 this.maxY = this.initPageY + iDown;
17407 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17409 this.constrainY = true;
17414 * resetConstraints must be called if you manually reposition a dd element.
17415 * @method resetConstraints
17416 * @param {boolean} maintainOffset
17418 resetConstraints: function() {
17421 // Maintain offsets if necessary
17422 if (this.initPageX || this.initPageX === 0) {
17423 // figure out how much this thing has moved
17424 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17425 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17427 this.setInitPosition(dx, dy);
17429 // This is the first time we have detected the element's position
17431 this.setInitPosition();
17434 if (this.constrainX) {
17435 this.setXConstraint( this.leftConstraint,
17436 this.rightConstraint,
17440 if (this.constrainY) {
17441 this.setYConstraint( this.topConstraint,
17442 this.bottomConstraint,
17448 * Normally the drag element is moved pixel by pixel, but we can specify
17449 * that it move a number of pixels at a time. This method resolves the
17450 * location when we have it set up like this.
17452 * @param {int} val where we want to place the object
17453 * @param {int[]} tickArray sorted array of valid points
17454 * @return {int} the closest tick
17457 getTick: function(val, tickArray) {
17460 // If tick interval is not defined, it is effectively 1 pixel,
17461 // so we return the value passed to us.
17463 } else if (tickArray[0] >= val) {
17464 // The value is lower than the first tick, so we return the first
17466 return tickArray[0];
17468 for (var i=0, len=tickArray.length; i<len; ++i) {
17470 if (tickArray[next] && tickArray[next] >= val) {
17471 var diff1 = val - tickArray[i];
17472 var diff2 = tickArray[next] - val;
17473 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17477 // The value is larger than the last tick, so we return the last
17479 return tickArray[tickArray.length - 1];
17486 * @return {string} string representation of the dd obj
17488 toString: function() {
17489 return ("DragDrop " + this.id);
17497 * Ext JS Library 1.1.1
17498 * Copyright(c) 2006-2007, Ext JS, LLC.
17500 * Originally Released Under LGPL - original licence link has changed is not relivant.
17503 * <script type="text/javascript">
17508 * The drag and drop utility provides a framework for building drag and drop
17509 * applications. In addition to enabling drag and drop for specific elements,
17510 * the drag and drop elements are tracked by the manager class, and the
17511 * interactions between the various elements are tracked during the drag and
17512 * the implementing code is notified about these important moments.
17515 // Only load the library once. Rewriting the manager class would orphan
17516 // existing drag and drop instances.
17517 if (!Roo.dd.DragDropMgr) {
17520 * @class Roo.dd.DragDropMgr
17521 * DragDropMgr is a singleton that tracks the element interaction for
17522 * all DragDrop items in the window. Generally, you will not call
17523 * this class directly, but it does have helper methods that could
17524 * be useful in your DragDrop implementations.
17527 Roo.dd.DragDropMgr = function() {
17529 var Event = Roo.EventManager;
17534 * Two dimensional Array of registered DragDrop objects. The first
17535 * dimension is the DragDrop item group, the second the DragDrop
17538 * @type {string: string}
17545 * Array of element ids defined as drag handles. Used to determine
17546 * if the element that generated the mousedown event is actually the
17547 * handle and not the html element itself.
17548 * @property handleIds
17549 * @type {string: string}
17556 * the DragDrop object that is currently being dragged
17557 * @property dragCurrent
17565 * the DragDrop object(s) that are being hovered over
17566 * @property dragOvers
17574 * the X distance between the cursor and the object being dragged
17583 * the Y distance between the cursor and the object being dragged
17592 * Flag to determine if we should prevent the default behavior of the
17593 * events we define. By default this is true, but this can be set to
17594 * false if you need the default behavior (not recommended)
17595 * @property preventDefault
17599 preventDefault: true,
17602 * Flag to determine if we should stop the propagation of the events
17603 * we generate. This is true by default but you may want to set it to
17604 * false if the html element contains other features that require the
17606 * @property stopPropagation
17610 stopPropagation: true,
17613 * Internal flag that is set to true when drag and drop has been
17615 * @property initialized
17622 * All drag and drop can be disabled.
17630 * Called the first time an element is registered.
17636 this.initialized = true;
17640 * In point mode, drag and drop interaction is defined by the
17641 * location of the cursor during the drag/drop
17649 * In intersect mode, drag and drop interactio nis defined by the
17650 * overlap of two or more drag and drop objects.
17651 * @property INTERSECT
17658 * The current drag and drop mode. Default: POINT
17666 * Runs method on all drag and drop objects
17667 * @method _execOnAll
17671 _execOnAll: function(sMethod, args) {
17672 for (var i in this.ids) {
17673 for (var j in this.ids[i]) {
17674 var oDD = this.ids[i][j];
17675 if (! this.isTypeOfDD(oDD)) {
17678 oDD[sMethod].apply(oDD, args);
17684 * Drag and drop initialization. Sets up the global event handlers
17689 _onLoad: function() {
17693 if (!Roo.isTouch) {
17694 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17695 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17697 Event.on(document, "touchend", this.handleMouseUp, this, true);
17698 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17700 Event.on(window, "unload", this._onUnload, this, true);
17701 Event.on(window, "resize", this._onResize, this, true);
17702 // Event.on(window, "mouseout", this._test);
17707 * Reset constraints on all drag and drop objs
17708 * @method _onResize
17712 _onResize: function(e) {
17713 this._execOnAll("resetConstraints", []);
17717 * Lock all drag and drop functionality
17721 lock: function() { this.locked = true; },
17724 * Unlock all drag and drop functionality
17728 unlock: function() { this.locked = false; },
17731 * Is drag and drop locked?
17733 * @return {boolean} True if drag and drop is locked, false otherwise.
17736 isLocked: function() { return this.locked; },
17739 * Location cache that is set for all drag drop objects when a drag is
17740 * initiated, cleared when the drag is finished.
17741 * @property locationCache
17748 * Set useCache to false if you want to force object the lookup of each
17749 * drag and drop linked element constantly during a drag.
17750 * @property useCache
17757 * The number of pixels that the mouse needs to move after the
17758 * mousedown before the drag is initiated. Default=3;
17759 * @property clickPixelThresh
17763 clickPixelThresh: 3,
17766 * The number of milliseconds after the mousedown event to initiate the
17767 * drag if we don't get a mouseup event. Default=1000
17768 * @property clickTimeThresh
17772 clickTimeThresh: 350,
17775 * Flag that indicates that either the drag pixel threshold or the
17776 * mousdown time threshold has been met
17777 * @property dragThreshMet
17782 dragThreshMet: false,
17785 * Timeout used for the click time threshold
17786 * @property clickTimeout
17791 clickTimeout: null,
17794 * The X position of the mousedown event stored for later use when a
17795 * drag threshold is met.
17804 * The Y position of the mousedown event stored for later use when a
17805 * drag threshold is met.
17814 * Each DragDrop instance must be registered with the DragDropMgr.
17815 * This is executed in DragDrop.init()
17816 * @method regDragDrop
17817 * @param {DragDrop} oDD the DragDrop object to register
17818 * @param {String} sGroup the name of the group this element belongs to
17821 regDragDrop: function(oDD, sGroup) {
17822 if (!this.initialized) { this.init(); }
17824 if (!this.ids[sGroup]) {
17825 this.ids[sGroup] = {};
17827 this.ids[sGroup][oDD.id] = oDD;
17831 * Removes the supplied dd instance from the supplied group. Executed
17832 * by DragDrop.removeFromGroup, so don't call this function directly.
17833 * @method removeDDFromGroup
17837 removeDDFromGroup: function(oDD, sGroup) {
17838 if (!this.ids[sGroup]) {
17839 this.ids[sGroup] = {};
17842 var obj = this.ids[sGroup];
17843 if (obj && obj[oDD.id]) {
17844 delete obj[oDD.id];
17849 * Unregisters a drag and drop item. This is executed in
17850 * DragDrop.unreg, use that method instead of calling this directly.
17855 _remove: function(oDD) {
17856 for (var g in oDD.groups) {
17857 if (g && this.ids[g][oDD.id]) {
17858 delete this.ids[g][oDD.id];
17861 delete this.handleIds[oDD.id];
17865 * Each DragDrop handle element must be registered. This is done
17866 * automatically when executing DragDrop.setHandleElId()
17867 * @method regHandle
17868 * @param {String} sDDId the DragDrop id this element is a handle for
17869 * @param {String} sHandleId the id of the element that is the drag
17873 regHandle: function(sDDId, sHandleId) {
17874 if (!this.handleIds[sDDId]) {
17875 this.handleIds[sDDId] = {};
17877 this.handleIds[sDDId][sHandleId] = sHandleId;
17881 * Utility function to determine if a given element has been
17882 * registered as a drag drop item.
17883 * @method isDragDrop
17884 * @param {String} id the element id to check
17885 * @return {boolean} true if this element is a DragDrop item,
17889 isDragDrop: function(id) {
17890 return ( this.getDDById(id) ) ? true : false;
17894 * Returns the drag and drop instances that are in all groups the
17895 * passed in instance belongs to.
17896 * @method getRelated
17897 * @param {DragDrop} p_oDD the obj to get related data for
17898 * @param {boolean} bTargetsOnly if true, only return targetable objs
17899 * @return {DragDrop[]} the related instances
17902 getRelated: function(p_oDD, bTargetsOnly) {
17904 for (var i in p_oDD.groups) {
17905 for (j in this.ids[i]) {
17906 var dd = this.ids[i][j];
17907 if (! this.isTypeOfDD(dd)) {
17910 if (!bTargetsOnly || dd.isTarget) {
17911 oDDs[oDDs.length] = dd;
17920 * Returns true if the specified dd target is a legal target for
17921 * the specifice drag obj
17922 * @method isLegalTarget
17923 * @param {DragDrop} the drag obj
17924 * @param {DragDrop} the target
17925 * @return {boolean} true if the target is a legal target for the
17929 isLegalTarget: function (oDD, oTargetDD) {
17930 var targets = this.getRelated(oDD, true);
17931 for (var i=0, len=targets.length;i<len;++i) {
17932 if (targets[i].id == oTargetDD.id) {
17941 * My goal is to be able to transparently determine if an object is
17942 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17943 * returns "object", oDD.constructor.toString() always returns
17944 * "DragDrop" and not the name of the subclass. So for now it just
17945 * evaluates a well-known variable in DragDrop.
17946 * @method isTypeOfDD
17947 * @param {Object} the object to evaluate
17948 * @return {boolean} true if typeof oDD = DragDrop
17951 isTypeOfDD: function (oDD) {
17952 return (oDD && oDD.__ygDragDrop);
17956 * Utility function to determine if a given element has been
17957 * registered as a drag drop handle for the given Drag Drop object.
17959 * @param {String} id the element id to check
17960 * @return {boolean} true if this element is a DragDrop handle, false
17964 isHandle: function(sDDId, sHandleId) {
17965 return ( this.handleIds[sDDId] &&
17966 this.handleIds[sDDId][sHandleId] );
17970 * Returns the DragDrop instance for a given id
17971 * @method getDDById
17972 * @param {String} id the id of the DragDrop object
17973 * @return {DragDrop} the drag drop object, null if it is not found
17976 getDDById: function(id) {
17977 for (var i in this.ids) {
17978 if (this.ids[i][id]) {
17979 return this.ids[i][id];
17986 * Fired after a registered DragDrop object gets the mousedown event.
17987 * Sets up the events required to track the object being dragged
17988 * @method handleMouseDown
17989 * @param {Event} e the event
17990 * @param oDD the DragDrop object being dragged
17994 handleMouseDown: function(e, oDD) {
17996 Roo.QuickTips.disable();
17998 this.currentTarget = e.getTarget();
18000 this.dragCurrent = oDD;
18002 var el = oDD.getEl();
18004 // track start position
18005 this.startX = e.getPageX();
18006 this.startY = e.getPageY();
18008 this.deltaX = this.startX - el.offsetLeft;
18009 this.deltaY = this.startY - el.offsetTop;
18011 this.dragThreshMet = false;
18013 this.clickTimeout = setTimeout(
18015 var DDM = Roo.dd.DDM;
18016 DDM.startDrag(DDM.startX, DDM.startY);
18018 this.clickTimeThresh );
18022 * Fired when either the drag pixel threshol or the mousedown hold
18023 * time threshold has been met.
18024 * @method startDrag
18025 * @param x {int} the X position of the original mousedown
18026 * @param y {int} the Y position of the original mousedown
18029 startDrag: function(x, y) {
18030 clearTimeout(this.clickTimeout);
18031 if (this.dragCurrent) {
18032 this.dragCurrent.b4StartDrag(x, y);
18033 this.dragCurrent.startDrag(x, y);
18035 this.dragThreshMet = true;
18039 * Internal function to handle the mouseup event. Will be invoked
18040 * from the context of the document.
18041 * @method handleMouseUp
18042 * @param {Event} e the event
18046 handleMouseUp: function(e) {
18049 Roo.QuickTips.enable();
18051 if (! this.dragCurrent) {
18055 clearTimeout(this.clickTimeout);
18057 if (this.dragThreshMet) {
18058 this.fireEvents(e, true);
18068 * Utility to stop event propagation and event default, if these
18069 * features are turned on.
18070 * @method stopEvent
18071 * @param {Event} e the event as returned by this.getEvent()
18074 stopEvent: function(e){
18075 if(this.stopPropagation) {
18076 e.stopPropagation();
18079 if (this.preventDefault) {
18080 e.preventDefault();
18085 * Internal function to clean up event handlers after the drag
18086 * operation is complete
18088 * @param {Event} e the event
18092 stopDrag: function(e) {
18093 // Fire the drag end event for the item that was dragged
18094 if (this.dragCurrent) {
18095 if (this.dragThreshMet) {
18096 this.dragCurrent.b4EndDrag(e);
18097 this.dragCurrent.endDrag(e);
18100 this.dragCurrent.onMouseUp(e);
18103 this.dragCurrent = null;
18104 this.dragOvers = {};
18108 * Internal function to handle the mousemove event. Will be invoked
18109 * from the context of the html element.
18111 * @TODO figure out what we can do about mouse events lost when the
18112 * user drags objects beyond the window boundary. Currently we can
18113 * detect this in internet explorer by verifying that the mouse is
18114 * down during the mousemove event. Firefox doesn't give us the
18115 * button state on the mousemove event.
18116 * @method handleMouseMove
18117 * @param {Event} e the event
18121 handleMouseMove: function(e) {
18122 if (! this.dragCurrent) {
18126 // var button = e.which || e.button;
18128 // check for IE mouseup outside of page boundary
18129 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18131 return this.handleMouseUp(e);
18134 if (!this.dragThreshMet) {
18135 var diffX = Math.abs(this.startX - e.getPageX());
18136 var diffY = Math.abs(this.startY - e.getPageY());
18137 if (diffX > this.clickPixelThresh ||
18138 diffY > this.clickPixelThresh) {
18139 this.startDrag(this.startX, this.startY);
18143 if (this.dragThreshMet) {
18144 this.dragCurrent.b4Drag(e);
18145 this.dragCurrent.onDrag(e);
18146 if(!this.dragCurrent.moveOnly){
18147 this.fireEvents(e, false);
18157 * Iterates over all of the DragDrop elements to find ones we are
18158 * hovering over or dropping on
18159 * @method fireEvents
18160 * @param {Event} e the event
18161 * @param {boolean} isDrop is this a drop op or a mouseover op?
18165 fireEvents: function(e, isDrop) {
18166 var dc = this.dragCurrent;
18168 // If the user did the mouse up outside of the window, we could
18169 // get here even though we have ended the drag.
18170 if (!dc || dc.isLocked()) {
18174 var pt = e.getPoint();
18176 // cache the previous dragOver array
18182 var enterEvts = [];
18184 // Check to see if the object(s) we were hovering over is no longer
18185 // being hovered over so we can fire the onDragOut event
18186 for (var i in this.dragOvers) {
18188 var ddo = this.dragOvers[i];
18190 if (! this.isTypeOfDD(ddo)) {
18194 if (! this.isOverTarget(pt, ddo, this.mode)) {
18195 outEvts.push( ddo );
18198 oldOvers[i] = true;
18199 delete this.dragOvers[i];
18202 for (var sGroup in dc.groups) {
18204 if ("string" != typeof sGroup) {
18208 for (i in this.ids[sGroup]) {
18209 var oDD = this.ids[sGroup][i];
18210 if (! this.isTypeOfDD(oDD)) {
18214 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18215 if (this.isOverTarget(pt, oDD, this.mode)) {
18216 // look for drop interactions
18218 dropEvts.push( oDD );
18219 // look for drag enter and drag over interactions
18222 // initial drag over: dragEnter fires
18223 if (!oldOvers[oDD.id]) {
18224 enterEvts.push( oDD );
18225 // subsequent drag overs: dragOver fires
18227 overEvts.push( oDD );
18230 this.dragOvers[oDD.id] = oDD;
18238 if (outEvts.length) {
18239 dc.b4DragOut(e, outEvts);
18240 dc.onDragOut(e, outEvts);
18243 if (enterEvts.length) {
18244 dc.onDragEnter(e, enterEvts);
18247 if (overEvts.length) {
18248 dc.b4DragOver(e, overEvts);
18249 dc.onDragOver(e, overEvts);
18252 if (dropEvts.length) {
18253 dc.b4DragDrop(e, dropEvts);
18254 dc.onDragDrop(e, dropEvts);
18258 // fire dragout events
18260 for (i=0, len=outEvts.length; i<len; ++i) {
18261 dc.b4DragOut(e, outEvts[i].id);
18262 dc.onDragOut(e, outEvts[i].id);
18265 // fire enter events
18266 for (i=0,len=enterEvts.length; i<len; ++i) {
18267 // dc.b4DragEnter(e, oDD.id);
18268 dc.onDragEnter(e, enterEvts[i].id);
18271 // fire over events
18272 for (i=0,len=overEvts.length; i<len; ++i) {
18273 dc.b4DragOver(e, overEvts[i].id);
18274 dc.onDragOver(e, overEvts[i].id);
18277 // fire drop events
18278 for (i=0, len=dropEvts.length; i<len; ++i) {
18279 dc.b4DragDrop(e, dropEvts[i].id);
18280 dc.onDragDrop(e, dropEvts[i].id);
18285 // notify about a drop that did not find a target
18286 if (isDrop && !dropEvts.length) {
18287 dc.onInvalidDrop(e);
18293 * Helper function for getting the best match from the list of drag
18294 * and drop objects returned by the drag and drop events when we are
18295 * in INTERSECT mode. It returns either the first object that the
18296 * cursor is over, or the object that has the greatest overlap with
18297 * the dragged element.
18298 * @method getBestMatch
18299 * @param {DragDrop[]} dds The array of drag and drop objects
18301 * @return {DragDrop} The best single match
18304 getBestMatch: function(dds) {
18306 // Return null if the input is not what we expect
18307 //if (!dds || !dds.length || dds.length == 0) {
18309 // If there is only one item, it wins
18310 //} else if (dds.length == 1) {
18312 var len = dds.length;
18317 // Loop through the targeted items
18318 for (var i=0; i<len; ++i) {
18320 // If the cursor is over the object, it wins. If the
18321 // cursor is over multiple matches, the first one we come
18323 if (dd.cursorIsOver) {
18326 // Otherwise the object with the most overlap wins
18329 winner.overlap.getArea() < dd.overlap.getArea()) {
18340 * Refreshes the cache of the top-left and bottom-right points of the
18341 * drag and drop objects in the specified group(s). This is in the
18342 * format that is stored in the drag and drop instance, so typical
18345 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18349 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18351 * @TODO this really should be an indexed array. Alternatively this
18352 * method could accept both.
18353 * @method refreshCache
18354 * @param {Object} groups an associative array of groups to refresh
18357 refreshCache: function(groups) {
18358 for (var sGroup in groups) {
18359 if ("string" != typeof sGroup) {
18362 for (var i in this.ids[sGroup]) {
18363 var oDD = this.ids[sGroup][i];
18365 if (this.isTypeOfDD(oDD)) {
18366 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18367 var loc = this.getLocation(oDD);
18369 this.locationCache[oDD.id] = loc;
18371 delete this.locationCache[oDD.id];
18372 // this will unregister the drag and drop object if
18373 // the element is not in a usable state
18382 * This checks to make sure an element exists and is in the DOM. The
18383 * main purpose is to handle cases where innerHTML is used to remove
18384 * drag and drop objects from the DOM. IE provides an 'unspecified
18385 * error' when trying to access the offsetParent of such an element
18387 * @param {HTMLElement} el the element to check
18388 * @return {boolean} true if the element looks usable
18391 verifyEl: function(el) {
18396 parent = el.offsetParent;
18399 parent = el.offsetParent;
18410 * Returns a Region object containing the drag and drop element's position
18411 * and size, including the padding configured for it
18412 * @method getLocation
18413 * @param {DragDrop} oDD the drag and drop object to get the
18415 * @return {Roo.lib.Region} a Region object representing the total area
18416 * the element occupies, including any padding
18417 * the instance is configured for.
18420 getLocation: function(oDD) {
18421 if (! this.isTypeOfDD(oDD)) {
18425 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18428 pos= Roo.lib.Dom.getXY(el);
18436 x2 = x1 + el.offsetWidth;
18438 y2 = y1 + el.offsetHeight;
18440 t = y1 - oDD.padding[0];
18441 r = x2 + oDD.padding[1];
18442 b = y2 + oDD.padding[2];
18443 l = x1 - oDD.padding[3];
18445 return new Roo.lib.Region( t, r, b, l );
18449 * Checks the cursor location to see if it over the target
18450 * @method isOverTarget
18451 * @param {Roo.lib.Point} pt The point to evaluate
18452 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18453 * @return {boolean} true if the mouse is over the target
18457 isOverTarget: function(pt, oTarget, intersect) {
18458 // use cache if available
18459 var loc = this.locationCache[oTarget.id];
18460 if (!loc || !this.useCache) {
18461 loc = this.getLocation(oTarget);
18462 this.locationCache[oTarget.id] = loc;
18470 oTarget.cursorIsOver = loc.contains( pt );
18472 // DragDrop is using this as a sanity check for the initial mousedown
18473 // in this case we are done. In POINT mode, if the drag obj has no
18474 // contraints, we are also done. Otherwise we need to evaluate the
18475 // location of the target as related to the actual location of the
18476 // dragged element.
18477 var dc = this.dragCurrent;
18478 if (!dc || !dc.getTargetCoord ||
18479 (!intersect && !dc.constrainX && !dc.constrainY)) {
18480 return oTarget.cursorIsOver;
18483 oTarget.overlap = null;
18485 // Get the current location of the drag element, this is the
18486 // location of the mouse event less the delta that represents
18487 // where the original mousedown happened on the element. We
18488 // need to consider constraints and ticks as well.
18489 var pos = dc.getTargetCoord(pt.x, pt.y);
18491 var el = dc.getDragEl();
18492 var curRegion = new Roo.lib.Region( pos.y,
18493 pos.x + el.offsetWidth,
18494 pos.y + el.offsetHeight,
18497 var overlap = curRegion.intersect(loc);
18500 oTarget.overlap = overlap;
18501 return (intersect) ? true : oTarget.cursorIsOver;
18508 * unload event handler
18509 * @method _onUnload
18513 _onUnload: function(e, me) {
18514 Roo.dd.DragDropMgr.unregAll();
18518 * Cleans up the drag and drop events and objects.
18523 unregAll: function() {
18525 if (this.dragCurrent) {
18527 this.dragCurrent = null;
18530 this._execOnAll("unreg", []);
18532 for (i in this.elementCache) {
18533 delete this.elementCache[i];
18536 this.elementCache = {};
18541 * A cache of DOM elements
18542 * @property elementCache
18549 * Get the wrapper for the DOM element specified
18550 * @method getElWrapper
18551 * @param {String} id the id of the element to get
18552 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18554 * @deprecated This wrapper isn't that useful
18557 getElWrapper: function(id) {
18558 var oWrapper = this.elementCache[id];
18559 if (!oWrapper || !oWrapper.el) {
18560 oWrapper = this.elementCache[id] =
18561 new this.ElementWrapper(Roo.getDom(id));
18567 * Returns the actual DOM element
18568 * @method getElement
18569 * @param {String} id the id of the elment to get
18570 * @return {Object} The element
18571 * @deprecated use Roo.getDom instead
18574 getElement: function(id) {
18575 return Roo.getDom(id);
18579 * Returns the style property for the DOM element (i.e.,
18580 * document.getElById(id).style)
18582 * @param {String} id the id of the elment to get
18583 * @return {Object} The style property of the element
18584 * @deprecated use Roo.getDom instead
18587 getCss: function(id) {
18588 var el = Roo.getDom(id);
18589 return (el) ? el.style : null;
18593 * Inner class for cached elements
18594 * @class DragDropMgr.ElementWrapper
18599 ElementWrapper: function(el) {
18604 this.el = el || null;
18609 this.id = this.el && el.id;
18611 * A reference to the style property
18614 this.css = this.el && el.style;
18618 * Returns the X position of an html element
18620 * @param el the element for which to get the position
18621 * @return {int} the X coordinate
18623 * @deprecated use Roo.lib.Dom.getX instead
18626 getPosX: function(el) {
18627 return Roo.lib.Dom.getX(el);
18631 * Returns the Y position of an html element
18633 * @param el the element for which to get the position
18634 * @return {int} the Y coordinate
18635 * @deprecated use Roo.lib.Dom.getY instead
18638 getPosY: function(el) {
18639 return Roo.lib.Dom.getY(el);
18643 * Swap two nodes. In IE, we use the native method, for others we
18644 * emulate the IE behavior
18646 * @param n1 the first node to swap
18647 * @param n2 the other node to swap
18650 swapNode: function(n1, n2) {
18654 var p = n2.parentNode;
18655 var s = n2.nextSibling;
18658 p.insertBefore(n1, n2);
18659 } else if (n2 == n1.nextSibling) {
18660 p.insertBefore(n2, n1);
18662 n1.parentNode.replaceChild(n2, n1);
18663 p.insertBefore(n1, s);
18669 * Returns the current scroll position
18670 * @method getScroll
18674 getScroll: function () {
18675 var t, l, dde=document.documentElement, db=document.body;
18676 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18678 l = dde.scrollLeft;
18685 return { top: t, left: l };
18689 * Returns the specified element style property
18691 * @param {HTMLElement} el the element
18692 * @param {string} styleProp the style property
18693 * @return {string} The value of the style property
18694 * @deprecated use Roo.lib.Dom.getStyle
18697 getStyle: function(el, styleProp) {
18698 return Roo.fly(el).getStyle(styleProp);
18702 * Gets the scrollTop
18703 * @method getScrollTop
18704 * @return {int} the document's scrollTop
18707 getScrollTop: function () { return this.getScroll().top; },
18710 * Gets the scrollLeft
18711 * @method getScrollLeft
18712 * @return {int} the document's scrollTop
18715 getScrollLeft: function () { return this.getScroll().left; },
18718 * Sets the x/y position of an element to the location of the
18721 * @param {HTMLElement} moveEl The element to move
18722 * @param {HTMLElement} targetEl The position reference element
18725 moveToEl: function (moveEl, targetEl) {
18726 var aCoord = Roo.lib.Dom.getXY(targetEl);
18727 Roo.lib.Dom.setXY(moveEl, aCoord);
18731 * Numeric array sort function
18732 * @method numericSort
18735 numericSort: function(a, b) { return (a - b); },
18739 * @property _timeoutCount
18746 * Trying to make the load order less important. Without this we get
18747 * an error if this file is loaded before the Event Utility.
18748 * @method _addListeners
18752 _addListeners: function() {
18753 var DDM = Roo.dd.DDM;
18754 if ( Roo.lib.Event && document ) {
18757 if (DDM._timeoutCount > 2000) {
18759 setTimeout(DDM._addListeners, 10);
18760 if (document && document.body) {
18761 DDM._timeoutCount += 1;
18768 * Recursively searches the immediate parent and all child nodes for
18769 * the handle element in order to determine wheter or not it was
18771 * @method handleWasClicked
18772 * @param node the html element to inspect
18775 handleWasClicked: function(node, id) {
18776 if (this.isHandle(id, node.id)) {
18779 // check to see if this is a text node child of the one we want
18780 var p = node.parentNode;
18783 if (this.isHandle(id, p.id)) {
18798 // shorter alias, save a few bytes
18799 Roo.dd.DDM = Roo.dd.DragDropMgr;
18800 Roo.dd.DDM._addListeners();
18804 * Ext JS Library 1.1.1
18805 * Copyright(c) 2006-2007, Ext JS, LLC.
18807 * Originally Released Under LGPL - original licence link has changed is not relivant.
18810 * <script type="text/javascript">
18815 * A DragDrop implementation where the linked element follows the
18816 * mouse cursor during a drag.
18817 * @extends Roo.dd.DragDrop
18819 * @param {String} id the id of the linked element
18820 * @param {String} sGroup the group of related DragDrop items
18821 * @param {object} config an object containing configurable attributes
18822 * Valid properties for DD:
18825 Roo.dd.DD = function(id, sGroup, config) {
18827 this.init(id, sGroup, config);
18831 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18834 * When set to true, the utility automatically tries to scroll the browser
18835 * window wehn a drag and drop element is dragged near the viewport boundary.
18836 * Defaults to true.
18843 * Sets the pointer offset to the distance between the linked element's top
18844 * left corner and the location the element was clicked
18845 * @method autoOffset
18846 * @param {int} iPageX the X coordinate of the click
18847 * @param {int} iPageY the Y coordinate of the click
18849 autoOffset: function(iPageX, iPageY) {
18850 var x = iPageX - this.startPageX;
18851 var y = iPageY - this.startPageY;
18852 this.setDelta(x, y);
18856 * Sets the pointer offset. You can call this directly to force the
18857 * offset to be in a particular location (e.g., pass in 0,0 to set it
18858 * to the center of the object)
18860 * @param {int} iDeltaX the distance from the left
18861 * @param {int} iDeltaY the distance from the top
18863 setDelta: function(iDeltaX, iDeltaY) {
18864 this.deltaX = iDeltaX;
18865 this.deltaY = iDeltaY;
18869 * Sets the drag element to the location of the mousedown or click event,
18870 * maintaining the cursor location relative to the location on the element
18871 * that was clicked. Override this if you want to place the element in a
18872 * location other than where the cursor is.
18873 * @method setDragElPos
18874 * @param {int} iPageX the X coordinate of the mousedown or drag event
18875 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18877 setDragElPos: function(iPageX, iPageY) {
18878 // the first time we do this, we are going to check to make sure
18879 // the element has css positioning
18881 var el = this.getDragEl();
18882 this.alignElWithMouse(el, iPageX, iPageY);
18886 * Sets the element to the location of the mousedown or click event,
18887 * maintaining the cursor location relative to the location on the element
18888 * that was clicked. Override this if you want to place the element in a
18889 * location other than where the cursor is.
18890 * @method alignElWithMouse
18891 * @param {HTMLElement} el the element to move
18892 * @param {int} iPageX the X coordinate of the mousedown or drag event
18893 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18895 alignElWithMouse: function(el, iPageX, iPageY) {
18896 var oCoord = this.getTargetCoord(iPageX, iPageY);
18897 var fly = el.dom ? el : Roo.fly(el);
18898 if (!this.deltaSetXY) {
18899 var aCoord = [oCoord.x, oCoord.y];
18901 var newLeft = fly.getLeft(true);
18902 var newTop = fly.getTop(true);
18903 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18905 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18908 this.cachePosition(oCoord.x, oCoord.y);
18909 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18914 * Saves the most recent position so that we can reset the constraints and
18915 * tick marks on-demand. We need to know this so that we can calculate the
18916 * number of pixels the element is offset from its original position.
18917 * @method cachePosition
18918 * @param iPageX the current x position (optional, this just makes it so we
18919 * don't have to look it up again)
18920 * @param iPageY the current y position (optional, this just makes it so we
18921 * don't have to look it up again)
18923 cachePosition: function(iPageX, iPageY) {
18925 this.lastPageX = iPageX;
18926 this.lastPageY = iPageY;
18928 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18929 this.lastPageX = aCoord[0];
18930 this.lastPageY = aCoord[1];
18935 * Auto-scroll the window if the dragged object has been moved beyond the
18936 * visible window boundary.
18937 * @method autoScroll
18938 * @param {int} x the drag element's x position
18939 * @param {int} y the drag element's y position
18940 * @param {int} h the height of the drag element
18941 * @param {int} w the width of the drag element
18944 autoScroll: function(x, y, h, w) {
18947 // The client height
18948 var clientH = Roo.lib.Dom.getViewWidth();
18950 // The client width
18951 var clientW = Roo.lib.Dom.getViewHeight();
18953 // The amt scrolled down
18954 var st = this.DDM.getScrollTop();
18956 // The amt scrolled right
18957 var sl = this.DDM.getScrollLeft();
18959 // Location of the bottom of the element
18962 // Location of the right of the element
18965 // The distance from the cursor to the bottom of the visible area,
18966 // adjusted so that we don't scroll if the cursor is beyond the
18967 // element drag constraints
18968 var toBot = (clientH + st - y - this.deltaY);
18970 // The distance from the cursor to the right of the visible area
18971 var toRight = (clientW + sl - x - this.deltaX);
18974 // How close to the edge the cursor must be before we scroll
18975 // var thresh = (document.all) ? 100 : 40;
18978 // How many pixels to scroll per autoscroll op. This helps to reduce
18979 // clunky scrolling. IE is more sensitive about this ... it needs this
18980 // value to be higher.
18981 var scrAmt = (document.all) ? 80 : 30;
18983 // Scroll down if we are near the bottom of the visible page and the
18984 // obj extends below the crease
18985 if ( bot > clientH && toBot < thresh ) {
18986 window.scrollTo(sl, st + scrAmt);
18989 // Scroll up if the window is scrolled down and the top of the object
18990 // goes above the top border
18991 if ( y < st && st > 0 && y - st < thresh ) {
18992 window.scrollTo(sl, st - scrAmt);
18995 // Scroll right if the obj is beyond the right border and the cursor is
18996 // near the border.
18997 if ( right > clientW && toRight < thresh ) {
18998 window.scrollTo(sl + scrAmt, st);
19001 // Scroll left if the window has been scrolled to the right and the obj
19002 // extends past the left border
19003 if ( x < sl && sl > 0 && x - sl < thresh ) {
19004 window.scrollTo(sl - scrAmt, st);
19010 * Finds the location the element should be placed if we want to move
19011 * it to where the mouse location less the click offset would place us.
19012 * @method getTargetCoord
19013 * @param {int} iPageX the X coordinate of the click
19014 * @param {int} iPageY the Y coordinate of the click
19015 * @return an object that contains the coordinates (Object.x and Object.y)
19018 getTargetCoord: function(iPageX, iPageY) {
19021 var x = iPageX - this.deltaX;
19022 var y = iPageY - this.deltaY;
19024 if (this.constrainX) {
19025 if (x < this.minX) { x = this.minX; }
19026 if (x > this.maxX) { x = this.maxX; }
19029 if (this.constrainY) {
19030 if (y < this.minY) { y = this.minY; }
19031 if (y > this.maxY) { y = this.maxY; }
19034 x = this.getTick(x, this.xTicks);
19035 y = this.getTick(y, this.yTicks);
19042 * Sets up config options specific to this class. Overrides
19043 * Roo.dd.DragDrop, but all versions of this method through the
19044 * inheritance chain are called
19046 applyConfig: function() {
19047 Roo.dd.DD.superclass.applyConfig.call(this);
19048 this.scroll = (this.config.scroll !== false);
19052 * Event that fires prior to the onMouseDown event. Overrides
19055 b4MouseDown: function(e) {
19056 // this.resetConstraints();
19057 this.autoOffset(e.getPageX(),
19062 * Event that fires prior to the onDrag event. Overrides
19065 b4Drag: function(e) {
19066 this.setDragElPos(e.getPageX(),
19070 toString: function() {
19071 return ("DD " + this.id);
19074 //////////////////////////////////////////////////////////////////////////
19075 // Debugging ygDragDrop events that can be overridden
19076 //////////////////////////////////////////////////////////////////////////
19078 startDrag: function(x, y) {
19081 onDrag: function(e) {
19084 onDragEnter: function(e, id) {
19087 onDragOver: function(e, id) {
19090 onDragOut: function(e, id) {
19093 onDragDrop: function(e, id) {
19096 endDrag: function(e) {
19103 * Ext JS Library 1.1.1
19104 * Copyright(c) 2006-2007, Ext JS, LLC.
19106 * Originally Released Under LGPL - original licence link has changed is not relivant.
19109 * <script type="text/javascript">
19113 * @class Roo.dd.DDProxy
19114 * A DragDrop implementation that inserts an empty, bordered div into
19115 * the document that follows the cursor during drag operations. At the time of
19116 * the click, the frame div is resized to the dimensions of the linked html
19117 * element, and moved to the exact location of the linked element.
19119 * References to the "frame" element refer to the single proxy element that
19120 * was created to be dragged in place of all DDProxy elements on the
19123 * @extends Roo.dd.DD
19125 * @param {String} id the id of the linked html element
19126 * @param {String} sGroup the group of related DragDrop objects
19127 * @param {object} config an object containing configurable attributes
19128 * Valid properties for DDProxy in addition to those in DragDrop:
19129 * resizeFrame, centerFrame, dragElId
19131 Roo.dd.DDProxy = function(id, sGroup, config) {
19133 this.init(id, sGroup, config);
19139 * The default drag frame div id
19140 * @property Roo.dd.DDProxy.dragElId
19144 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19146 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19149 * By default we resize the drag frame to be the same size as the element
19150 * we want to drag (this is to get the frame effect). We can turn it off
19151 * if we want a different behavior.
19152 * @property resizeFrame
19158 * By default the frame is positioned exactly where the drag element is, so
19159 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19160 * you do not have constraints on the obj is to have the drag frame centered
19161 * around the cursor. Set centerFrame to true for this effect.
19162 * @property centerFrame
19165 centerFrame: false,
19168 * Creates the proxy element if it does not yet exist
19169 * @method createFrame
19171 createFrame: function() {
19173 var body = document.body;
19175 if (!body || !body.firstChild) {
19176 setTimeout( function() { self.createFrame(); }, 50 );
19180 var div = this.getDragEl();
19183 div = document.createElement("div");
19184 div.id = this.dragElId;
19187 s.position = "absolute";
19188 s.visibility = "hidden";
19190 s.border = "2px solid #aaa";
19193 // appendChild can blow up IE if invoked prior to the window load event
19194 // while rendering a table. It is possible there are other scenarios
19195 // that would cause this to happen as well.
19196 body.insertBefore(div, body.firstChild);
19201 * Initialization for the drag frame element. Must be called in the
19202 * constructor of all subclasses
19203 * @method initFrame
19205 initFrame: function() {
19206 this.createFrame();
19209 applyConfig: function() {
19210 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19212 this.resizeFrame = (this.config.resizeFrame !== false);
19213 this.centerFrame = (this.config.centerFrame);
19214 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19218 * Resizes the drag frame to the dimensions of the clicked object, positions
19219 * it over the object, and finally displays it
19220 * @method showFrame
19221 * @param {int} iPageX X click position
19222 * @param {int} iPageY Y click position
19225 showFrame: function(iPageX, iPageY) {
19226 var el = this.getEl();
19227 var dragEl = this.getDragEl();
19228 var s = dragEl.style;
19230 this._resizeProxy();
19232 if (this.centerFrame) {
19233 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19234 Math.round(parseInt(s.height, 10)/2) );
19237 this.setDragElPos(iPageX, iPageY);
19239 Roo.fly(dragEl).show();
19243 * The proxy is automatically resized to the dimensions of the linked
19244 * element when a drag is initiated, unless resizeFrame is set to false
19245 * @method _resizeProxy
19248 _resizeProxy: function() {
19249 if (this.resizeFrame) {
19250 var el = this.getEl();
19251 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19255 // overrides Roo.dd.DragDrop
19256 b4MouseDown: function(e) {
19257 var x = e.getPageX();
19258 var y = e.getPageY();
19259 this.autoOffset(x, y);
19260 this.setDragElPos(x, y);
19263 // overrides Roo.dd.DragDrop
19264 b4StartDrag: function(x, y) {
19265 // show the drag frame
19266 this.showFrame(x, y);
19269 // overrides Roo.dd.DragDrop
19270 b4EndDrag: function(e) {
19271 Roo.fly(this.getDragEl()).hide();
19274 // overrides Roo.dd.DragDrop
19275 // By default we try to move the element to the last location of the frame.
19276 // This is so that the default behavior mirrors that of Roo.dd.DD.
19277 endDrag: function(e) {
19279 var lel = this.getEl();
19280 var del = this.getDragEl();
19282 // Show the drag frame briefly so we can get its position
19283 del.style.visibility = "";
19286 // Hide the linked element before the move to get around a Safari
19288 lel.style.visibility = "hidden";
19289 Roo.dd.DDM.moveToEl(lel, del);
19290 del.style.visibility = "hidden";
19291 lel.style.visibility = "";
19296 beforeMove : function(){
19300 afterDrag : function(){
19304 toString: function() {
19305 return ("DDProxy " + this.id);
19311 * Ext JS Library 1.1.1
19312 * Copyright(c) 2006-2007, Ext JS, LLC.
19314 * Originally Released Under LGPL - original licence link has changed is not relivant.
19317 * <script type="text/javascript">
19321 * @class Roo.dd.DDTarget
19322 * A DragDrop implementation that does not move, but can be a drop
19323 * target. You would get the same result by simply omitting implementation
19324 * for the event callbacks, but this way we reduce the processing cost of the
19325 * event listener and the callbacks.
19326 * @extends Roo.dd.DragDrop
19328 * @param {String} id the id of the element that is a drop target
19329 * @param {String} sGroup the group of related DragDrop objects
19330 * @param {object} config an object containing configurable attributes
19331 * Valid properties for DDTarget in addition to those in
19335 Roo.dd.DDTarget = function(id, sGroup, config) {
19337 this.initTarget(id, sGroup, config);
19339 if (config.listeners || config.events) {
19340 Roo.dd.DragDrop.superclass.constructor.call(this, {
19341 listeners : config.listeners || {},
19342 events : config.events || {}
19347 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19348 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19349 toString: function() {
19350 return ("DDTarget " + this.id);
19355 * Ext JS Library 1.1.1
19356 * Copyright(c) 2006-2007, Ext JS, LLC.
19358 * Originally Released Under LGPL - original licence link has changed is not relivant.
19361 * <script type="text/javascript">
19366 * @class Roo.dd.ScrollManager
19367 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19368 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19371 Roo.dd.ScrollManager = function(){
19372 var ddm = Roo.dd.DragDropMgr;
19379 var onStop = function(e){
19384 var triggerRefresh = function(){
19385 if(ddm.dragCurrent){
19386 ddm.refreshCache(ddm.dragCurrent.groups);
19390 var doScroll = function(){
19391 if(ddm.dragCurrent){
19392 var dds = Roo.dd.ScrollManager;
19394 if(proc.el.scroll(proc.dir, dds.increment)){
19398 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19403 var clearProc = function(){
19405 clearInterval(proc.id);
19412 var startProc = function(el, dir){
19413 Roo.log('scroll startproc');
19417 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19420 var onFire = function(e, isDrop){
19422 if(isDrop || !ddm.dragCurrent){ return; }
19423 var dds = Roo.dd.ScrollManager;
19424 if(!dragEl || dragEl != ddm.dragCurrent){
19425 dragEl = ddm.dragCurrent;
19426 // refresh regions on drag start
19427 dds.refreshCache();
19430 var xy = Roo.lib.Event.getXY(e);
19431 var pt = new Roo.lib.Point(xy[0], xy[1]);
19432 for(var id in els){
19433 var el = els[id], r = el._region;
19434 if(r && r.contains(pt) && el.isScrollable()){
19435 if(r.bottom - pt.y <= dds.thresh){
19437 startProc(el, "down");
19440 }else if(r.right - pt.x <= dds.thresh){
19442 startProc(el, "left");
19445 }else if(pt.y - r.top <= dds.thresh){
19447 startProc(el, "up");
19450 }else if(pt.x - r.left <= dds.thresh){
19452 startProc(el, "right");
19461 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19462 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19466 * Registers new overflow element(s) to auto scroll
19467 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19469 register : function(el){
19470 if(el instanceof Array){
19471 for(var i = 0, len = el.length; i < len; i++) {
19472 this.register(el[i]);
19478 Roo.dd.ScrollManager.els = els;
19482 * Unregisters overflow element(s) so they are no longer scrolled
19483 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19485 unregister : function(el){
19486 if(el instanceof Array){
19487 for(var i = 0, len = el.length; i < len; i++) {
19488 this.unregister(el[i]);
19497 * The number of pixels from the edge of a container the pointer needs to be to
19498 * trigger scrolling (defaults to 25)
19504 * The number of pixels to scroll in each scroll increment (defaults to 50)
19510 * The frequency of scrolls in milliseconds (defaults to 500)
19516 * True to animate the scroll (defaults to true)
19522 * The animation duration in seconds -
19523 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19529 * Manually trigger a cache refresh.
19531 refreshCache : function(){
19532 for(var id in els){
19533 if(typeof els[id] == 'object'){ // for people extending the object prototype
19534 els[id]._region = els[id].getRegion();
19541 * Ext JS Library 1.1.1
19542 * Copyright(c) 2006-2007, Ext JS, LLC.
19544 * Originally Released Under LGPL - original licence link has changed is not relivant.
19547 * <script type="text/javascript">
19552 * @class Roo.dd.Registry
19553 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19554 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19557 Roo.dd.Registry = function(){
19560 var autoIdSeed = 0;
19562 var getId = function(el, autogen){
19563 if(typeof el == "string"){
19567 if(!id && autogen !== false){
19568 id = "roodd-" + (++autoIdSeed);
19576 * Register a drag drop element
19577 * @param {String|HTMLElement} element The id or DOM node to register
19578 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19579 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19580 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19581 * populated in the data object (if applicable):
19583 Value Description<br />
19584 --------- ------------------------------------------<br />
19585 handles Array of DOM nodes that trigger dragging<br />
19586 for the element being registered<br />
19587 isHandle True if the element passed in triggers<br />
19588 dragging itself, else false
19591 register : function(el, data){
19593 if(typeof el == "string"){
19594 el = document.getElementById(el);
19597 elements[getId(el)] = data;
19598 if(data.isHandle !== false){
19599 handles[data.ddel.id] = data;
19602 var hs = data.handles;
19603 for(var i = 0, len = hs.length; i < len; i++){
19604 handles[getId(hs[i])] = data;
19610 * Unregister a drag drop element
19611 * @param {String|HTMLElement} element The id or DOM node to unregister
19613 unregister : function(el){
19614 var id = getId(el, false);
19615 var data = elements[id];
19617 delete elements[id];
19619 var hs = data.handles;
19620 for(var i = 0, len = hs.length; i < len; i++){
19621 delete handles[getId(hs[i], false)];
19628 * Returns the handle registered for a DOM Node by id
19629 * @param {String|HTMLElement} id The DOM node or id to look up
19630 * @return {Object} handle The custom handle data
19632 getHandle : function(id){
19633 if(typeof id != "string"){ // must be element?
19636 return handles[id];
19640 * Returns the handle that is registered for the DOM node that is the target of the event
19641 * @param {Event} e The event
19642 * @return {Object} handle The custom handle data
19644 getHandleFromEvent : function(e){
19645 var t = Roo.lib.Event.getTarget(e);
19646 return t ? handles[t.id] : null;
19650 * Returns a custom data object that is registered for a DOM node by id
19651 * @param {String|HTMLElement} id The DOM node or id to look up
19652 * @return {Object} data The custom data
19654 getTarget : function(id){
19655 if(typeof id != "string"){ // must be element?
19658 return elements[id];
19662 * Returns a custom data object that is registered for the DOM node that is the target of the event
19663 * @param {Event} e The event
19664 * @return {Object} data The custom data
19666 getTargetFromEvent : function(e){
19667 var t = Roo.lib.Event.getTarget(e);
19668 return t ? elements[t.id] || handles[t.id] : null;
19673 * Ext JS Library 1.1.1
19674 * Copyright(c) 2006-2007, Ext JS, LLC.
19676 * Originally Released Under LGPL - original licence link has changed is not relivant.
19679 * <script type="text/javascript">
19684 * @class Roo.dd.StatusProxy
19685 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19686 * default drag proxy used by all Roo.dd components.
19688 * @param {Object} config
19690 Roo.dd.StatusProxy = function(config){
19691 Roo.apply(this, config);
19692 this.id = this.id || Roo.id();
19693 this.el = new Roo.Layer({
19695 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19696 {tag: "div", cls: "x-dd-drop-icon"},
19697 {tag: "div", cls: "x-dd-drag-ghost"}
19700 shadow: !config || config.shadow !== false
19702 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19703 this.dropStatus = this.dropNotAllowed;
19706 Roo.dd.StatusProxy.prototype = {
19708 * @cfg {String} dropAllowed
19709 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19711 dropAllowed : "x-dd-drop-ok",
19713 * @cfg {String} dropNotAllowed
19714 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19716 dropNotAllowed : "x-dd-drop-nodrop",
19719 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19720 * over the current target element.
19721 * @param {String} cssClass The css class for the new drop status indicator image
19723 setStatus : function(cssClass){
19724 cssClass = cssClass || this.dropNotAllowed;
19725 if(this.dropStatus != cssClass){
19726 this.el.replaceClass(this.dropStatus, cssClass);
19727 this.dropStatus = cssClass;
19732 * Resets the status indicator to the default dropNotAllowed value
19733 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19735 reset : function(clearGhost){
19736 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19737 this.dropStatus = this.dropNotAllowed;
19739 this.ghost.update("");
19744 * Updates the contents of the ghost element
19745 * @param {String} html The html that will replace the current innerHTML of the ghost element
19747 update : function(html){
19748 if(typeof html == "string"){
19749 this.ghost.update(html);
19751 this.ghost.update("");
19752 html.style.margin = "0";
19753 this.ghost.dom.appendChild(html);
19755 // ensure float = none set?? cant remember why though.
19756 var el = this.ghost.dom.firstChild;
19758 Roo.fly(el).setStyle('float', 'none');
19763 * Returns the underlying proxy {@link Roo.Layer}
19764 * @return {Roo.Layer} el
19766 getEl : function(){
19771 * Returns the ghost element
19772 * @return {Roo.Element} el
19774 getGhost : function(){
19780 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19782 hide : function(clear){
19790 * Stops the repair animation if it's currently running
19793 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19799 * Displays this proxy
19806 * Force the Layer to sync its shadow and shim positions to the element
19813 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19814 * invalid drop operation by the item being dragged.
19815 * @param {Array} xy The XY position of the element ([x, y])
19816 * @param {Function} callback The function to call after the repair is complete
19817 * @param {Object} scope The scope in which to execute the callback
19819 repair : function(xy, callback, scope){
19820 this.callback = callback;
19821 this.scope = scope;
19822 if(xy && this.animRepair !== false){
19823 this.el.addClass("x-dd-drag-repair");
19824 this.el.hideUnders(true);
19825 this.anim = this.el.shift({
19826 duration: this.repairDuration || .5,
19830 callback: this.afterRepair,
19834 this.afterRepair();
19839 afterRepair : function(){
19841 if(typeof this.callback == "function"){
19842 this.callback.call(this.scope || this);
19844 this.callback = null;
19849 * Ext JS Library 1.1.1
19850 * Copyright(c) 2006-2007, Ext JS, LLC.
19852 * Originally Released Under LGPL - original licence link has changed is not relivant.
19855 * <script type="text/javascript">
19859 * @class Roo.dd.DragSource
19860 * @extends Roo.dd.DDProxy
19861 * A simple class that provides the basic implementation needed to make any element draggable.
19863 * @param {String/HTMLElement/Element} el The container element
19864 * @param {Object} config
19866 Roo.dd.DragSource = function(el, config){
19867 this.el = Roo.get(el);
19868 this.dragData = {};
19870 Roo.apply(this, config);
19873 this.proxy = new Roo.dd.StatusProxy();
19876 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19877 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19879 this.dragging = false;
19882 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19884 * @cfg {String} dropAllowed
19885 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19887 dropAllowed : "x-dd-drop-ok",
19889 * @cfg {String} dropNotAllowed
19890 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19892 dropNotAllowed : "x-dd-drop-nodrop",
19895 * Returns the data object associated with this drag source
19896 * @return {Object} data An object containing arbitrary data
19898 getDragData : function(e){
19899 return this.dragData;
19903 onDragEnter : function(e, id){
19904 var target = Roo.dd.DragDropMgr.getDDById(id);
19905 this.cachedTarget = target;
19906 if(this.beforeDragEnter(target, e, id) !== false){
19907 if(target.isNotifyTarget){
19908 var status = target.notifyEnter(this, e, this.dragData);
19909 this.proxy.setStatus(status);
19911 this.proxy.setStatus(this.dropAllowed);
19914 if(this.afterDragEnter){
19916 * An empty function by default, but provided so that you can perform a custom action
19917 * when the dragged item enters the drop target by providing an implementation.
19918 * @param {Roo.dd.DragDrop} target The drop target
19919 * @param {Event} e The event object
19920 * @param {String} id The id of the dragged element
19921 * @method afterDragEnter
19923 this.afterDragEnter(target, e, id);
19929 * An empty function by default, but provided so that you can perform a custom action
19930 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19931 * @param {Roo.dd.DragDrop} target The drop target
19932 * @param {Event} e The event object
19933 * @param {String} id The id of the dragged element
19934 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19936 beforeDragEnter : function(target, e, id){
19941 alignElWithMouse: function() {
19942 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19947 onDragOver : function(e, id){
19948 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19949 if(this.beforeDragOver(target, e, id) !== false){
19950 if(target.isNotifyTarget){
19951 var status = target.notifyOver(this, e, this.dragData);
19952 this.proxy.setStatus(status);
19955 if(this.afterDragOver){
19957 * An empty function by default, but provided so that you can perform a custom action
19958 * while the dragged item is over the drop target by providing an implementation.
19959 * @param {Roo.dd.DragDrop} target The drop target
19960 * @param {Event} e The event object
19961 * @param {String} id The id of the dragged element
19962 * @method afterDragOver
19964 this.afterDragOver(target, e, id);
19970 * An empty function by default, but provided so that you can perform a custom action
19971 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19972 * @param {Roo.dd.DragDrop} target The drop target
19973 * @param {Event} e The event object
19974 * @param {String} id The id of the dragged element
19975 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19977 beforeDragOver : function(target, e, id){
19982 onDragOut : function(e, id){
19983 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19984 if(this.beforeDragOut(target, e, id) !== false){
19985 if(target.isNotifyTarget){
19986 target.notifyOut(this, e, this.dragData);
19988 this.proxy.reset();
19989 if(this.afterDragOut){
19991 * An empty function by default, but provided so that you can perform a custom action
19992 * after the dragged item is dragged out of the target without dropping.
19993 * @param {Roo.dd.DragDrop} target The drop target
19994 * @param {Event} e The event object
19995 * @param {String} id The id of the dragged element
19996 * @method afterDragOut
19998 this.afterDragOut(target, e, id);
20001 this.cachedTarget = null;
20005 * An empty function by default, but provided so that you can perform a custom action before the dragged
20006 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20007 * @param {Roo.dd.DragDrop} target The drop target
20008 * @param {Event} e The event object
20009 * @param {String} id The id of the dragged element
20010 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20012 beforeDragOut : function(target, e, id){
20017 onDragDrop : function(e, id){
20018 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20019 if(this.beforeDragDrop(target, e, id) !== false){
20020 if(target.isNotifyTarget){
20021 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20022 this.onValidDrop(target, e, id);
20024 this.onInvalidDrop(target, e, id);
20027 this.onValidDrop(target, e, id);
20030 if(this.afterDragDrop){
20032 * An empty function by default, but provided so that you can perform a custom action
20033 * after a valid drag drop has occurred by providing an implementation.
20034 * @param {Roo.dd.DragDrop} target The drop target
20035 * @param {Event} e The event object
20036 * @param {String} id The id of the dropped element
20037 * @method afterDragDrop
20039 this.afterDragDrop(target, e, id);
20042 delete this.cachedTarget;
20046 * An empty function by default, but provided so that you can perform a custom action before the dragged
20047 * item is dropped onto the target and optionally cancel the onDragDrop.
20048 * @param {Roo.dd.DragDrop} target The drop target
20049 * @param {Event} e The event object
20050 * @param {String} id The id of the dragged element
20051 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20053 beforeDragDrop : function(target, e, id){
20058 onValidDrop : function(target, e, id){
20060 if(this.afterValidDrop){
20062 * An empty function by default, but provided so that you can perform a custom action
20063 * after a valid drop has occurred by providing an implementation.
20064 * @param {Object} target The target DD
20065 * @param {Event} e The event object
20066 * @param {String} id The id of the dropped element
20067 * @method afterInvalidDrop
20069 this.afterValidDrop(target, e, id);
20074 getRepairXY : function(e, data){
20075 return this.el.getXY();
20079 onInvalidDrop : function(target, e, id){
20080 this.beforeInvalidDrop(target, e, id);
20081 if(this.cachedTarget){
20082 if(this.cachedTarget.isNotifyTarget){
20083 this.cachedTarget.notifyOut(this, e, this.dragData);
20085 this.cacheTarget = null;
20087 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20089 if(this.afterInvalidDrop){
20091 * An empty function by default, but provided so that you can perform a custom action
20092 * after an invalid drop has occurred by providing an implementation.
20093 * @param {Event} e The event object
20094 * @param {String} id The id of the dropped element
20095 * @method afterInvalidDrop
20097 this.afterInvalidDrop(e, id);
20102 afterRepair : function(){
20104 this.el.highlight(this.hlColor || "c3daf9");
20106 this.dragging = false;
20110 * An empty function by default, but provided so that you can perform a custom action after an invalid
20111 * drop has occurred.
20112 * @param {Roo.dd.DragDrop} target The drop target
20113 * @param {Event} e The event object
20114 * @param {String} id The id of the dragged element
20115 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20117 beforeInvalidDrop : function(target, e, id){
20122 handleMouseDown : function(e){
20123 if(this.dragging) {
20126 var data = this.getDragData(e);
20127 if(data && this.onBeforeDrag(data, e) !== false){
20128 this.dragData = data;
20130 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20135 * An empty function by default, but provided so that you can perform a custom action before the initial
20136 * drag event begins and optionally cancel it.
20137 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20138 * @param {Event} e The event object
20139 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20141 onBeforeDrag : function(data, e){
20146 * An empty function by default, but provided so that you can perform a custom action once the initial
20147 * drag event has begun. The drag cannot be canceled from this function.
20148 * @param {Number} x The x position of the click on the dragged object
20149 * @param {Number} y The y position of the click on the dragged object
20151 onStartDrag : Roo.emptyFn,
20153 // private - YUI override
20154 startDrag : function(x, y){
20155 this.proxy.reset();
20156 this.dragging = true;
20157 this.proxy.update("");
20158 this.onInitDrag(x, y);
20163 onInitDrag : function(x, y){
20164 var clone = this.el.dom.cloneNode(true);
20165 clone.id = Roo.id(); // prevent duplicate ids
20166 this.proxy.update(clone);
20167 this.onStartDrag(x, y);
20172 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20173 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20175 getProxy : function(){
20180 * Hides the drag source's {@link Roo.dd.StatusProxy}
20182 hideProxy : function(){
20184 this.proxy.reset(true);
20185 this.dragging = false;
20189 triggerCacheRefresh : function(){
20190 Roo.dd.DDM.refreshCache(this.groups);
20193 // private - override to prevent hiding
20194 b4EndDrag: function(e) {
20197 // private - override to prevent moving
20198 endDrag : function(e){
20199 this.onEndDrag(this.dragData, e);
20203 onEndDrag : function(data, e){
20206 // private - pin to cursor
20207 autoOffset : function(x, y) {
20208 this.setDelta(-12, -20);
20212 * Ext JS Library 1.1.1
20213 * Copyright(c) 2006-2007, Ext JS, LLC.
20215 * Originally Released Under LGPL - original licence link has changed is not relivant.
20218 * <script type="text/javascript">
20223 * @class Roo.dd.DropTarget
20224 * @extends Roo.dd.DDTarget
20225 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20226 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20228 * @param {String/HTMLElement/Element} el The container element
20229 * @param {Object} config
20231 Roo.dd.DropTarget = function(el, config){
20232 this.el = Roo.get(el);
20234 var listeners = false; ;
20235 if (config && config.listeners) {
20236 listeners= config.listeners;
20237 delete config.listeners;
20239 Roo.apply(this, config);
20241 if(this.containerScroll){
20242 Roo.dd.ScrollManager.register(this.el);
20246 * @scope Roo.dd.DropTarget
20251 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20252 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20253 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20255 * IMPORTANT : it should set this.overClass and this.dropAllowed
20257 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20258 * @param {Event} e The event
20259 * @param {Object} data An object containing arbitrary data supplied by the drag source
20265 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20266 * This method will be called on every mouse movement while the drag source is over the drop target.
20267 * This default implementation simply returns the dropAllowed config value.
20269 * IMPORTANT : it should set this.dropAllowed
20271 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20272 * @param {Event} e The event
20273 * @param {Object} data An object containing arbitrary data supplied by the drag source
20279 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20280 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20281 * overClass (if any) from the drop element.
20283 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20284 * @param {Event} e The event
20285 * @param {Object} data An object containing arbitrary data supplied by the drag source
20291 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20292 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20293 * implementation that does something to process the drop event and returns true so that the drag source's
20294 * repair action does not run.
20296 * IMPORTANT : it should set this.success
20298 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20299 * @param {Event} e The event
20300 * @param {Object} data An object containing arbitrary data supplied by the drag source
20306 Roo.dd.DropTarget.superclass.constructor.call( this,
20308 this.ddGroup || this.group,
20311 listeners : listeners || {}
20319 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20321 * @cfg {String} overClass
20322 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20325 * @cfg {String} ddGroup
20326 * The drag drop group to handle drop events for
20330 * @cfg {String} dropAllowed
20331 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20333 dropAllowed : "x-dd-drop-ok",
20335 * @cfg {String} dropNotAllowed
20336 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20338 dropNotAllowed : "x-dd-drop-nodrop",
20340 * @cfg {boolean} success
20341 * set this after drop listener..
20345 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20346 * if the drop point is valid for over/enter..
20353 isNotifyTarget : true,
20358 notifyEnter : function(dd, e, data)
20361 this.fireEvent('enter', dd, e, data);
20362 if(this.overClass){
20363 this.el.addClass(this.overClass);
20365 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20366 this.valid ? this.dropAllowed : this.dropNotAllowed
20373 notifyOver : function(dd, e, data)
20376 this.fireEvent('over', dd, e, data);
20377 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20378 this.valid ? this.dropAllowed : this.dropNotAllowed
20385 notifyOut : function(dd, e, data)
20387 this.fireEvent('out', dd, e, data);
20388 if(this.overClass){
20389 this.el.removeClass(this.overClass);
20396 notifyDrop : function(dd, e, data)
20398 this.success = false;
20399 this.fireEvent('drop', dd, e, data);
20400 return this.success;
20404 * Ext JS Library 1.1.1
20405 * Copyright(c) 2006-2007, Ext JS, LLC.
20407 * Originally Released Under LGPL - original licence link has changed is not relivant.
20410 * <script type="text/javascript">
20415 * @class Roo.dd.DragZone
20416 * @extends Roo.dd.DragSource
20417 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20418 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20420 * @param {String/HTMLElement/Element} el The container element
20421 * @param {Object} config
20423 Roo.dd.DragZone = function(el, config){
20424 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20425 if(this.containerScroll){
20426 Roo.dd.ScrollManager.register(this.el);
20430 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20432 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20433 * for auto scrolling during drag operations.
20436 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20437 * method after a failed drop (defaults to "c3daf9" - light blue)
20441 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20442 * for a valid target to drag based on the mouse down. Override this method
20443 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20444 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20445 * @param {EventObject} e The mouse down event
20446 * @return {Object} The dragData
20448 getDragData : function(e){
20449 return Roo.dd.Registry.getHandleFromEvent(e);
20453 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20454 * this.dragData.ddel
20455 * @param {Number} x The x position of the click on the dragged object
20456 * @param {Number} y The y position of the click on the dragged object
20457 * @return {Boolean} true to continue the drag, false to cancel
20459 onInitDrag : function(x, y){
20460 this.proxy.update(this.dragData.ddel.cloneNode(true));
20461 this.onStartDrag(x, y);
20466 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20468 afterRepair : function(){
20470 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20472 this.dragging = false;
20476 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20477 * the XY of this.dragData.ddel
20478 * @param {EventObject} e The mouse up event
20479 * @return {Array} The xy location (e.g. [100, 200])
20481 getRepairXY : function(e){
20482 return Roo.Element.fly(this.dragData.ddel).getXY();
20486 * Ext JS Library 1.1.1
20487 * Copyright(c) 2006-2007, Ext JS, LLC.
20489 * Originally Released Under LGPL - original licence link has changed is not relivant.
20492 * <script type="text/javascript">
20495 * @class Roo.dd.DropZone
20496 * @extends Roo.dd.DropTarget
20497 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20498 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20500 * @param {String/HTMLElement/Element} el The container element
20501 * @param {Object} config
20503 Roo.dd.DropZone = function(el, config){
20504 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20507 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20509 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20510 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20511 * provide your own custom lookup.
20512 * @param {Event} e The event
20513 * @return {Object} data The custom data
20515 getTargetFromEvent : function(e){
20516 return Roo.dd.Registry.getTargetFromEvent(e);
20520 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20521 * that it has registered. This method has no default implementation and should be overridden to provide
20522 * node-specific processing if necessary.
20523 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20524 * {@link #getTargetFromEvent} for this node)
20525 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20526 * @param {Event} e The event
20527 * @param {Object} data An object containing arbitrary data supplied by the drag source
20529 onNodeEnter : function(n, dd, e, data){
20534 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20535 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20536 * overridden to provide the proper feedback.
20537 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20538 * {@link #getTargetFromEvent} for this node)
20539 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20540 * @param {Event} e The event
20541 * @param {Object} data An object containing arbitrary data supplied by the drag source
20542 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20543 * underlying {@link Roo.dd.StatusProxy} can be updated
20545 onNodeOver : function(n, dd, e, data){
20546 return this.dropAllowed;
20550 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20551 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20552 * node-specific processing if necessary.
20553 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20554 * {@link #getTargetFromEvent} for this node)
20555 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20556 * @param {Event} e The event
20557 * @param {Object} data An object containing arbitrary data supplied by the drag source
20559 onNodeOut : function(n, dd, e, data){
20564 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20565 * the drop node. The default implementation returns false, so it should be overridden to provide the
20566 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20567 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20568 * {@link #getTargetFromEvent} for this node)
20569 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20570 * @param {Event} e The event
20571 * @param {Object} data An object containing arbitrary data supplied by the drag source
20572 * @return {Boolean} True if the drop was valid, else false
20574 onNodeDrop : function(n, dd, e, data){
20579 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20580 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20581 * it should be overridden to provide the proper feedback if necessary.
20582 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20583 * @param {Event} e The event
20584 * @param {Object} data An object containing arbitrary data supplied by the drag source
20585 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20586 * underlying {@link Roo.dd.StatusProxy} can be updated
20588 onContainerOver : function(dd, e, data){
20589 return this.dropNotAllowed;
20593 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20594 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20595 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20596 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20597 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20598 * @param {Event} e The event
20599 * @param {Object} data An object containing arbitrary data supplied by the drag source
20600 * @return {Boolean} True if the drop was valid, else false
20602 onContainerDrop : function(dd, e, data){
20607 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20608 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20609 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20610 * you should override this method and provide a custom implementation.
20611 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20612 * @param {Event} e The event
20613 * @param {Object} data An object containing arbitrary data supplied by the drag source
20614 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20615 * underlying {@link Roo.dd.StatusProxy} can be updated
20617 notifyEnter : function(dd, e, data){
20618 return this.dropNotAllowed;
20622 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20623 * This method will be called on every mouse movement while the drag source is over the drop zone.
20624 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20625 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20626 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20627 * registered node, it will call {@link #onContainerOver}.
20628 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20629 * @param {Event} e The event
20630 * @param {Object} data An object containing arbitrary data supplied by the drag source
20631 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20632 * underlying {@link Roo.dd.StatusProxy} can be updated
20634 notifyOver : function(dd, e, data){
20635 var n = this.getTargetFromEvent(e);
20636 if(!n){ // not over valid drop target
20637 if(this.lastOverNode){
20638 this.onNodeOut(this.lastOverNode, dd, e, data);
20639 this.lastOverNode = null;
20641 return this.onContainerOver(dd, e, data);
20643 if(this.lastOverNode != n){
20644 if(this.lastOverNode){
20645 this.onNodeOut(this.lastOverNode, dd, e, data);
20647 this.onNodeEnter(n, dd, e, data);
20648 this.lastOverNode = n;
20650 return this.onNodeOver(n, dd, e, data);
20654 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20655 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20656 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20657 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20658 * @param {Event} e The event
20659 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20661 notifyOut : function(dd, e, data){
20662 if(this.lastOverNode){
20663 this.onNodeOut(this.lastOverNode, dd, e, data);
20664 this.lastOverNode = null;
20669 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20670 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20671 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20672 * otherwise it will call {@link #onContainerDrop}.
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 {Boolean} True if the drop was valid, else false
20678 notifyDrop : function(dd, e, data){
20679 if(this.lastOverNode){
20680 this.onNodeOut(this.lastOverNode, dd, e, data);
20681 this.lastOverNode = null;
20683 var n = this.getTargetFromEvent(e);
20685 this.onNodeDrop(n, dd, e, data) :
20686 this.onContainerDrop(dd, e, data);
20690 triggerCacheRefresh : function(){
20691 Roo.dd.DDM.refreshCache(this.groups);
20695 * Ext JS Library 1.1.1
20696 * Copyright(c) 2006-2007, Ext JS, LLC.
20698 * Originally Released Under LGPL - original licence link has changed is not relivant.
20701 * <script type="text/javascript">
20706 * @class Roo.data.SortTypes
20708 * Defines the default sorting (casting?) comparison functions used when sorting data.
20710 Roo.data.SortTypes = {
20712 * Default sort that does nothing
20713 * @param {Mixed} s The value being converted
20714 * @return {Mixed} The comparison value
20716 none : function(s){
20721 * The regular expression used to strip tags
20725 stripTagsRE : /<\/?[^>]+>/gi,
20728 * Strips all HTML tags to sort on text only
20729 * @param {Mixed} s The value being converted
20730 * @return {String} The comparison value
20732 asText : function(s){
20733 return String(s).replace(this.stripTagsRE, "");
20737 * Strips all HTML tags to sort on text only - Case insensitive
20738 * @param {Mixed} s The value being converted
20739 * @return {String} The comparison value
20741 asUCText : function(s){
20742 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20746 * Case insensitive string
20747 * @param {Mixed} s The value being converted
20748 * @return {String} The comparison value
20750 asUCString : function(s) {
20751 return String(s).toUpperCase();
20756 * @param {Mixed} s The value being converted
20757 * @return {Number} The comparison value
20759 asDate : function(s) {
20763 if(s instanceof Date){
20764 return s.getTime();
20766 return Date.parse(String(s));
20771 * @param {Mixed} s The value being converted
20772 * @return {Float} The comparison value
20774 asFloat : function(s) {
20775 var val = parseFloat(String(s).replace(/,/g, ""));
20776 if(isNaN(val)) val = 0;
20782 * @param {Mixed} s The value being converted
20783 * @return {Number} The comparison value
20785 asInt : function(s) {
20786 var val = parseInt(String(s).replace(/,/g, ""));
20787 if(isNaN(val)) val = 0;
20792 * Ext JS Library 1.1.1
20793 * Copyright(c) 2006-2007, Ext JS, LLC.
20795 * Originally Released Under LGPL - original licence link has changed is not relivant.
20798 * <script type="text/javascript">
20802 * @class Roo.data.Record
20803 * Instances of this class encapsulate both record <em>definition</em> information, and record
20804 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20805 * to access Records cached in an {@link Roo.data.Store} object.<br>
20807 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20808 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20811 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20813 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20814 * {@link #create}. The parameters are the same.
20815 * @param {Array} data An associative Array of data values keyed by the field name.
20816 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20817 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20818 * not specified an integer id is generated.
20820 Roo.data.Record = function(data, id){
20821 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20826 * Generate a constructor for a specific record layout.
20827 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20828 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20829 * Each field definition object may contain the following properties: <ul>
20830 * <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,
20831 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20832 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20833 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20834 * is being used, then this is a string containing the javascript expression to reference the data relative to
20835 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20836 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20837 * this may be omitted.</p></li>
20838 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20839 * <ul><li>auto (Default, implies no conversion)</li>
20844 * <li>date</li></ul></p></li>
20845 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20846 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20847 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20848 * by the Reader into an object that will be stored in the Record. It is passed the
20849 * following parameters:<ul>
20850 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20852 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20854 * <br>usage:<br><pre><code>
20855 var TopicRecord = Roo.data.Record.create(
20856 {name: 'title', mapping: 'topic_title'},
20857 {name: 'author', mapping: 'username'},
20858 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20859 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20860 {name: 'lastPoster', mapping: 'user2'},
20861 {name: 'excerpt', mapping: 'post_text'}
20864 var myNewRecord = new TopicRecord({
20865 title: 'Do my job please',
20868 lastPost: new Date(),
20869 lastPoster: 'Animal',
20870 excerpt: 'No way dude!'
20872 myStore.add(myNewRecord);
20877 Roo.data.Record.create = function(o){
20878 var f = function(){
20879 f.superclass.constructor.apply(this, arguments);
20881 Roo.extend(f, Roo.data.Record);
20882 var p = f.prototype;
20883 p.fields = new Roo.util.MixedCollection(false, function(field){
20886 for(var i = 0, len = o.length; i < len; i++){
20887 p.fields.add(new Roo.data.Field(o[i]));
20889 f.getField = function(name){
20890 return p.fields.get(name);
20895 Roo.data.Record.AUTO_ID = 1000;
20896 Roo.data.Record.EDIT = 'edit';
20897 Roo.data.Record.REJECT = 'reject';
20898 Roo.data.Record.COMMIT = 'commit';
20900 Roo.data.Record.prototype = {
20902 * Readonly flag - true if this record has been modified.
20911 join : function(store){
20912 this.store = store;
20916 * Set the named field to the specified value.
20917 * @param {String} name The name of the field to set.
20918 * @param {Object} value The value to set the field to.
20920 set : function(name, value){
20921 if(this.data[name] == value){
20925 if(!this.modified){
20926 this.modified = {};
20928 if(typeof this.modified[name] == 'undefined'){
20929 this.modified[name] = this.data[name];
20931 this.data[name] = value;
20932 if(!this.editing && this.store){
20933 this.store.afterEdit(this);
20938 * Get the value of the named field.
20939 * @param {String} name The name of the field to get the value of.
20940 * @return {Object} The value of the field.
20942 get : function(name){
20943 return this.data[name];
20947 beginEdit : function(){
20948 this.editing = true;
20949 this.modified = {};
20953 cancelEdit : function(){
20954 this.editing = false;
20955 delete this.modified;
20959 endEdit : function(){
20960 this.editing = false;
20961 if(this.dirty && this.store){
20962 this.store.afterEdit(this);
20967 * Usually called by the {@link Roo.data.Store} which owns the Record.
20968 * Rejects all changes made to the Record since either creation, or the last commit operation.
20969 * Modified fields are reverted to their original values.
20971 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20972 * of reject operations.
20974 reject : function(){
20975 var m = this.modified;
20977 if(typeof m[n] != "function"){
20978 this.data[n] = m[n];
20981 this.dirty = false;
20982 delete this.modified;
20983 this.editing = false;
20985 this.store.afterReject(this);
20990 * Usually called by the {@link Roo.data.Store} which owns the Record.
20991 * Commits all changes made to the Record since either creation, or the last commit operation.
20993 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20994 * of commit operations.
20996 commit : function(){
20997 this.dirty = false;
20998 delete this.modified;
20999 this.editing = false;
21001 this.store.afterCommit(this);
21006 hasError : function(){
21007 return this.error != null;
21011 clearError : function(){
21016 * Creates a copy of this record.
21017 * @param {String} id (optional) A new record id if you don't want to use this record's id
21020 copy : function(newId) {
21021 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21025 * Ext JS Library 1.1.1
21026 * Copyright(c) 2006-2007, Ext JS, LLC.
21028 * Originally Released Under LGPL - original licence link has changed is not relivant.
21031 * <script type="text/javascript">
21037 * @class Roo.data.Store
21038 * @extends Roo.util.Observable
21039 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21040 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21042 * 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
21043 * has no knowledge of the format of the data returned by the Proxy.<br>
21045 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21046 * instances from the data object. These records are cached and made available through accessor functions.
21048 * Creates a new Store.
21049 * @param {Object} config A config object containing the objects needed for the Store to access data,
21050 * and read the data into Records.
21052 Roo.data.Store = function(config){
21053 this.data = new Roo.util.MixedCollection(false);
21054 this.data.getKey = function(o){
21057 this.baseParams = {};
21059 this.paramNames = {
21064 "multisort" : "_multisort"
21067 if(config && config.data){
21068 this.inlineData = config.data;
21069 delete config.data;
21072 Roo.apply(this, config);
21074 if(this.reader){ // reader passed
21075 this.reader = Roo.factory(this.reader, Roo.data);
21076 this.reader.xmodule = this.xmodule || false;
21077 if(!this.recordType){
21078 this.recordType = this.reader.recordType;
21080 if(this.reader.onMetaChange){
21081 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21085 if(this.recordType){
21086 this.fields = this.recordType.prototype.fields;
21088 this.modified = [];
21092 * @event datachanged
21093 * Fires when the data cache has changed, and a widget which is using this Store
21094 * as a Record cache should refresh its view.
21095 * @param {Store} this
21097 datachanged : true,
21099 * @event metachange
21100 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21101 * @param {Store} this
21102 * @param {Object} meta The JSON metadata
21107 * Fires when Records have been added to the Store
21108 * @param {Store} this
21109 * @param {Roo.data.Record[]} records The array of Records added
21110 * @param {Number} index The index at which the record(s) were added
21115 * Fires when a Record has been removed from the Store
21116 * @param {Store} this
21117 * @param {Roo.data.Record} record The Record that was removed
21118 * @param {Number} index The index at which the record was removed
21123 * Fires when a Record has been updated
21124 * @param {Store} this
21125 * @param {Roo.data.Record} record The Record that was updated
21126 * @param {String} operation The update operation being performed. Value may be one of:
21128 Roo.data.Record.EDIT
21129 Roo.data.Record.REJECT
21130 Roo.data.Record.COMMIT
21136 * Fires when the data cache has been cleared.
21137 * @param {Store} this
21141 * @event beforeload
21142 * Fires before a request is made for a new data object. If the beforeload handler returns false
21143 * the load action will be canceled.
21144 * @param {Store} this
21145 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21149 * @event beforeloadadd
21150 * Fires after a new set of Records has been loaded.
21151 * @param {Store} this
21152 * @param {Roo.data.Record[]} records The Records that were loaded
21153 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21155 beforeloadadd : true,
21158 * Fires after a new set of Records has been loaded, before they are added to the store.
21159 * @param {Store} this
21160 * @param {Roo.data.Record[]} records The Records that were loaded
21161 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21162 * @params {Object} return from reader
21166 * @event loadexception
21167 * Fires if an exception occurs in the Proxy during loading.
21168 * Called with the signature of the Proxy's "loadexception" event.
21169 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21172 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21173 * @param {Object} load options
21174 * @param {Object} jsonData from your request (normally this contains the Exception)
21176 loadexception : true
21180 this.proxy = Roo.factory(this.proxy, Roo.data);
21181 this.proxy.xmodule = this.xmodule || false;
21182 this.relayEvents(this.proxy, ["loadexception"]);
21184 this.sortToggle = {};
21185 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21187 Roo.data.Store.superclass.constructor.call(this);
21189 if(this.inlineData){
21190 this.loadData(this.inlineData);
21191 delete this.inlineData;
21195 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21197 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21198 * without a remote query - used by combo/forms at present.
21202 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21205 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21208 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21209 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21212 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21213 * on any HTTP request
21216 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21219 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21223 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21224 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21226 remoteSort : false,
21229 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21230 * loaded or when a record is removed. (defaults to false).
21232 pruneModifiedRecords : false,
21235 lastOptions : null,
21238 * Add Records to the Store and fires the add event.
21239 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21241 add : function(records){
21242 records = [].concat(records);
21243 for(var i = 0, len = records.length; i < len; i++){
21244 records[i].join(this);
21246 var index = this.data.length;
21247 this.data.addAll(records);
21248 this.fireEvent("add", this, records, index);
21252 * Remove a Record from the Store and fires the remove event.
21253 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21255 remove : function(record){
21256 var index = this.data.indexOf(record);
21257 this.data.removeAt(index);
21258 if(this.pruneModifiedRecords){
21259 this.modified.remove(record);
21261 this.fireEvent("remove", this, record, index);
21265 * Remove all Records from the Store and fires the clear event.
21267 removeAll : function(){
21269 if(this.pruneModifiedRecords){
21270 this.modified = [];
21272 this.fireEvent("clear", this);
21276 * Inserts Records to the Store at the given index and fires the add event.
21277 * @param {Number} index The start index at which to insert the passed Records.
21278 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21280 insert : function(index, records){
21281 records = [].concat(records);
21282 for(var i = 0, len = records.length; i < len; i++){
21283 this.data.insert(index, records[i]);
21284 records[i].join(this);
21286 this.fireEvent("add", this, records, index);
21290 * Get the index within the cache of the passed Record.
21291 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21292 * @return {Number} The index of the passed Record. Returns -1 if not found.
21294 indexOf : function(record){
21295 return this.data.indexOf(record);
21299 * Get the index within the cache of the Record with the passed id.
21300 * @param {String} id The id of the Record to find.
21301 * @return {Number} The index of the Record. Returns -1 if not found.
21303 indexOfId : function(id){
21304 return this.data.indexOfKey(id);
21308 * Get the Record with the specified id.
21309 * @param {String} id The id of the Record to find.
21310 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21312 getById : function(id){
21313 return this.data.key(id);
21317 * Get the Record at the specified index.
21318 * @param {Number} index The index of the Record to find.
21319 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21321 getAt : function(index){
21322 return this.data.itemAt(index);
21326 * Returns a range of Records between specified indices.
21327 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21328 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21329 * @return {Roo.data.Record[]} An array of Records
21331 getRange : function(start, end){
21332 return this.data.getRange(start, end);
21336 storeOptions : function(o){
21337 o = Roo.apply({}, o);
21340 this.lastOptions = o;
21344 * Loads the Record cache from the configured Proxy using the configured Reader.
21346 * If using remote paging, then the first load call must specify the <em>start</em>
21347 * and <em>limit</em> properties in the options.params property to establish the initial
21348 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21350 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21351 * and this call will return before the new data has been loaded. Perform any post-processing
21352 * in a callback function, or in a "load" event handler.</strong>
21354 * @param {Object} options An object containing properties which control loading options:<ul>
21355 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21356 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21357 * passed the following arguments:<ul>
21358 * <li>r : Roo.data.Record[]</li>
21359 * <li>options: Options object from the load call</li>
21360 * <li>success: Boolean success indicator</li></ul></li>
21361 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21362 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21365 load : function(options){
21366 options = options || {};
21367 if(this.fireEvent("beforeload", this, options) !== false){
21368 this.storeOptions(options);
21369 var p = Roo.apply(options.params || {}, this.baseParams);
21370 // if meta was not loaded from remote source.. try requesting it.
21371 if (!this.reader.metaFromRemote) {
21372 p._requestMeta = 1;
21374 if(this.sortInfo && this.remoteSort){
21375 var pn = this.paramNames;
21376 p[pn["sort"]] = this.sortInfo.field;
21377 p[pn["dir"]] = this.sortInfo.direction;
21379 if (this.multiSort) {
21380 var pn = this.paramNames;
21381 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21384 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21389 * Reloads the Record cache from the configured Proxy using the configured Reader and
21390 * the options from the last load operation performed.
21391 * @param {Object} options (optional) An object containing properties which may override the options
21392 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21393 * the most recently used options are reused).
21395 reload : function(options){
21396 this.load(Roo.applyIf(options||{}, this.lastOptions));
21400 // Called as a callback by the Reader during a load operation.
21401 loadRecords : function(o, options, success){
21402 if(!o || success === false){
21403 if(success !== false){
21404 this.fireEvent("load", this, [], options, o);
21406 if(options.callback){
21407 options.callback.call(options.scope || this, [], options, false);
21411 // if data returned failure - throw an exception.
21412 if (o.success === false) {
21413 // show a message if no listener is registered.
21414 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21415 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21417 // loadmask wil be hooked into this..
21418 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21421 var r = o.records, t = o.totalRecords || r.length;
21423 this.fireEvent("beforeloadadd", this, r, options, o);
21425 if(!options || options.add !== true){
21426 if(this.pruneModifiedRecords){
21427 this.modified = [];
21429 for(var i = 0, len = r.length; i < len; i++){
21433 this.data = this.snapshot;
21434 delete this.snapshot;
21437 this.data.addAll(r);
21438 this.totalLength = t;
21440 this.fireEvent("datachanged", this);
21442 this.totalLength = Math.max(t, this.data.length+r.length);
21445 this.fireEvent("load", this, r, options, o);
21446 if(options.callback){
21447 options.callback.call(options.scope || this, r, options, true);
21453 * Loads data from a passed data block. A Reader which understands the format of the data
21454 * must have been configured in the constructor.
21455 * @param {Object} data The data block from which to read the Records. The format of the data expected
21456 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21457 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21459 loadData : function(o, append){
21460 var r = this.reader.readRecords(o);
21461 this.loadRecords(r, {add: append}, true);
21465 * Gets the number of cached records.
21467 * <em>If using paging, this may not be the total size of the dataset. If the data object
21468 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21469 * the data set size</em>
21471 getCount : function(){
21472 return this.data.length || 0;
21476 * Gets the total number of records in the dataset as returned by the server.
21478 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21479 * the dataset size</em>
21481 getTotalCount : function(){
21482 return this.totalLength || 0;
21486 * Returns the sort state of the Store as an object with two properties:
21488 field {String} The name of the field by which the Records are sorted
21489 direction {String} The sort order, "ASC" or "DESC"
21492 getSortState : function(){
21493 return this.sortInfo;
21497 applySort : function(){
21498 if(this.sortInfo && !this.remoteSort){
21499 var s = this.sortInfo, f = s.field;
21500 var st = this.fields.get(f).sortType;
21501 var fn = function(r1, r2){
21502 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21503 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21505 this.data.sort(s.direction, fn);
21506 if(this.snapshot && this.snapshot != this.data){
21507 this.snapshot.sort(s.direction, fn);
21513 * Sets the default sort column and order to be used by the next load operation.
21514 * @param {String} fieldName The name of the field to sort by.
21515 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21517 setDefaultSort : function(field, dir){
21518 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21522 * Sort the Records.
21523 * If remote sorting is used, the sort is performed on the server, and the cache is
21524 * reloaded. If local sorting is used, the cache is sorted internally.
21525 * @param {String} fieldName The name of the field to sort by.
21526 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21528 sort : function(fieldName, dir){
21529 var f = this.fields.get(fieldName);
21531 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21533 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21534 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21539 this.sortToggle[f.name] = dir;
21540 this.sortInfo = {field: f.name, direction: dir};
21541 if(!this.remoteSort){
21543 this.fireEvent("datachanged", this);
21545 this.load(this.lastOptions);
21550 * Calls the specified function for each of the Records in the cache.
21551 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21552 * Returning <em>false</em> aborts and exits the iteration.
21553 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21555 each : function(fn, scope){
21556 this.data.each(fn, scope);
21560 * Gets all records modified since the last commit. Modified records are persisted across load operations
21561 * (e.g., during paging).
21562 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21564 getModifiedRecords : function(){
21565 return this.modified;
21569 createFilterFn : function(property, value, anyMatch){
21570 if(!value.exec){ // not a regex
21571 value = String(value);
21572 if(value.length == 0){
21575 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21577 return function(r){
21578 return value.test(r.data[property]);
21583 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21584 * @param {String} property A field on your records
21585 * @param {Number} start The record index to start at (defaults to 0)
21586 * @param {Number} end The last record index to include (defaults to length - 1)
21587 * @return {Number} The sum
21589 sum : function(property, start, end){
21590 var rs = this.data.items, v = 0;
21591 start = start || 0;
21592 end = (end || end === 0) ? end : rs.length-1;
21594 for(var i = start; i <= end; i++){
21595 v += (rs[i].data[property] || 0);
21601 * Filter the records by a specified property.
21602 * @param {String} field A field on your records
21603 * @param {String/RegExp} value Either a string that the field
21604 * should start with or a RegExp to test against the field
21605 * @param {Boolean} anyMatch True to match any part not just the beginning
21607 filter : function(property, value, anyMatch){
21608 var fn = this.createFilterFn(property, value, anyMatch);
21609 return fn ? this.filterBy(fn) : this.clearFilter();
21613 * Filter by a function. The specified function will be called with each
21614 * record in this data source. If the function returns true the record is included,
21615 * otherwise it is filtered.
21616 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21617 * @param {Object} scope (optional) The scope of the function (defaults to this)
21619 filterBy : function(fn, scope){
21620 this.snapshot = this.snapshot || this.data;
21621 this.data = this.queryBy(fn, scope||this);
21622 this.fireEvent("datachanged", this);
21626 * Query the records by a specified property.
21627 * @param {String} field A field on your records
21628 * @param {String/RegExp} value Either a string that the field
21629 * should start with or a RegExp to test against the field
21630 * @param {Boolean} anyMatch True to match any part not just the beginning
21631 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21633 query : function(property, value, anyMatch){
21634 var fn = this.createFilterFn(property, value, anyMatch);
21635 return fn ? this.queryBy(fn) : this.data.clone();
21639 * Query by a function. The specified function will be called with each
21640 * record in this data source. If the function returns true the record is included
21642 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21643 * @param {Object} scope (optional) The scope of the function (defaults to this)
21644 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21646 queryBy : function(fn, scope){
21647 var data = this.snapshot || this.data;
21648 return data.filterBy(fn, scope||this);
21652 * Collects unique values for a particular dataIndex from this store.
21653 * @param {String} dataIndex The property to collect
21654 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21655 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21656 * @return {Array} An array of the unique values
21658 collect : function(dataIndex, allowNull, bypassFilter){
21659 var d = (bypassFilter === true && this.snapshot) ?
21660 this.snapshot.items : this.data.items;
21661 var v, sv, r = [], l = {};
21662 for(var i = 0, len = d.length; i < len; i++){
21663 v = d[i].data[dataIndex];
21665 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21674 * Revert to a view of the Record cache with no filtering applied.
21675 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21677 clearFilter : function(suppressEvent){
21678 if(this.snapshot && this.snapshot != this.data){
21679 this.data = this.snapshot;
21680 delete this.snapshot;
21681 if(suppressEvent !== true){
21682 this.fireEvent("datachanged", this);
21688 afterEdit : function(record){
21689 if(this.modified.indexOf(record) == -1){
21690 this.modified.push(record);
21692 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21696 afterReject : function(record){
21697 this.modified.remove(record);
21698 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21702 afterCommit : function(record){
21703 this.modified.remove(record);
21704 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21708 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21709 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21711 commitChanges : function(){
21712 var m = this.modified.slice(0);
21713 this.modified = [];
21714 for(var i = 0, len = m.length; i < len; i++){
21720 * Cancel outstanding changes on all changed records.
21722 rejectChanges : function(){
21723 var m = this.modified.slice(0);
21724 this.modified = [];
21725 for(var i = 0, len = m.length; i < len; i++){
21730 onMetaChange : function(meta, rtype, o){
21731 this.recordType = rtype;
21732 this.fields = rtype.prototype.fields;
21733 delete this.snapshot;
21734 this.sortInfo = meta.sortInfo || this.sortInfo;
21735 this.modified = [];
21736 this.fireEvent('metachange', this, this.reader.meta);
21740 * Ext JS Library 1.1.1
21741 * Copyright(c) 2006-2007, Ext JS, LLC.
21743 * Originally Released Under LGPL - original licence link has changed is not relivant.
21746 * <script type="text/javascript">
21750 * @class Roo.data.SimpleStore
21751 * @extends Roo.data.Store
21752 * Small helper class to make creating Stores from Array data easier.
21753 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21754 * @cfg {Array} fields An array of field definition objects, or field name strings.
21755 * @cfg {Array} data The multi-dimensional array of data
21757 * @param {Object} config
21759 Roo.data.SimpleStore = function(config){
21760 Roo.data.SimpleStore.superclass.constructor.call(this, {
21762 reader: new Roo.data.ArrayReader({
21765 Roo.data.Record.create(config.fields)
21767 proxy : new Roo.data.MemoryProxy(config.data)
21771 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21773 * Ext JS Library 1.1.1
21774 * Copyright(c) 2006-2007, Ext JS, LLC.
21776 * Originally Released Under LGPL - original licence link has changed is not relivant.
21779 * <script type="text/javascript">
21784 * @extends Roo.data.Store
21785 * @class Roo.data.JsonStore
21786 * Small helper class to make creating Stores for JSON data easier. <br/>
21788 var store = new Roo.data.JsonStore({
21789 url: 'get-images.php',
21791 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21794 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21795 * JsonReader and HttpProxy (unless inline data is provided).</b>
21796 * @cfg {Array} fields An array of field definition objects, or field name strings.
21798 * @param {Object} config
21800 Roo.data.JsonStore = function(c){
21801 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21802 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21803 reader: new Roo.data.JsonReader(c, c.fields)
21806 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21808 * Ext JS Library 1.1.1
21809 * Copyright(c) 2006-2007, Ext JS, LLC.
21811 * Originally Released Under LGPL - original licence link has changed is not relivant.
21814 * <script type="text/javascript">
21818 Roo.data.Field = function(config){
21819 if(typeof config == "string"){
21820 config = {name: config};
21822 Roo.apply(this, config);
21825 this.type = "auto";
21828 var st = Roo.data.SortTypes;
21829 // named sortTypes are supported, here we look them up
21830 if(typeof this.sortType == "string"){
21831 this.sortType = st[this.sortType];
21834 // set default sortType for strings and dates
21835 if(!this.sortType){
21838 this.sortType = st.asUCString;
21841 this.sortType = st.asDate;
21844 this.sortType = st.none;
21849 var stripRe = /[\$,%]/g;
21851 // prebuilt conversion function for this field, instead of
21852 // switching every time we're reading a value
21854 var cv, dateFormat = this.dateFormat;
21859 cv = function(v){ return v; };
21862 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21866 return v !== undefined && v !== null && v !== '' ?
21867 parseInt(String(v).replace(stripRe, ""), 10) : '';
21872 return v !== undefined && v !== null && v !== '' ?
21873 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21878 cv = function(v){ return v === true || v === "true" || v == 1; };
21885 if(v instanceof Date){
21889 if(dateFormat == "timestamp"){
21890 return new Date(v*1000);
21892 return Date.parseDate(v, dateFormat);
21894 var parsed = Date.parse(v);
21895 return parsed ? new Date(parsed) : null;
21904 Roo.data.Field.prototype = {
21912 * Ext JS Library 1.1.1
21913 * Copyright(c) 2006-2007, Ext JS, LLC.
21915 * Originally Released Under LGPL - original licence link has changed is not relivant.
21918 * <script type="text/javascript">
21921 // Base class for reading structured data from a data source. This class is intended to be
21922 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21925 * @class Roo.data.DataReader
21926 * Base class for reading structured data from a data source. This class is intended to be
21927 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21930 Roo.data.DataReader = function(meta, recordType){
21934 this.recordType = recordType instanceof Array ?
21935 Roo.data.Record.create(recordType) : recordType;
21938 Roo.data.DataReader.prototype = {
21940 * Create an empty record
21941 * @param {Object} data (optional) - overlay some values
21942 * @return {Roo.data.Record} record created.
21944 newRow : function(d) {
21946 this.recordType.prototype.fields.each(function(c) {
21948 case 'int' : da[c.name] = 0; break;
21949 case 'date' : da[c.name] = new Date(); break;
21950 case 'float' : da[c.name] = 0.0; break;
21951 case 'boolean' : da[c.name] = false; break;
21952 default : da[c.name] = ""; break;
21956 return new this.recordType(Roo.apply(da, d));
21961 * Ext JS Library 1.1.1
21962 * Copyright(c) 2006-2007, Ext JS, LLC.
21964 * Originally Released Under LGPL - original licence link has changed is not relivant.
21967 * <script type="text/javascript">
21971 * @class Roo.data.DataProxy
21972 * @extends Roo.data.Observable
21973 * This class is an abstract base class for implementations which provide retrieval of
21974 * unformatted data objects.<br>
21976 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
21977 * (of the appropriate type which knows how to parse the data object) to provide a block of
21978 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
21980 * Custom implementations must implement the load method as described in
21981 * {@link Roo.data.HttpProxy#load}.
21983 Roo.data.DataProxy = function(){
21986 * @event beforeload
21987 * Fires before a network request is made to retrieve a data object.
21988 * @param {Object} This DataProxy object.
21989 * @param {Object} params The params parameter to the load function.
21994 * Fires before the load method's callback is called.
21995 * @param {Object} This DataProxy object.
21996 * @param {Object} o The data object.
21997 * @param {Object} arg The callback argument object passed to the load function.
22001 * @event loadexception
22002 * Fires if an Exception occurs during data retrieval.
22003 * @param {Object} This DataProxy object.
22004 * @param {Object} o The data object.
22005 * @param {Object} arg The callback argument object passed to the load function.
22006 * @param {Object} e The Exception.
22008 loadexception : true
22010 Roo.data.DataProxy.superclass.constructor.call(this);
22013 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22016 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22020 * Ext JS Library 1.1.1
22021 * Copyright(c) 2006-2007, Ext JS, LLC.
22023 * Originally Released Under LGPL - original licence link has changed is not relivant.
22026 * <script type="text/javascript">
22029 * @class Roo.data.MemoryProxy
22030 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22031 * to the Reader when its load method is called.
22033 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22035 Roo.data.MemoryProxy = function(data){
22039 Roo.data.MemoryProxy.superclass.constructor.call(this);
22043 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22045 * Load data from the requested source (in this case an in-memory
22046 * data object passed to the constructor), read the data object into
22047 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22048 * process that block using the passed callback.
22049 * @param {Object} params This parameter is not used by the MemoryProxy class.
22050 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22051 * object into a block of Roo.data.Records.
22052 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22053 * The function must be passed <ul>
22054 * <li>The Record block object</li>
22055 * <li>The "arg" argument from the load function</li>
22056 * <li>A boolean success indicator</li>
22058 * @param {Object} scope The scope in which to call the callback
22059 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22061 load : function(params, reader, callback, scope, arg){
22062 params = params || {};
22065 result = reader.readRecords(this.data);
22067 this.fireEvent("loadexception", this, arg, null, e);
22068 callback.call(scope, null, arg, false);
22071 callback.call(scope, result, arg, true);
22075 update : function(params, records){
22080 * Ext JS Library 1.1.1
22081 * Copyright(c) 2006-2007, Ext JS, LLC.
22083 * Originally Released Under LGPL - original licence link has changed is not relivant.
22086 * <script type="text/javascript">
22089 * @class Roo.data.HttpProxy
22090 * @extends Roo.data.DataProxy
22091 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22092 * configured to reference a certain URL.<br><br>
22094 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22095 * from which the running page was served.<br><br>
22097 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22099 * Be aware that to enable the browser to parse an XML document, the server must set
22100 * the Content-Type header in the HTTP response to "text/xml".
22102 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22103 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22104 * will be used to make the request.
22106 Roo.data.HttpProxy = function(conn){
22107 Roo.data.HttpProxy.superclass.constructor.call(this);
22108 // is conn a conn config or a real conn?
22110 this.useAjax = !conn || !conn.events;
22114 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22115 // thse are take from connection...
22118 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22121 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22122 * extra parameters to each request made by this object. (defaults to undefined)
22125 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22126 * to each request made by this object. (defaults to undefined)
22129 * @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)
22132 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22135 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22141 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22145 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22146 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22147 * a finer-grained basis than the DataProxy events.
22149 getConnection : function(){
22150 return this.useAjax ? Roo.Ajax : this.conn;
22154 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22155 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22156 * process that block using the passed callback.
22157 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22158 * for the request to the remote server.
22159 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22160 * object into a block of Roo.data.Records.
22161 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22162 * The function must be passed <ul>
22163 * <li>The Record block object</li>
22164 * <li>The "arg" argument from the load function</li>
22165 * <li>A boolean success indicator</li>
22167 * @param {Object} scope The scope in which to call the callback
22168 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22170 load : function(params, reader, callback, scope, arg){
22171 if(this.fireEvent("beforeload", this, params) !== false){
22173 params : params || {},
22175 callback : callback,
22180 callback : this.loadResponse,
22184 Roo.applyIf(o, this.conn);
22185 if(this.activeRequest){
22186 Roo.Ajax.abort(this.activeRequest);
22188 this.activeRequest = Roo.Ajax.request(o);
22190 this.conn.request(o);
22193 callback.call(scope||this, null, arg, false);
22198 loadResponse : function(o, success, response){
22199 delete this.activeRequest;
22201 this.fireEvent("loadexception", this, o, response);
22202 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22207 result = o.reader.read(response);
22209 this.fireEvent("loadexception", this, o, response, e);
22210 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22214 this.fireEvent("load", this, o, o.request.arg);
22215 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22219 update : function(dataSet){
22224 updateResponse : function(dataSet){
22229 * Ext JS Library 1.1.1
22230 * Copyright(c) 2006-2007, Ext JS, LLC.
22232 * Originally Released Under LGPL - original licence link has changed is not relivant.
22235 * <script type="text/javascript">
22239 * @class Roo.data.ScriptTagProxy
22240 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22241 * other than the originating domain of the running page.<br><br>
22243 * <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
22244 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22246 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22247 * source code that is used as the source inside a <script> tag.<br><br>
22249 * In order for the browser to process the returned data, the server must wrap the data object
22250 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22251 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22252 * depending on whether the callback name was passed:
22255 boolean scriptTag = false;
22256 String cb = request.getParameter("callback");
22259 response.setContentType("text/javascript");
22261 response.setContentType("application/x-json");
22263 Writer out = response.getWriter();
22265 out.write(cb + "(");
22267 out.print(dataBlock.toJsonString());
22274 * @param {Object} config A configuration object.
22276 Roo.data.ScriptTagProxy = function(config){
22277 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22278 Roo.apply(this, config);
22279 this.head = document.getElementsByTagName("head")[0];
22282 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22284 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22286 * @cfg {String} url The URL from which to request the data object.
22289 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22293 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22294 * the server the name of the callback function set up by the load call to process the returned data object.
22295 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22296 * javascript output which calls this named function passing the data object as its only parameter.
22298 callbackParam : "callback",
22300 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22301 * name to the request.
22306 * Load data from the configured URL, read the data object into
22307 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22308 * process that block using the passed callback.
22309 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22310 * for the request to the remote server.
22311 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22312 * object into a block of Roo.data.Records.
22313 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22314 * The function must be passed <ul>
22315 * <li>The Record block object</li>
22316 * <li>The "arg" argument from the load function</li>
22317 * <li>A boolean success indicator</li>
22319 * @param {Object} scope The scope in which to call the callback
22320 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22322 load : function(params, reader, callback, scope, arg){
22323 if(this.fireEvent("beforeload", this, params) !== false){
22325 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22327 var url = this.url;
22328 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22330 url += "&_dc=" + (new Date().getTime());
22332 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22335 cb : "stcCallback"+transId,
22336 scriptId : "stcScript"+transId,
22340 callback : callback,
22346 window[trans.cb] = function(o){
22347 conn.handleResponse(o, trans);
22350 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22352 if(this.autoAbort !== false){
22356 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22358 var script = document.createElement("script");
22359 script.setAttribute("src", url);
22360 script.setAttribute("type", "text/javascript");
22361 script.setAttribute("id", trans.scriptId);
22362 this.head.appendChild(script);
22364 this.trans = trans;
22366 callback.call(scope||this, null, arg, false);
22371 isLoading : function(){
22372 return this.trans ? true : false;
22376 * Abort the current server request.
22378 abort : function(){
22379 if(this.isLoading()){
22380 this.destroyTrans(this.trans);
22385 destroyTrans : function(trans, isLoaded){
22386 this.head.removeChild(document.getElementById(trans.scriptId));
22387 clearTimeout(trans.timeoutId);
22389 window[trans.cb] = undefined;
22391 delete window[trans.cb];
22394 // if hasn't been loaded, wait for load to remove it to prevent script error
22395 window[trans.cb] = function(){
22396 window[trans.cb] = undefined;
22398 delete window[trans.cb];
22405 handleResponse : function(o, trans){
22406 this.trans = false;
22407 this.destroyTrans(trans, true);
22410 result = trans.reader.readRecords(o);
22412 this.fireEvent("loadexception", this, o, trans.arg, e);
22413 trans.callback.call(trans.scope||window, null, trans.arg, false);
22416 this.fireEvent("load", this, o, trans.arg);
22417 trans.callback.call(trans.scope||window, result, trans.arg, true);
22421 handleFailure : function(trans){
22422 this.trans = false;
22423 this.destroyTrans(trans, false);
22424 this.fireEvent("loadexception", this, null, trans.arg);
22425 trans.callback.call(trans.scope||window, null, trans.arg, false);
22429 * Ext JS Library 1.1.1
22430 * Copyright(c) 2006-2007, Ext JS, LLC.
22432 * Originally Released Under LGPL - original licence link has changed is not relivant.
22435 * <script type="text/javascript">
22439 * @class Roo.data.JsonReader
22440 * @extends Roo.data.DataReader
22441 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22442 * based on mappings in a provided Roo.data.Record constructor.
22444 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22445 * in the reply previously.
22450 var RecordDef = Roo.data.Record.create([
22451 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22452 {name: 'occupation'} // This field will use "occupation" as the mapping.
22454 var myReader = new Roo.data.JsonReader({
22455 totalProperty: "results", // The property which contains the total dataset size (optional)
22456 root: "rows", // The property which contains an Array of row objects
22457 id: "id" // The property within each row object that provides an ID for the record (optional)
22461 * This would consume a JSON file like this:
22463 { 'results': 2, 'rows': [
22464 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22465 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22468 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22469 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22470 * paged from the remote server.
22471 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22472 * @cfg {String} root name of the property which contains the Array of row objects.
22473 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22475 * Create a new JsonReader
22476 * @param {Object} meta Metadata configuration options
22477 * @param {Object} recordType Either an Array of field definition objects,
22478 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22480 Roo.data.JsonReader = function(meta, recordType){
22483 // set some defaults:
22484 Roo.applyIf(meta, {
22485 totalProperty: 'total',
22486 successProperty : 'success',
22491 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22493 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22496 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22497 * Used by Store query builder to append _requestMeta to params.
22500 metaFromRemote : false,
22502 * This method is only used by a DataProxy which has retrieved data from a remote server.
22503 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22504 * @return {Object} data A data block which is used by an Roo.data.Store object as
22505 * a cache of Roo.data.Records.
22507 read : function(response){
22508 var json = response.responseText;
22510 var o = /* eval:var:o */ eval("("+json+")");
22512 throw {message: "JsonReader.read: Json object not found"};
22518 this.metaFromRemote = true;
22519 this.meta = o.metaData;
22520 this.recordType = Roo.data.Record.create(o.metaData.fields);
22521 this.onMetaChange(this.meta, this.recordType, o);
22523 return this.readRecords(o);
22526 // private function a store will implement
22527 onMetaChange : function(meta, recordType, o){
22534 simpleAccess: function(obj, subsc) {
22541 getJsonAccessor: function(){
22543 return function(expr) {
22545 return(re.test(expr))
22546 ? new Function("obj", "return obj." + expr)
22551 return Roo.emptyFn;
22556 * Create a data block containing Roo.data.Records from an XML document.
22557 * @param {Object} o An object which contains an Array of row objects in the property specified
22558 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22559 * which contains the total size of the dataset.
22560 * @return {Object} data A data block which is used by an Roo.data.Store object as
22561 * a cache of Roo.data.Records.
22563 readRecords : function(o){
22565 * After any data loads, the raw JSON data is available for further custom processing.
22569 var s = this.meta, Record = this.recordType,
22570 f = Record.prototype.fields, fi = f.items, fl = f.length;
22572 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22574 if(s.totalProperty) {
22575 this.getTotal = this.getJsonAccessor(s.totalProperty);
22577 if(s.successProperty) {
22578 this.getSuccess = this.getJsonAccessor(s.successProperty);
22580 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22582 var g = this.getJsonAccessor(s.id);
22583 this.getId = function(rec) {
22585 return (r === undefined || r === "") ? null : r;
22588 this.getId = function(){return null;};
22591 for(var jj = 0; jj < fl; jj++){
22593 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22594 this.ef[jj] = this.getJsonAccessor(map);
22598 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22599 if(s.totalProperty){
22600 var vt = parseInt(this.getTotal(o), 10);
22605 if(s.successProperty){
22606 var vs = this.getSuccess(o);
22607 if(vs === false || vs === 'false'){
22612 for(var i = 0; i < c; i++){
22615 var id = this.getId(n);
22616 for(var j = 0; j < fl; j++){
22618 var v = this.ef[j](n);
22620 Roo.log('missing convert for ' + f.name);
22624 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22626 var record = new Record(values, id);
22628 records[i] = record;
22634 totalRecords : totalRecords
22639 * Ext JS Library 1.1.1
22640 * Copyright(c) 2006-2007, Ext JS, LLC.
22642 * Originally Released Under LGPL - original licence link has changed is not relivant.
22645 * <script type="text/javascript">
22649 * @class Roo.data.XmlReader
22650 * @extends Roo.data.DataReader
22651 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22652 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22654 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22655 * header in the HTTP response must be set to "text/xml".</em>
22659 var RecordDef = Roo.data.Record.create([
22660 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22661 {name: 'occupation'} // This field will use "occupation" as the mapping.
22663 var myReader = new Roo.data.XmlReader({
22664 totalRecords: "results", // The element which contains the total dataset size (optional)
22665 record: "row", // The repeated element which contains row information
22666 id: "id" // The element within the row that provides an ID for the record (optional)
22670 * This would consume an XML file like this:
22674 <results>2</results>
22677 <name>Bill</name>
22678 <occupation>Gardener</occupation>
22682 <name>Ben</name>
22683 <occupation>Horticulturalist</occupation>
22687 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22688 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22689 * paged from the remote server.
22690 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22691 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22692 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22693 * a record identifier value.
22695 * Create a new XmlReader
22696 * @param {Object} meta Metadata configuration options
22697 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22698 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22699 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22701 Roo.data.XmlReader = function(meta, recordType){
22703 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22705 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22707 * This method is only used by a DataProxy which has retrieved data from a remote server.
22708 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22709 * to contain a method called 'responseXML' that returns an XML document object.
22710 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22711 * a cache of Roo.data.Records.
22713 read : function(response){
22714 var doc = response.responseXML;
22716 throw {message: "XmlReader.read: XML Document not available"};
22718 return this.readRecords(doc);
22722 * Create a data block containing Roo.data.Records from an XML document.
22723 * @param {Object} doc A parsed XML document.
22724 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22725 * a cache of Roo.data.Records.
22727 readRecords : function(doc){
22729 * After any data loads/reads, the raw XML Document is available for further custom processing.
22730 * @type XMLDocument
22732 this.xmlData = doc;
22733 var root = doc.documentElement || doc;
22734 var q = Roo.DomQuery;
22735 var recordType = this.recordType, fields = recordType.prototype.fields;
22736 var sid = this.meta.id;
22737 var totalRecords = 0, success = true;
22738 if(this.meta.totalRecords){
22739 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22742 if(this.meta.success){
22743 var sv = q.selectValue(this.meta.success, root, true);
22744 success = sv !== false && sv !== 'false';
22747 var ns = q.select(this.meta.record, root);
22748 for(var i = 0, len = ns.length; i < len; i++) {
22751 var id = sid ? q.selectValue(sid, n) : undefined;
22752 for(var j = 0, jlen = fields.length; j < jlen; j++){
22753 var f = fields.items[j];
22754 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22756 values[f.name] = v;
22758 var record = new recordType(values, id);
22760 records[records.length] = record;
22766 totalRecords : totalRecords || records.length
22771 * Ext JS Library 1.1.1
22772 * Copyright(c) 2006-2007, Ext JS, LLC.
22774 * Originally Released Under LGPL - original licence link has changed is not relivant.
22777 * <script type="text/javascript">
22781 * @class Roo.data.ArrayReader
22782 * @extends Roo.data.DataReader
22783 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22784 * Each element of that Array represents a row of data fields. The
22785 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22786 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22790 var RecordDef = Roo.data.Record.create([
22791 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22792 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22794 var myReader = new Roo.data.ArrayReader({
22795 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22799 * This would consume an Array like this:
22801 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22803 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22805 * Create a new JsonReader
22806 * @param {Object} meta Metadata configuration options.
22807 * @param {Object} recordType Either an Array of field definition objects
22808 * as specified to {@link Roo.data.Record#create},
22809 * or an {@link Roo.data.Record} object
22810 * created using {@link Roo.data.Record#create}.
22812 Roo.data.ArrayReader = function(meta, recordType){
22813 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22816 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22818 * Create a data block containing Roo.data.Records from an XML document.
22819 * @param {Object} o An Array of row objects which represents the dataset.
22820 * @return {Object} data A data block which is used by an Roo.data.Store object as
22821 * a cache of Roo.data.Records.
22823 readRecords : function(o){
22824 var sid = this.meta ? this.meta.id : null;
22825 var recordType = this.recordType, fields = recordType.prototype.fields;
22828 for(var i = 0; i < root.length; i++){
22831 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22832 for(var j = 0, jlen = fields.length; j < jlen; j++){
22833 var f = fields.items[j];
22834 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22835 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22837 values[f.name] = v;
22839 var record = new recordType(values, id);
22841 records[records.length] = record;
22845 totalRecords : records.length
22850 * Ext JS Library 1.1.1
22851 * Copyright(c) 2006-2007, Ext JS, LLC.
22853 * Originally Released Under LGPL - original licence link has changed is not relivant.
22856 * <script type="text/javascript">
22861 * @class Roo.data.Tree
22862 * @extends Roo.util.Observable
22863 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22864 * in the tree have most standard DOM functionality.
22866 * @param {Node} root (optional) The root node
22868 Roo.data.Tree = function(root){
22869 this.nodeHash = {};
22871 * The root node for this tree
22876 this.setRootNode(root);
22881 * Fires when a new child node is appended to a node in this tree.
22882 * @param {Tree} tree The owner tree
22883 * @param {Node} parent The parent node
22884 * @param {Node} node The newly appended node
22885 * @param {Number} index The index of the newly appended node
22890 * Fires when a child node is removed from a node in this tree.
22891 * @param {Tree} tree The owner tree
22892 * @param {Node} parent The parent node
22893 * @param {Node} node The child node removed
22898 * Fires when a node is moved to a new location in the tree
22899 * @param {Tree} tree The owner tree
22900 * @param {Node} node The node moved
22901 * @param {Node} oldParent The old parent of this node
22902 * @param {Node} newParent The new parent of this node
22903 * @param {Number} index The index it was moved to
22908 * Fires when a new child node is inserted in a node in this tree.
22909 * @param {Tree} tree The owner tree
22910 * @param {Node} parent The parent node
22911 * @param {Node} node The child node inserted
22912 * @param {Node} refNode The child node the node was inserted before
22916 * @event beforeappend
22917 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22918 * @param {Tree} tree The owner tree
22919 * @param {Node} parent The parent node
22920 * @param {Node} node The child node to be appended
22922 "beforeappend" : true,
22924 * @event beforeremove
22925 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22926 * @param {Tree} tree The owner tree
22927 * @param {Node} parent The parent node
22928 * @param {Node} node The child node to be removed
22930 "beforeremove" : true,
22932 * @event beforemove
22933 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22934 * @param {Tree} tree The owner tree
22935 * @param {Node} node The node being moved
22936 * @param {Node} oldParent The parent of the node
22937 * @param {Node} newParent The new parent the node is moving to
22938 * @param {Number} index The index it is being moved to
22940 "beforemove" : true,
22942 * @event beforeinsert
22943 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22944 * @param {Tree} tree The owner tree
22945 * @param {Node} parent The parent node
22946 * @param {Node} node The child node to be inserted
22947 * @param {Node} refNode The child node the node is being inserted before
22949 "beforeinsert" : true
22952 Roo.data.Tree.superclass.constructor.call(this);
22955 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22956 pathSeparator: "/",
22958 proxyNodeEvent : function(){
22959 return this.fireEvent.apply(this, arguments);
22963 * Returns the root node for this tree.
22966 getRootNode : function(){
22971 * Sets the root node for this tree.
22972 * @param {Node} node
22975 setRootNode : function(node){
22977 node.ownerTree = this;
22978 node.isRoot = true;
22979 this.registerNode(node);
22984 * Gets a node in this tree by its id.
22985 * @param {String} id
22988 getNodeById : function(id){
22989 return this.nodeHash[id];
22992 registerNode : function(node){
22993 this.nodeHash[node.id] = node;
22996 unregisterNode : function(node){
22997 delete this.nodeHash[node.id];
23000 toString : function(){
23001 return "[Tree"+(this.id?" "+this.id:"")+"]";
23006 * @class Roo.data.Node
23007 * @extends Roo.util.Observable
23008 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23009 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23011 * @param {Object} attributes The attributes/config for the node
23013 Roo.data.Node = function(attributes){
23015 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23018 this.attributes = attributes || {};
23019 this.leaf = this.attributes.leaf;
23021 * The node id. @type String
23023 this.id = this.attributes.id;
23025 this.id = Roo.id(null, "ynode-");
23026 this.attributes.id = this.id;
23031 * All child nodes of this node. @type Array
23033 this.childNodes = [];
23034 if(!this.childNodes.indexOf){ // indexOf is a must
23035 this.childNodes.indexOf = function(o){
23036 for(var i = 0, len = this.length; i < len; i++){
23045 * The parent node for this node. @type Node
23047 this.parentNode = null;
23049 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23051 this.firstChild = null;
23053 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23055 this.lastChild = null;
23057 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23059 this.previousSibling = null;
23061 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23063 this.nextSibling = null;
23068 * Fires when a new child node is appended
23069 * @param {Tree} tree The owner tree
23070 * @param {Node} this This node
23071 * @param {Node} node The newly appended node
23072 * @param {Number} index The index of the newly appended node
23077 * Fires when a child node is removed
23078 * @param {Tree} tree The owner tree
23079 * @param {Node} this This node
23080 * @param {Node} node The removed node
23085 * Fires when this node is moved to a new location in the tree
23086 * @param {Tree} tree The owner tree
23087 * @param {Node} this This node
23088 * @param {Node} oldParent The old parent of this node
23089 * @param {Node} newParent The new parent of this node
23090 * @param {Number} index The index it was moved to
23095 * Fires when a new child node is inserted.
23096 * @param {Tree} tree The owner tree
23097 * @param {Node} this This node
23098 * @param {Node} node The child node inserted
23099 * @param {Node} refNode The child node the node was inserted before
23103 * @event beforeappend
23104 * Fires before a new child is appended, return false to cancel the append.
23105 * @param {Tree} tree The owner tree
23106 * @param {Node} this This node
23107 * @param {Node} node The child node to be appended
23109 "beforeappend" : true,
23111 * @event beforeremove
23112 * Fires before a child is removed, return false to cancel the remove.
23113 * @param {Tree} tree The owner tree
23114 * @param {Node} this This node
23115 * @param {Node} node The child node to be removed
23117 "beforeremove" : true,
23119 * @event beforemove
23120 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23121 * @param {Tree} tree The owner tree
23122 * @param {Node} this This node
23123 * @param {Node} oldParent The parent of this node
23124 * @param {Node} newParent The new parent this node is moving to
23125 * @param {Number} index The index it is being moved to
23127 "beforemove" : true,
23129 * @event beforeinsert
23130 * Fires before a new child is inserted, return false to cancel the insert.
23131 * @param {Tree} tree The owner tree
23132 * @param {Node} this This node
23133 * @param {Node} node The child node to be inserted
23134 * @param {Node} refNode The child node the node is being inserted before
23136 "beforeinsert" : true
23138 this.listeners = this.attributes.listeners;
23139 Roo.data.Node.superclass.constructor.call(this);
23142 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23143 fireEvent : function(evtName){
23144 // first do standard event for this node
23145 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23148 // then bubble it up to the tree if the event wasn't cancelled
23149 var ot = this.getOwnerTree();
23151 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23159 * Returns true if this node is a leaf
23160 * @return {Boolean}
23162 isLeaf : function(){
23163 return this.leaf === true;
23167 setFirstChild : function(node){
23168 this.firstChild = node;
23172 setLastChild : function(node){
23173 this.lastChild = node;
23178 * Returns true if this node is the last child of its parent
23179 * @return {Boolean}
23181 isLast : function(){
23182 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23186 * Returns true if this node is the first child of its parent
23187 * @return {Boolean}
23189 isFirst : function(){
23190 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23193 hasChildNodes : function(){
23194 return !this.isLeaf() && this.childNodes.length > 0;
23198 * Insert node(s) as the last child node of this node.
23199 * @param {Node/Array} node The node or Array of nodes to append
23200 * @return {Node} The appended node if single append, or null if an array was passed
23202 appendChild : function(node){
23204 if(node instanceof Array){
23206 }else if(arguments.length > 1){
23209 // if passed an array or multiple args do them one by one
23211 for(var i = 0, len = multi.length; i < len; i++) {
23212 this.appendChild(multi[i]);
23215 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23218 var index = this.childNodes.length;
23219 var oldParent = node.parentNode;
23220 // it's a move, make sure we move it cleanly
23222 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23225 oldParent.removeChild(node);
23227 index = this.childNodes.length;
23229 this.setFirstChild(node);
23231 this.childNodes.push(node);
23232 node.parentNode = this;
23233 var ps = this.childNodes[index-1];
23235 node.previousSibling = ps;
23236 ps.nextSibling = node;
23238 node.previousSibling = null;
23240 node.nextSibling = null;
23241 this.setLastChild(node);
23242 node.setOwnerTree(this.getOwnerTree());
23243 this.fireEvent("append", this.ownerTree, this, node, index);
23245 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23252 * Removes a child node from this node.
23253 * @param {Node} node The node to remove
23254 * @return {Node} The removed node
23256 removeChild : function(node){
23257 var index = this.childNodes.indexOf(node);
23261 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23265 // remove it from childNodes collection
23266 this.childNodes.splice(index, 1);
23269 if(node.previousSibling){
23270 node.previousSibling.nextSibling = node.nextSibling;
23272 if(node.nextSibling){
23273 node.nextSibling.previousSibling = node.previousSibling;
23276 // update child refs
23277 if(this.firstChild == node){
23278 this.setFirstChild(node.nextSibling);
23280 if(this.lastChild == node){
23281 this.setLastChild(node.previousSibling);
23284 node.setOwnerTree(null);
23285 // clear any references from the node
23286 node.parentNode = null;
23287 node.previousSibling = null;
23288 node.nextSibling = null;
23289 this.fireEvent("remove", this.ownerTree, this, node);
23294 * Inserts the first node before the second node in this nodes childNodes collection.
23295 * @param {Node} node The node to insert
23296 * @param {Node} refNode The node to insert before (if null the node is appended)
23297 * @return {Node} The inserted node
23299 insertBefore : function(node, refNode){
23300 if(!refNode){ // like standard Dom, refNode can be null for append
23301 return this.appendChild(node);
23304 if(node == refNode){
23308 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23311 var index = this.childNodes.indexOf(refNode);
23312 var oldParent = node.parentNode;
23313 var refIndex = index;
23315 // when moving internally, indexes will change after remove
23316 if(oldParent == this && this.childNodes.indexOf(node) < index){
23320 // it's a move, make sure we move it cleanly
23322 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23325 oldParent.removeChild(node);
23328 this.setFirstChild(node);
23330 this.childNodes.splice(refIndex, 0, node);
23331 node.parentNode = this;
23332 var ps = this.childNodes[refIndex-1];
23334 node.previousSibling = ps;
23335 ps.nextSibling = node;
23337 node.previousSibling = null;
23339 node.nextSibling = refNode;
23340 refNode.previousSibling = node;
23341 node.setOwnerTree(this.getOwnerTree());
23342 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23344 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23350 * Returns the child node at the specified index.
23351 * @param {Number} index
23354 item : function(index){
23355 return this.childNodes[index];
23359 * Replaces one child node in this node with another.
23360 * @param {Node} newChild The replacement node
23361 * @param {Node} oldChild The node to replace
23362 * @return {Node} The replaced node
23364 replaceChild : function(newChild, oldChild){
23365 this.insertBefore(newChild, oldChild);
23366 this.removeChild(oldChild);
23371 * Returns the index of a child node
23372 * @param {Node} node
23373 * @return {Number} The index of the node or -1 if it was not found
23375 indexOf : function(child){
23376 return this.childNodes.indexOf(child);
23380 * Returns the tree this node is in.
23383 getOwnerTree : function(){
23384 // if it doesn't have one, look for one
23385 if(!this.ownerTree){
23389 this.ownerTree = p.ownerTree;
23395 return this.ownerTree;
23399 * Returns depth of this node (the root node has a depth of 0)
23402 getDepth : function(){
23405 while(p.parentNode){
23413 setOwnerTree : function(tree){
23414 // if it's move, we need to update everyone
23415 if(tree != this.ownerTree){
23416 if(this.ownerTree){
23417 this.ownerTree.unregisterNode(this);
23419 this.ownerTree = tree;
23420 var cs = this.childNodes;
23421 for(var i = 0, len = cs.length; i < len; i++) {
23422 cs[i].setOwnerTree(tree);
23425 tree.registerNode(this);
23431 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23432 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23433 * @return {String} The path
23435 getPath : function(attr){
23436 attr = attr || "id";
23437 var p = this.parentNode;
23438 var b = [this.attributes[attr]];
23440 b.unshift(p.attributes[attr]);
23443 var sep = this.getOwnerTree().pathSeparator;
23444 return sep + b.join(sep);
23448 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23449 * function call will be the scope provided or the current node. The arguments to the function
23450 * will be the args provided or the current node. If the function returns false at any point,
23451 * the bubble is stopped.
23452 * @param {Function} fn The function to call
23453 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23454 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23456 bubble : function(fn, scope, args){
23459 if(fn.call(scope || p, args || p) === false){
23467 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23468 * function call will be the scope provided or the current node. The arguments to the function
23469 * will be the args provided or the current node. If the function returns false at any point,
23470 * the cascade is stopped on that branch.
23471 * @param {Function} fn The function to call
23472 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23473 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23475 cascade : function(fn, scope, args){
23476 if(fn.call(scope || this, args || this) !== false){
23477 var cs = this.childNodes;
23478 for(var i = 0, len = cs.length; i < len; i++) {
23479 cs[i].cascade(fn, scope, args);
23485 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23486 * function call will be the scope provided or the current node. The arguments to the function
23487 * will be the args provided or the current node. If the function returns false at any point,
23488 * the iteration stops.
23489 * @param {Function} fn The function to call
23490 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23491 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23493 eachChild : function(fn, scope, args){
23494 var cs = this.childNodes;
23495 for(var i = 0, len = cs.length; i < len; i++) {
23496 if(fn.call(scope || this, args || cs[i]) === false){
23503 * Finds the first child that has the attribute with the specified value.
23504 * @param {String} attribute The attribute name
23505 * @param {Mixed} value The value to search for
23506 * @return {Node} The found child or null if none was found
23508 findChild : function(attribute, value){
23509 var cs = this.childNodes;
23510 for(var i = 0, len = cs.length; i < len; i++) {
23511 if(cs[i].attributes[attribute] == value){
23519 * Finds the first child by a custom function. The child matches if the function passed
23521 * @param {Function} fn
23522 * @param {Object} scope (optional)
23523 * @return {Node} The found child or null if none was found
23525 findChildBy : function(fn, scope){
23526 var cs = this.childNodes;
23527 for(var i = 0, len = cs.length; i < len; i++) {
23528 if(fn.call(scope||cs[i], cs[i]) === true){
23536 * Sorts this nodes children using the supplied sort function
23537 * @param {Function} fn
23538 * @param {Object} scope (optional)
23540 sort : function(fn, scope){
23541 var cs = this.childNodes;
23542 var len = cs.length;
23544 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23546 for(var i = 0; i < len; i++){
23548 n.previousSibling = cs[i-1];
23549 n.nextSibling = cs[i+1];
23551 this.setFirstChild(n);
23554 this.setLastChild(n);
23561 * Returns true if this node is an ancestor (at any point) of the passed node.
23562 * @param {Node} node
23563 * @return {Boolean}
23565 contains : function(node){
23566 return node.isAncestor(this);
23570 * Returns true if the passed node is an ancestor (at any point) of this node.
23571 * @param {Node} node
23572 * @return {Boolean}
23574 isAncestor : function(node){
23575 var p = this.parentNode;
23585 toString : function(){
23586 return "[Node"+(this.id?" "+this.id:"")+"]";
23590 * Ext JS Library 1.1.1
23591 * Copyright(c) 2006-2007, Ext JS, LLC.
23593 * Originally Released Under LGPL - original licence link has changed is not relivant.
23596 * <script type="text/javascript">
23601 * @extends Roo.Element
23602 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23603 * automatic maintaining of shadow/shim positions.
23604 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23605 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23606 * you can pass a string with a CSS class name. False turns off the shadow.
23607 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23608 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23609 * @cfg {String} cls CSS class to add to the element
23610 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23611 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23613 * @param {Object} config An object with config options.
23614 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23617 Roo.Layer = function(config, existingEl){
23618 config = config || {};
23619 var dh = Roo.DomHelper;
23620 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23622 this.dom = Roo.getDom(existingEl);
23625 var o = config.dh || {tag: "div", cls: "x-layer"};
23626 this.dom = dh.append(pel, o);
23629 this.addClass(config.cls);
23631 this.constrain = config.constrain !== false;
23632 this.visibilityMode = Roo.Element.VISIBILITY;
23634 this.id = this.dom.id = config.id;
23636 this.id = Roo.id(this.dom);
23638 this.zindex = config.zindex || this.getZIndex();
23639 this.position("absolute", this.zindex);
23641 this.shadowOffset = config.shadowOffset || 4;
23642 this.shadow = new Roo.Shadow({
23643 offset : this.shadowOffset,
23644 mode : config.shadow
23647 this.shadowOffset = 0;
23649 this.useShim = config.shim !== false && Roo.useShims;
23650 this.useDisplay = config.useDisplay;
23654 var supr = Roo.Element.prototype;
23656 // shims are shared among layer to keep from having 100 iframes
23659 Roo.extend(Roo.Layer, Roo.Element, {
23661 getZIndex : function(){
23662 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23665 getShim : function(){
23672 var shim = shims.shift();
23674 shim = this.createShim();
23675 shim.enableDisplayMode('block');
23676 shim.dom.style.display = 'none';
23677 shim.dom.style.visibility = 'visible';
23679 var pn = this.dom.parentNode;
23680 if(shim.dom.parentNode != pn){
23681 pn.insertBefore(shim.dom, this.dom);
23683 shim.setStyle('z-index', this.getZIndex()-2);
23688 hideShim : function(){
23690 this.shim.setDisplayed(false);
23691 shims.push(this.shim);
23696 disableShadow : function(){
23698 this.shadowDisabled = true;
23699 this.shadow.hide();
23700 this.lastShadowOffset = this.shadowOffset;
23701 this.shadowOffset = 0;
23705 enableShadow : function(show){
23707 this.shadowDisabled = false;
23708 this.shadowOffset = this.lastShadowOffset;
23709 delete this.lastShadowOffset;
23717 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23718 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23719 sync : function(doShow){
23720 var sw = this.shadow;
23721 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23722 var sh = this.getShim();
23724 var w = this.getWidth(),
23725 h = this.getHeight();
23727 var l = this.getLeft(true),
23728 t = this.getTop(true);
23730 if(sw && !this.shadowDisabled){
23731 if(doShow && !sw.isVisible()){
23734 sw.realign(l, t, w, h);
23740 // fit the shim behind the shadow, so it is shimmed too
23741 var a = sw.adjusts, s = sh.dom.style;
23742 s.left = (Math.min(l, l+a.l))+"px";
23743 s.top = (Math.min(t, t+a.t))+"px";
23744 s.width = (w+a.w)+"px";
23745 s.height = (h+a.h)+"px";
23752 sh.setLeftTop(l, t);
23759 destroy : function(){
23762 this.shadow.hide();
23764 this.removeAllListeners();
23765 var pn = this.dom.parentNode;
23767 pn.removeChild(this.dom);
23769 Roo.Element.uncache(this.id);
23772 remove : function(){
23777 beginUpdate : function(){
23778 this.updating = true;
23782 endUpdate : function(){
23783 this.updating = false;
23788 hideUnders : function(negOffset){
23790 this.shadow.hide();
23796 constrainXY : function(){
23797 if(this.constrain){
23798 var vw = Roo.lib.Dom.getViewWidth(),
23799 vh = Roo.lib.Dom.getViewHeight();
23800 var s = Roo.get(document).getScroll();
23802 var xy = this.getXY();
23803 var x = xy[0], y = xy[1];
23804 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23805 // only move it if it needs it
23807 // first validate right/bottom
23808 if((x + w) > vw+s.left){
23809 x = vw - w - this.shadowOffset;
23812 if((y + h) > vh+s.top){
23813 y = vh - h - this.shadowOffset;
23816 // then make sure top/left isn't negative
23827 var ay = this.avoidY;
23828 if(y <= ay && (y+h) >= ay){
23834 supr.setXY.call(this, xy);
23840 isVisible : function(){
23841 return this.visible;
23845 showAction : function(){
23846 this.visible = true; // track visibility to prevent getStyle calls
23847 if(this.useDisplay === true){
23848 this.setDisplayed("");
23849 }else if(this.lastXY){
23850 supr.setXY.call(this, this.lastXY);
23851 }else if(this.lastLT){
23852 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23857 hideAction : function(){
23858 this.visible = false;
23859 if(this.useDisplay === true){
23860 this.setDisplayed(false);
23862 this.setLeftTop(-10000,-10000);
23866 // overridden Element method
23867 setVisible : function(v, a, d, c, e){
23872 var cb = function(){
23877 }.createDelegate(this);
23878 supr.setVisible.call(this, true, true, d, cb, e);
23881 this.hideUnders(true);
23890 }.createDelegate(this);
23892 supr.setVisible.call(this, v, a, d, cb, e);
23901 storeXY : function(xy){
23902 delete this.lastLT;
23906 storeLeftTop : function(left, top){
23907 delete this.lastXY;
23908 this.lastLT = [left, top];
23912 beforeFx : function(){
23913 this.beforeAction();
23914 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23918 afterFx : function(){
23919 Roo.Layer.superclass.afterFx.apply(this, arguments);
23920 this.sync(this.isVisible());
23924 beforeAction : function(){
23925 if(!this.updating && this.shadow){
23926 this.shadow.hide();
23930 // overridden Element method
23931 setLeft : function(left){
23932 this.storeLeftTop(left, this.getTop(true));
23933 supr.setLeft.apply(this, arguments);
23937 setTop : function(top){
23938 this.storeLeftTop(this.getLeft(true), top);
23939 supr.setTop.apply(this, arguments);
23943 setLeftTop : function(left, top){
23944 this.storeLeftTop(left, top);
23945 supr.setLeftTop.apply(this, arguments);
23949 setXY : function(xy, a, d, c, e){
23951 this.beforeAction();
23953 var cb = this.createCB(c);
23954 supr.setXY.call(this, xy, a, d, cb, e);
23961 createCB : function(c){
23972 // overridden Element method
23973 setX : function(x, a, d, c, e){
23974 this.setXY([x, this.getY()], a, d, c, e);
23977 // overridden Element method
23978 setY : function(y, a, d, c, e){
23979 this.setXY([this.getX(), y], a, d, c, e);
23982 // overridden Element method
23983 setSize : function(w, h, a, d, c, e){
23984 this.beforeAction();
23985 var cb = this.createCB(c);
23986 supr.setSize.call(this, w, h, a, d, cb, e);
23992 // overridden Element method
23993 setWidth : function(w, a, d, c, e){
23994 this.beforeAction();
23995 var cb = this.createCB(c);
23996 supr.setWidth.call(this, w, a, d, cb, e);
24002 // overridden Element method
24003 setHeight : function(h, a, d, c, e){
24004 this.beforeAction();
24005 var cb = this.createCB(c);
24006 supr.setHeight.call(this, h, a, d, cb, e);
24012 // overridden Element method
24013 setBounds : function(x, y, w, h, a, d, c, e){
24014 this.beforeAction();
24015 var cb = this.createCB(c);
24017 this.storeXY([x, y]);
24018 supr.setXY.call(this, [x, y]);
24019 supr.setSize.call(this, w, h, a, d, cb, e);
24022 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24028 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24029 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24030 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24031 * @param {Number} zindex The new z-index to set
24032 * @return {this} The Layer
24034 setZIndex : function(zindex){
24035 this.zindex = zindex;
24036 this.setStyle("z-index", zindex + 2);
24038 this.shadow.setZIndex(zindex + 1);
24041 this.shim.setStyle("z-index", zindex);
24047 * Ext JS Library 1.1.1
24048 * Copyright(c) 2006-2007, Ext JS, LLC.
24050 * Originally Released Under LGPL - original licence link has changed is not relivant.
24053 * <script type="text/javascript">
24058 * @class Roo.Shadow
24059 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24060 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24061 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24063 * Create a new Shadow
24064 * @param {Object} config The config object
24066 Roo.Shadow = function(config){
24067 Roo.apply(this, config);
24068 if(typeof this.mode != "string"){
24069 this.mode = this.defaultMode;
24071 var o = this.offset, a = {h: 0};
24072 var rad = Math.floor(this.offset/2);
24073 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24079 a.l -= this.offset + rad;
24080 a.t -= this.offset + rad;
24091 a.l -= (this.offset - rad);
24092 a.t -= this.offset + rad;
24094 a.w -= (this.offset - rad)*2;
24105 a.l -= (this.offset - rad);
24106 a.t -= (this.offset - rad);
24108 a.w -= (this.offset + rad + 1);
24109 a.h -= (this.offset + rad);
24118 Roo.Shadow.prototype = {
24120 * @cfg {String} mode
24121 * The shadow display mode. Supports the following options:<br />
24122 * sides: Shadow displays on both sides and bottom only<br />
24123 * frame: Shadow displays equally on all four sides<br />
24124 * drop: Traditional bottom-right drop shadow (default)
24127 * @cfg {String} offset
24128 * The number of pixels to offset the shadow from the element (defaults to 4)
24133 defaultMode: "drop",
24136 * Displays the shadow under the target element
24137 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24139 show : function(target){
24140 target = Roo.get(target);
24142 this.el = Roo.Shadow.Pool.pull();
24143 if(this.el.dom.nextSibling != target.dom){
24144 this.el.insertBefore(target);
24147 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24149 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24152 target.getLeft(true),
24153 target.getTop(true),
24157 this.el.dom.style.display = "block";
24161 * Returns true if the shadow is visible, else false
24163 isVisible : function(){
24164 return this.el ? true : false;
24168 * Direct alignment when values are already available. Show must be called at least once before
24169 * calling this method to ensure it is initialized.
24170 * @param {Number} left The target element left position
24171 * @param {Number} top The target element top position
24172 * @param {Number} width The target element width
24173 * @param {Number} height The target element height
24175 realign : function(l, t, w, h){
24179 var a = this.adjusts, d = this.el.dom, s = d.style;
24181 s.left = (l+a.l)+"px";
24182 s.top = (t+a.t)+"px";
24183 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24185 if(s.width != sws || s.height != shs){
24189 var cn = d.childNodes;
24190 var sww = Math.max(0, (sw-12))+"px";
24191 cn[0].childNodes[1].style.width = sww;
24192 cn[1].childNodes[1].style.width = sww;
24193 cn[2].childNodes[1].style.width = sww;
24194 cn[1].style.height = Math.max(0, (sh-12))+"px";
24200 * Hides this shadow
24204 this.el.dom.style.display = "none";
24205 Roo.Shadow.Pool.push(this.el);
24211 * Adjust the z-index of this shadow
24212 * @param {Number} zindex The new z-index
24214 setZIndex : function(z){
24217 this.el.setStyle("z-index", z);
24222 // Private utility class that manages the internal Shadow cache
24223 Roo.Shadow.Pool = function(){
24225 var markup = Roo.isIE ?
24226 '<div class="x-ie-shadow"></div>' :
24227 '<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>';
24230 var sh = p.shift();
24232 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24233 sh.autoBoxAdjust = false;
24238 push : function(sh){
24244 * Ext JS Library 1.1.1
24245 * Copyright(c) 2006-2007, Ext JS, LLC.
24247 * Originally Released Under LGPL - original licence link has changed is not relivant.
24250 * <script type="text/javascript">
24255 * @class Roo.SplitBar
24256 * @extends Roo.util.Observable
24257 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24261 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24262 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24263 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24264 split.minSize = 100;
24265 split.maxSize = 600;
24266 split.animate = true;
24267 split.on('moved', splitterMoved);
24270 * Create a new SplitBar
24271 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24272 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24273 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24274 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24275 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24276 position of the SplitBar).
24278 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24281 this.el = Roo.get(dragElement, true);
24282 this.el.dom.unselectable = "on";
24284 this.resizingEl = Roo.get(resizingElement, true);
24288 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24289 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24292 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24295 * The minimum size of the resizing element. (Defaults to 0)
24301 * The maximum size of the resizing element. (Defaults to 2000)
24304 this.maxSize = 2000;
24307 * Whether to animate the transition to the new size
24310 this.animate = false;
24313 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24316 this.useShim = false;
24321 if(!existingProxy){
24323 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24325 this.proxy = Roo.get(existingProxy).dom;
24328 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24331 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24334 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24337 this.dragSpecs = {};
24340 * @private The adapter to use to positon and resize elements
24342 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24343 this.adapter.init(this);
24345 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24347 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24348 this.el.addClass("x-splitbar-h");
24351 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24352 this.el.addClass("x-splitbar-v");
24358 * Fires when the splitter is moved (alias for {@link #event-moved})
24359 * @param {Roo.SplitBar} this
24360 * @param {Number} newSize the new width or height
24365 * Fires when the splitter is moved
24366 * @param {Roo.SplitBar} this
24367 * @param {Number} newSize the new width or height
24371 * @event beforeresize
24372 * Fires before the splitter is dragged
24373 * @param {Roo.SplitBar} this
24375 "beforeresize" : true,
24377 "beforeapply" : true
24380 Roo.util.Observable.call(this);
24383 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24384 onStartProxyDrag : function(x, y){
24385 this.fireEvent("beforeresize", this);
24387 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24389 o.enableDisplayMode("block");
24390 // all splitbars share the same overlay
24391 Roo.SplitBar.prototype.overlay = o;
24393 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24394 this.overlay.show();
24395 Roo.get(this.proxy).setDisplayed("block");
24396 var size = this.adapter.getElementSize(this);
24397 this.activeMinSize = this.getMinimumSize();;
24398 this.activeMaxSize = this.getMaximumSize();;
24399 var c1 = size - this.activeMinSize;
24400 var c2 = Math.max(this.activeMaxSize - size, 0);
24401 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24402 this.dd.resetConstraints();
24403 this.dd.setXConstraint(
24404 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24405 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24407 this.dd.setYConstraint(0, 0);
24409 this.dd.resetConstraints();
24410 this.dd.setXConstraint(0, 0);
24411 this.dd.setYConstraint(
24412 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24413 this.placement == Roo.SplitBar.TOP ? c2 : c1
24416 this.dragSpecs.startSize = size;
24417 this.dragSpecs.startPoint = [x, y];
24418 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24422 * @private Called after the drag operation by the DDProxy
24424 onEndProxyDrag : function(e){
24425 Roo.get(this.proxy).setDisplayed(false);
24426 var endPoint = Roo.lib.Event.getXY(e);
24428 this.overlay.hide();
24431 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24432 newSize = this.dragSpecs.startSize +
24433 (this.placement == Roo.SplitBar.LEFT ?
24434 endPoint[0] - this.dragSpecs.startPoint[0] :
24435 this.dragSpecs.startPoint[0] - endPoint[0]
24438 newSize = this.dragSpecs.startSize +
24439 (this.placement == Roo.SplitBar.TOP ?
24440 endPoint[1] - this.dragSpecs.startPoint[1] :
24441 this.dragSpecs.startPoint[1] - endPoint[1]
24444 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24445 if(newSize != this.dragSpecs.startSize){
24446 if(this.fireEvent('beforeapply', this, newSize) !== false){
24447 this.adapter.setElementSize(this, newSize);
24448 this.fireEvent("moved", this, newSize);
24449 this.fireEvent("resize", this, newSize);
24455 * Get the adapter this SplitBar uses
24456 * @return The adapter object
24458 getAdapter : function(){
24459 return this.adapter;
24463 * Set the adapter this SplitBar uses
24464 * @param {Object} adapter A SplitBar adapter object
24466 setAdapter : function(adapter){
24467 this.adapter = adapter;
24468 this.adapter.init(this);
24472 * Gets the minimum size for the resizing element
24473 * @return {Number} The minimum size
24475 getMinimumSize : function(){
24476 return this.minSize;
24480 * Sets the minimum size for the resizing element
24481 * @param {Number} minSize The minimum size
24483 setMinimumSize : function(minSize){
24484 this.minSize = minSize;
24488 * Gets the maximum size for the resizing element
24489 * @return {Number} The maximum size
24491 getMaximumSize : function(){
24492 return this.maxSize;
24496 * Sets the maximum size for the resizing element
24497 * @param {Number} maxSize The maximum size
24499 setMaximumSize : function(maxSize){
24500 this.maxSize = maxSize;
24504 * Sets the initialize size for the resizing element
24505 * @param {Number} size The initial size
24507 setCurrentSize : function(size){
24508 var oldAnimate = this.animate;
24509 this.animate = false;
24510 this.adapter.setElementSize(this, size);
24511 this.animate = oldAnimate;
24515 * Destroy this splitbar.
24516 * @param {Boolean} removeEl True to remove the element
24518 destroy : function(removeEl){
24520 this.shim.remove();
24523 this.proxy.parentNode.removeChild(this.proxy);
24531 * @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.
24533 Roo.SplitBar.createProxy = function(dir){
24534 var proxy = new Roo.Element(document.createElement("div"));
24535 proxy.unselectable();
24536 var cls = 'x-splitbar-proxy';
24537 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24538 document.body.appendChild(proxy.dom);
24543 * @class Roo.SplitBar.BasicLayoutAdapter
24544 * Default Adapter. It assumes the splitter and resizing element are not positioned
24545 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24547 Roo.SplitBar.BasicLayoutAdapter = function(){
24550 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24551 // do nothing for now
24552 init : function(s){
24556 * Called before drag operations to get the current size of the resizing element.
24557 * @param {Roo.SplitBar} s The SplitBar using this adapter
24559 getElementSize : function(s){
24560 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24561 return s.resizingEl.getWidth();
24563 return s.resizingEl.getHeight();
24568 * Called after drag operations to set the size of the resizing element.
24569 * @param {Roo.SplitBar} s The SplitBar using this adapter
24570 * @param {Number} newSize The new size to set
24571 * @param {Function} onComplete A function to be invoked when resizing is complete
24573 setElementSize : function(s, newSize, onComplete){
24574 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24576 s.resizingEl.setWidth(newSize);
24578 onComplete(s, newSize);
24581 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24586 s.resizingEl.setHeight(newSize);
24588 onComplete(s, newSize);
24591 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24598 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24599 * @extends Roo.SplitBar.BasicLayoutAdapter
24600 * Adapter that moves the splitter element to align with the resized sizing element.
24601 * Used with an absolute positioned SplitBar.
24602 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24603 * document.body, make sure you assign an id to the body element.
24605 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24606 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24607 this.container = Roo.get(container);
24610 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24611 init : function(s){
24612 this.basic.init(s);
24615 getElementSize : function(s){
24616 return this.basic.getElementSize(s);
24619 setElementSize : function(s, newSize, onComplete){
24620 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24623 moveSplitter : function(s){
24624 var yes = Roo.SplitBar;
24625 switch(s.placement){
24627 s.el.setX(s.resizingEl.getRight());
24630 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24633 s.el.setY(s.resizingEl.getBottom());
24636 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24643 * Orientation constant - Create a vertical SplitBar
24647 Roo.SplitBar.VERTICAL = 1;
24650 * Orientation constant - Create a horizontal SplitBar
24654 Roo.SplitBar.HORIZONTAL = 2;
24657 * Placement constant - The resizing element is to the left of the splitter element
24661 Roo.SplitBar.LEFT = 1;
24664 * Placement constant - The resizing element is to the right of the splitter element
24668 Roo.SplitBar.RIGHT = 2;
24671 * Placement constant - The resizing element is positioned above the splitter element
24675 Roo.SplitBar.TOP = 3;
24678 * Placement constant - The resizing element is positioned under splitter element
24682 Roo.SplitBar.BOTTOM = 4;
24685 * Ext JS Library 1.1.1
24686 * Copyright(c) 2006-2007, Ext JS, LLC.
24688 * Originally Released Under LGPL - original licence link has changed is not relivant.
24691 * <script type="text/javascript">
24696 * @extends Roo.util.Observable
24697 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24698 * This class also supports single and multi selection modes. <br>
24699 * Create a data model bound view:
24701 var store = new Roo.data.Store(...);
24703 var view = new Roo.View({
24705 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24707 singleSelect: true,
24708 selectedClass: "ydataview-selected",
24712 // listen for node click?
24713 view.on("click", function(vw, index, node, e){
24714 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24718 dataModel.load("foobar.xml");
24720 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24722 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24723 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24725 * Note: old style constructor is still suported (container, template, config)
24728 * Create a new View
24729 * @param {Object} config The config object
24732 Roo.View = function(config, depreciated_tpl, depreciated_config){
24734 if (typeof(depreciated_tpl) == 'undefined') {
24735 // new way.. - universal constructor.
24736 Roo.apply(this, config);
24737 this.el = Roo.get(this.el);
24740 this.el = Roo.get(config);
24741 this.tpl = depreciated_tpl;
24742 Roo.apply(this, depreciated_config);
24744 this.wrapEl = this.el.wrap().wrap();
24745 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24748 if(typeof(this.tpl) == "string"){
24749 this.tpl = new Roo.Template(this.tpl);
24751 // support xtype ctors..
24752 this.tpl = new Roo.factory(this.tpl, Roo);
24756 this.tpl.compile();
24764 * @event beforeclick
24765 * Fires before a click is processed. Returns false to cancel the default action.
24766 * @param {Roo.View} this
24767 * @param {Number} index The index of the target node
24768 * @param {HTMLElement} node The target node
24769 * @param {Roo.EventObject} e The raw event object
24771 "beforeclick" : true,
24774 * Fires when a template node is clicked.
24775 * @param {Roo.View} this
24776 * @param {Number} index The index of the target node
24777 * @param {HTMLElement} node The target node
24778 * @param {Roo.EventObject} e The raw event object
24783 * Fires when a template node is double clicked.
24784 * @param {Roo.View} this
24785 * @param {Number} index The index of the target node
24786 * @param {HTMLElement} node The target node
24787 * @param {Roo.EventObject} e The raw event object
24791 * @event contextmenu
24792 * Fires when a template node is right clicked.
24793 * @param {Roo.View} this
24794 * @param {Number} index The index of the target node
24795 * @param {HTMLElement} node The target node
24796 * @param {Roo.EventObject} e The raw event object
24798 "contextmenu" : true,
24800 * @event selectionchange
24801 * Fires when the selected nodes change.
24802 * @param {Roo.View} this
24803 * @param {Array} selections Array of the selected nodes
24805 "selectionchange" : true,
24808 * @event beforeselect
24809 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24810 * @param {Roo.View} this
24811 * @param {HTMLElement} node The node to be selected
24812 * @param {Array} selections Array of currently selected nodes
24814 "beforeselect" : true,
24816 * @event preparedata
24817 * Fires on every row to render, to allow you to change the data.
24818 * @param {Roo.View} this
24819 * @param {Object} data to be rendered (change this)
24821 "preparedata" : true
24829 "click": this.onClick,
24830 "dblclick": this.onDblClick,
24831 "contextmenu": this.onContextMenu,
24835 this.selections = [];
24837 this.cmp = new Roo.CompositeElementLite([]);
24839 this.store = Roo.factory(this.store, Roo.data);
24840 this.setStore(this.store, true);
24843 if ( this.footer && this.footer.xtype) {
24845 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24847 this.footer.dataSource = this.store
24848 this.footer.container = fctr;
24849 this.footer = Roo.factory(this.footer, Roo);
24850 fctr.insertFirst(this.el);
24852 // this is a bit insane - as the paging toolbar seems to detach the el..
24853 // dom.parentNode.parentNode.parentNode
24854 // they get detached?
24858 Roo.View.superclass.constructor.call(this);
24863 Roo.extend(Roo.View, Roo.util.Observable, {
24866 * @cfg {Roo.data.Store} store Data store to load data from.
24871 * @cfg {String|Roo.Element} el The container element.
24876 * @cfg {String|Roo.Template} tpl The template used by this View
24880 * @cfg {String} dataName the named area of the template to use as the data area
24881 * Works with domtemplates roo-name="name"
24885 * @cfg {String} selectedClass The css class to add to selected nodes
24887 selectedClass : "x-view-selected",
24889 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24894 * @cfg {String} text to display on mask (default Loading)
24898 * @cfg {Boolean} multiSelect Allow multiple selection
24900 multiSelect : false,
24902 * @cfg {Boolean} singleSelect Allow single selection
24904 singleSelect: false,
24907 * @cfg {Boolean} toggleSelect - selecting
24909 toggleSelect : false,
24912 * Returns the element this view is bound to.
24913 * @return {Roo.Element}
24915 getEl : function(){
24916 return this.wrapEl;
24922 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24924 refresh : function(){
24927 // if we are using something like 'domtemplate', then
24928 // the what gets used is:
24929 // t.applySubtemplate(NAME, data, wrapping data..)
24930 // the outer template then get' applied with
24931 // the store 'extra data'
24932 // and the body get's added to the
24933 // roo-name="data" node?
24934 // <span class='roo-tpl-{name}'></span> ?????
24938 this.clearSelections();
24939 this.el.update("");
24941 var records = this.store.getRange();
24942 if(records.length < 1) {
24944 // is this valid?? = should it render a template??
24946 this.el.update(this.emptyText);
24950 if (this.dataName) {
24951 this.el.update(t.apply(this.store.meta)); //????
24952 el = this.el.child('.roo-tpl-' + this.dataName);
24955 for(var i = 0, len = records.length; i < len; i++){
24956 var data = this.prepareData(records[i].data, i, records[i]);
24957 this.fireEvent("preparedata", this, data, i, records[i]);
24958 html[html.length] = Roo.util.Format.trim(
24960 t.applySubtemplate(this.dataName, data, this.store.meta) :
24967 el.update(html.join(""));
24968 this.nodes = el.dom.childNodes;
24969 this.updateIndexes(0);
24973 * Function to override to reformat the data that is sent to
24974 * the template for each node.
24975 * DEPRICATED - use the preparedata event handler.
24976 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
24977 * a JSON object for an UpdateManager bound view).
24979 prepareData : function(data, index, record)
24981 this.fireEvent("preparedata", this, data, index, record);
24985 onUpdate : function(ds, record){
24986 this.clearSelections();
24987 var index = this.store.indexOf(record);
24988 var n = this.nodes[index];
24989 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
24990 n.parentNode.removeChild(n);
24991 this.updateIndexes(index, index);
24997 onAdd : function(ds, records, index)
24999 this.clearSelections();
25000 if(this.nodes.length == 0){
25004 var n = this.nodes[index];
25005 for(var i = 0, len = records.length; i < len; i++){
25006 var d = this.prepareData(records[i].data, i, records[i]);
25008 this.tpl.insertBefore(n, d);
25011 this.tpl.append(this.el, d);
25014 this.updateIndexes(index);
25017 onRemove : function(ds, record, index){
25018 this.clearSelections();
25019 var el = this.dataName ?
25020 this.el.child('.roo-tpl-' + this.dataName) :
25022 el.dom.removeChild(this.nodes[index]);
25023 this.updateIndexes(index);
25027 * Refresh an individual node.
25028 * @param {Number} index
25030 refreshNode : function(index){
25031 this.onUpdate(this.store, this.store.getAt(index));
25034 updateIndexes : function(startIndex, endIndex){
25035 var ns = this.nodes;
25036 startIndex = startIndex || 0;
25037 endIndex = endIndex || ns.length - 1;
25038 for(var i = startIndex; i <= endIndex; i++){
25039 ns[i].nodeIndex = i;
25044 * Changes the data store this view uses and refresh the view.
25045 * @param {Store} store
25047 setStore : function(store, initial){
25048 if(!initial && this.store){
25049 this.store.un("datachanged", this.refresh);
25050 this.store.un("add", this.onAdd);
25051 this.store.un("remove", this.onRemove);
25052 this.store.un("update", this.onUpdate);
25053 this.store.un("clear", this.refresh);
25054 this.store.un("beforeload", this.onBeforeLoad);
25055 this.store.un("load", this.onLoad);
25056 this.store.un("loadexception", this.onLoad);
25060 store.on("datachanged", this.refresh, this);
25061 store.on("add", this.onAdd, this);
25062 store.on("remove", this.onRemove, this);
25063 store.on("update", this.onUpdate, this);
25064 store.on("clear", this.refresh, this);
25065 store.on("beforeload", this.onBeforeLoad, this);
25066 store.on("load", this.onLoad, this);
25067 store.on("loadexception", this.onLoad, this);
25075 * onbeforeLoad - masks the loading area.
25078 onBeforeLoad : function()
25080 this.el.update("");
25081 this.el.mask(this.mask ? this.mask : "Loading" );
25083 onLoad : function ()
25090 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25091 * @param {HTMLElement} node
25092 * @return {HTMLElement} The template node
25094 findItemFromChild : function(node){
25095 var el = this.dataName ?
25096 this.el.child('.roo-tpl-' + this.dataName,true) :
25099 if(!node || node.parentNode == el){
25102 var p = node.parentNode;
25103 while(p && p != el){
25104 if(p.parentNode == el){
25113 onClick : function(e){
25114 var item = this.findItemFromChild(e.getTarget());
25116 var index = this.indexOf(item);
25117 if(this.onItemClick(item, index, e) !== false){
25118 this.fireEvent("click", this, index, item, e);
25121 this.clearSelections();
25126 onContextMenu : function(e){
25127 var item = this.findItemFromChild(e.getTarget());
25129 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25134 onDblClick : function(e){
25135 var item = this.findItemFromChild(e.getTarget());
25137 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25141 onItemClick : function(item, index, e)
25143 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25146 if (this.toggleSelect) {
25147 var m = this.isSelected(item) ? 'unselect' : 'select';
25150 _t[m](item, true, false);
25153 if(this.multiSelect || this.singleSelect){
25154 if(this.multiSelect && e.shiftKey && this.lastSelection){
25155 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25157 this.select(item, this.multiSelect && e.ctrlKey);
25158 this.lastSelection = item;
25160 e.preventDefault();
25166 * Get the number of selected nodes.
25169 getSelectionCount : function(){
25170 return this.selections.length;
25174 * Get the currently selected nodes.
25175 * @return {Array} An array of HTMLElements
25177 getSelectedNodes : function(){
25178 return this.selections;
25182 * Get the indexes of the selected nodes.
25185 getSelectedIndexes : function(){
25186 var indexes = [], s = this.selections;
25187 for(var i = 0, len = s.length; i < len; i++){
25188 indexes.push(s[i].nodeIndex);
25194 * Clear all selections
25195 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25197 clearSelections : function(suppressEvent){
25198 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25199 this.cmp.elements = this.selections;
25200 this.cmp.removeClass(this.selectedClass);
25201 this.selections = [];
25202 if(!suppressEvent){
25203 this.fireEvent("selectionchange", this, this.selections);
25209 * Returns true if the passed node is selected
25210 * @param {HTMLElement/Number} node The node or node index
25211 * @return {Boolean}
25213 isSelected : function(node){
25214 var s = this.selections;
25218 node = this.getNode(node);
25219 return s.indexOf(node) !== -1;
25224 * @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
25225 * @param {Boolean} keepExisting (optional) true to keep existing selections
25226 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25228 select : function(nodeInfo, keepExisting, suppressEvent){
25229 if(nodeInfo instanceof Array){
25231 this.clearSelections(true);
25233 for(var i = 0, len = nodeInfo.length; i < len; i++){
25234 this.select(nodeInfo[i], true, true);
25238 var node = this.getNode(nodeInfo);
25239 if(!node || this.isSelected(node)){
25240 return; // already selected.
25243 this.clearSelections(true);
25245 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25246 Roo.fly(node).addClass(this.selectedClass);
25247 this.selections.push(node);
25248 if(!suppressEvent){
25249 this.fireEvent("selectionchange", this, this.selections);
25257 * @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
25258 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25259 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25261 unselect : function(nodeInfo, keepExisting, suppressEvent)
25263 if(nodeInfo instanceof Array){
25264 Roo.each(this.selections, function(s) {
25265 this.unselect(s, nodeInfo);
25269 var node = this.getNode(nodeInfo);
25270 if(!node || !this.isSelected(node)){
25271 Roo.log("not selected");
25272 return; // not selected.
25276 Roo.each(this.selections, function(s) {
25278 Roo.fly(node).removeClass(this.selectedClass);
25285 this.selections= ns;
25286 this.fireEvent("selectionchange", this, this.selections);
25290 * Gets a template node.
25291 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25292 * @return {HTMLElement} The node or null if it wasn't found
25294 getNode : function(nodeInfo){
25295 if(typeof nodeInfo == "string"){
25296 return document.getElementById(nodeInfo);
25297 }else if(typeof nodeInfo == "number"){
25298 return this.nodes[nodeInfo];
25304 * Gets a range template nodes.
25305 * @param {Number} startIndex
25306 * @param {Number} endIndex
25307 * @return {Array} An array of nodes
25309 getNodes : function(start, end){
25310 var ns = this.nodes;
25311 start = start || 0;
25312 end = typeof end == "undefined" ? ns.length - 1 : end;
25315 for(var i = start; i <= end; i++){
25319 for(var i = start; i >= end; i--){
25327 * Finds the index of the passed node
25328 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25329 * @return {Number} The index of the node or -1
25331 indexOf : function(node){
25332 node = this.getNode(node);
25333 if(typeof node.nodeIndex == "number"){
25334 return node.nodeIndex;
25336 var ns = this.nodes;
25337 for(var i = 0, len = ns.length; i < len; i++){
25347 * Ext JS Library 1.1.1
25348 * Copyright(c) 2006-2007, Ext JS, LLC.
25350 * Originally Released Under LGPL - original licence link has changed is not relivant.
25353 * <script type="text/javascript">
25357 * @class Roo.JsonView
25358 * @extends Roo.View
25359 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25361 var view = new Roo.JsonView({
25362 container: "my-element",
25363 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25368 // listen for node click?
25369 view.on("click", function(vw, index, node, e){
25370 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25373 // direct load of JSON data
25374 view.load("foobar.php");
25376 // Example from my blog list
25377 var tpl = new Roo.Template(
25378 '<div class="entry">' +
25379 '<a class="entry-title" href="{link}">{title}</a>' +
25380 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25381 "</div><hr />"
25384 var moreView = new Roo.JsonView({
25385 container : "entry-list",
25389 moreView.on("beforerender", this.sortEntries, this);
25391 url: "/blog/get-posts.php",
25392 params: "allposts=true",
25393 text: "Loading Blog Entries..."
25397 * Note: old code is supported with arguments : (container, template, config)
25401 * Create a new JsonView
25403 * @param {Object} config The config object
25406 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25409 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25411 var um = this.el.getUpdateManager();
25412 um.setRenderer(this);
25413 um.on("update", this.onLoad, this);
25414 um.on("failure", this.onLoadException, this);
25417 * @event beforerender
25418 * Fires before rendering of the downloaded JSON data.
25419 * @param {Roo.JsonView} this
25420 * @param {Object} data The JSON data loaded
25424 * Fires when data is loaded.
25425 * @param {Roo.JsonView} this
25426 * @param {Object} data The JSON data loaded
25427 * @param {Object} response The raw Connect response object
25430 * @event loadexception
25431 * Fires when loading fails.
25432 * @param {Roo.JsonView} this
25433 * @param {Object} response The raw Connect response object
25436 'beforerender' : true,
25438 'loadexception' : true
25441 Roo.extend(Roo.JsonView, Roo.View, {
25443 * @type {String} The root property in the loaded JSON object that contains the data
25448 * Refreshes the view.
25450 refresh : function(){
25451 this.clearSelections();
25452 this.el.update("");
25454 var o = this.jsonData;
25455 if(o && o.length > 0){
25456 for(var i = 0, len = o.length; i < len; i++){
25457 var data = this.prepareData(o[i], i, o);
25458 html[html.length] = this.tpl.apply(data);
25461 html.push(this.emptyText);
25463 this.el.update(html.join(""));
25464 this.nodes = this.el.dom.childNodes;
25465 this.updateIndexes(0);
25469 * 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.
25470 * @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:
25473 url: "your-url.php",
25474 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25475 callback: yourFunction,
25476 scope: yourObject, //(optional scope)
25479 text: "Loading...",
25484 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25485 * 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.
25486 * @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}
25487 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25488 * @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.
25491 var um = this.el.getUpdateManager();
25492 um.update.apply(um, arguments);
25495 render : function(el, response){
25496 this.clearSelections();
25497 this.el.update("");
25500 o = Roo.util.JSON.decode(response.responseText);
25503 o = o[this.jsonRoot];
25508 * The current JSON data or null
25511 this.beforeRender();
25516 * Get the number of records in the current JSON dataset
25519 getCount : function(){
25520 return this.jsonData ? this.jsonData.length : 0;
25524 * Returns the JSON object for the specified node(s)
25525 * @param {HTMLElement/Array} node The node or an array of nodes
25526 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25527 * you get the JSON object for the node
25529 getNodeData : function(node){
25530 if(node instanceof Array){
25532 for(var i = 0, len = node.length; i < len; i++){
25533 data.push(this.getNodeData(node[i]));
25537 return this.jsonData[this.indexOf(node)] || null;
25540 beforeRender : function(){
25541 this.snapshot = this.jsonData;
25543 this.sort.apply(this, this.sortInfo);
25545 this.fireEvent("beforerender", this, this.jsonData);
25548 onLoad : function(el, o){
25549 this.fireEvent("load", this, this.jsonData, o);
25552 onLoadException : function(el, o){
25553 this.fireEvent("loadexception", this, o);
25557 * Filter the data by a specific property.
25558 * @param {String} property A property on your JSON objects
25559 * @param {String/RegExp} value Either string that the property values
25560 * should start with, or a RegExp to test against the property
25562 filter : function(property, value){
25565 var ss = this.snapshot;
25566 if(typeof value == "string"){
25567 var vlen = value.length;
25569 this.clearFilter();
25572 value = value.toLowerCase();
25573 for(var i = 0, len = ss.length; i < len; i++){
25575 if(o[property].substr(0, vlen).toLowerCase() == value){
25579 } else if(value.exec){ // regex?
25580 for(var i = 0, len = ss.length; i < len; i++){
25582 if(value.test(o[property])){
25589 this.jsonData = data;
25595 * Filter by a function. The passed function will be called with each
25596 * object in the current dataset. If the function returns true the value is kept,
25597 * otherwise it is filtered.
25598 * @param {Function} fn
25599 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25601 filterBy : function(fn, scope){
25604 var ss = this.snapshot;
25605 for(var i = 0, len = ss.length; i < len; i++){
25607 if(fn.call(scope || this, o)){
25611 this.jsonData = data;
25617 * Clears the current filter.
25619 clearFilter : function(){
25620 if(this.snapshot && this.jsonData != this.snapshot){
25621 this.jsonData = this.snapshot;
25628 * Sorts the data for this view and refreshes it.
25629 * @param {String} property A property on your JSON objects to sort on
25630 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25631 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25633 sort : function(property, dir, sortType){
25634 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25637 var dsc = dir && dir.toLowerCase() == "desc";
25638 var f = function(o1, o2){
25639 var v1 = sortType ? sortType(o1[p]) : o1[p];
25640 var v2 = sortType ? sortType(o2[p]) : o2[p];
25643 return dsc ? +1 : -1;
25644 } else if(v1 > v2){
25645 return dsc ? -1 : +1;
25650 this.jsonData.sort(f);
25652 if(this.jsonData != this.snapshot){
25653 this.snapshot.sort(f);
25659 * Ext JS Library 1.1.1
25660 * Copyright(c) 2006-2007, Ext JS, LLC.
25662 * Originally Released Under LGPL - original licence link has changed is not relivant.
25665 * <script type="text/javascript">
25670 * @class Roo.ColorPalette
25671 * @extends Roo.Component
25672 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25673 * Here's an example of typical usage:
25675 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25676 cp.render('my-div');
25678 cp.on('select', function(palette, selColor){
25679 // do something with selColor
25683 * Create a new ColorPalette
25684 * @param {Object} config The config object
25686 Roo.ColorPalette = function(config){
25687 Roo.ColorPalette.superclass.constructor.call(this, config);
25691 * Fires when a color is selected
25692 * @param {ColorPalette} this
25693 * @param {String} color The 6-digit color hex code (without the # symbol)
25699 this.on("select", this.handler, this.scope, true);
25702 Roo.extend(Roo.ColorPalette, Roo.Component, {
25704 * @cfg {String} itemCls
25705 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25707 itemCls : "x-color-palette",
25709 * @cfg {String} value
25710 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25711 * the hex codes are case-sensitive.
25714 clickEvent:'click',
25716 ctype: "Roo.ColorPalette",
25719 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25721 allowReselect : false,
25724 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25725 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25726 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25727 * of colors with the width setting until the box is symmetrical.</p>
25728 * <p>You can override individual colors if needed:</p>
25730 var cp = new Roo.ColorPalette();
25731 cp.colors[0] = "FF0000"; // change the first box to red
25734 Or you can provide a custom array of your own for complete control:
25736 var cp = new Roo.ColorPalette();
25737 cp.colors = ["000000", "993300", "333300"];
25742 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25743 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25744 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25745 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25746 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25750 onRender : function(container, position){
25751 var t = new Roo.MasterTemplate(
25752 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25754 var c = this.colors;
25755 for(var i = 0, len = c.length; i < len; i++){
25758 var el = document.createElement("div");
25759 el.className = this.itemCls;
25761 container.dom.insertBefore(el, position);
25762 this.el = Roo.get(el);
25763 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25764 if(this.clickEvent != 'click'){
25765 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25770 afterRender : function(){
25771 Roo.ColorPalette.superclass.afterRender.call(this);
25773 var s = this.value;
25780 handleClick : function(e, t){
25781 e.preventDefault();
25782 if(!this.disabled){
25783 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25784 this.select(c.toUpperCase());
25789 * Selects the specified color in the palette (fires the select event)
25790 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25792 select : function(color){
25793 color = color.replace("#", "");
25794 if(color != this.value || this.allowReselect){
25797 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25799 el.child("a.color-"+color).addClass("x-color-palette-sel");
25800 this.value = color;
25801 this.fireEvent("select", this, color);
25806 * Ext JS Library 1.1.1
25807 * Copyright(c) 2006-2007, Ext JS, LLC.
25809 * Originally Released Under LGPL - original licence link has changed is not relivant.
25812 * <script type="text/javascript">
25816 * @class Roo.DatePicker
25817 * @extends Roo.Component
25818 * Simple date picker class.
25820 * Create a new DatePicker
25821 * @param {Object} config The config object
25823 Roo.DatePicker = function(config){
25824 Roo.DatePicker.superclass.constructor.call(this, config);
25826 this.value = config && config.value ?
25827 config.value.clearTime() : new Date().clearTime();
25832 * Fires when a date is selected
25833 * @param {DatePicker} this
25834 * @param {Date} date The selected date
25838 * @event monthchange
25839 * Fires when the displayed month changes
25840 * @param {DatePicker} this
25841 * @param {Date} date The selected month
25843 'monthchange': true
25847 this.on("select", this.handler, this.scope || this);
25849 // build the disabledDatesRE
25850 if(!this.disabledDatesRE && this.disabledDates){
25851 var dd = this.disabledDates;
25853 for(var i = 0; i < dd.length; i++){
25855 if(i != dd.length-1) re += "|";
25857 this.disabledDatesRE = new RegExp(re + ")");
25861 Roo.extend(Roo.DatePicker, Roo.Component, {
25863 * @cfg {String} todayText
25864 * The text to display on the button that selects the current date (defaults to "Today")
25866 todayText : "Today",
25868 * @cfg {String} okText
25869 * The text to display on the ok button
25871 okText : " OK ", //   to give the user extra clicking room
25873 * @cfg {String} cancelText
25874 * The text to display on the cancel button
25876 cancelText : "Cancel",
25878 * @cfg {String} todayTip
25879 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25881 todayTip : "{0} (Spacebar)",
25883 * @cfg {Date} minDate
25884 * Minimum allowable date (JavaScript date object, defaults to null)
25888 * @cfg {Date} maxDate
25889 * Maximum allowable date (JavaScript date object, defaults to null)
25893 * @cfg {String} minText
25894 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25896 minText : "This date is before the minimum date",
25898 * @cfg {String} maxText
25899 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25901 maxText : "This date is after the maximum date",
25903 * @cfg {String} format
25904 * The default date format string which can be overriden for localization support. The format must be
25905 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25909 * @cfg {Array} disabledDays
25910 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25912 disabledDays : null,
25914 * @cfg {String} disabledDaysText
25915 * The tooltip to display when the date falls on a disabled day (defaults to "")
25917 disabledDaysText : "",
25919 * @cfg {RegExp} disabledDatesRE
25920 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25922 disabledDatesRE : null,
25924 * @cfg {String} disabledDatesText
25925 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25927 disabledDatesText : "",
25929 * @cfg {Boolean} constrainToViewport
25930 * True to constrain the date picker to the viewport (defaults to true)
25932 constrainToViewport : true,
25934 * @cfg {Array} monthNames
25935 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25937 monthNames : Date.monthNames,
25939 * @cfg {Array} dayNames
25940 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25942 dayNames : Date.dayNames,
25944 * @cfg {String} nextText
25945 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25947 nextText: 'Next Month (Control+Right)',
25949 * @cfg {String} prevText
25950 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25952 prevText: 'Previous Month (Control+Left)',
25954 * @cfg {String} monthYearText
25955 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25957 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25959 * @cfg {Number} startDay
25960 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25964 * @cfg {Bool} showClear
25965 * Show a clear button (usefull for date form elements that can be blank.)
25971 * Sets the value of the date field
25972 * @param {Date} value The date to set
25974 setValue : function(value){
25975 var old = this.value;
25977 if (typeof(value) == 'string') {
25979 value = Date.parseDate(value, this.format);
25982 value = new Date();
25985 this.value = value.clearTime(true);
25987 this.update(this.value);
25992 * Gets the current selected value of the date field
25993 * @return {Date} The selected date
25995 getValue : function(){
26000 focus : function(){
26002 this.update(this.activeDate);
26007 onRender : function(container, position){
26010 '<table cellspacing="0">',
26011 '<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>',
26012 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26013 var dn = this.dayNames;
26014 for(var i = 0; i < 7; i++){
26015 var d = this.startDay+i;
26019 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26021 m[m.length] = "</tr></thead><tbody><tr>";
26022 for(var i = 0; i < 42; i++) {
26023 if(i % 7 == 0 && i != 0){
26024 m[m.length] = "</tr><tr>";
26026 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26028 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26029 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26031 var el = document.createElement("div");
26032 el.className = "x-date-picker";
26033 el.innerHTML = m.join("");
26035 container.dom.insertBefore(el, position);
26037 this.el = Roo.get(el);
26038 this.eventEl = Roo.get(el.firstChild);
26040 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26041 handler: this.showPrevMonth,
26043 preventDefault:true,
26047 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26048 handler: this.showNextMonth,
26050 preventDefault:true,
26054 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26056 this.monthPicker = this.el.down('div.x-date-mp');
26057 this.monthPicker.enableDisplayMode('block');
26059 var kn = new Roo.KeyNav(this.eventEl, {
26060 "left" : function(e){
26062 this.showPrevMonth() :
26063 this.update(this.activeDate.add("d", -1));
26066 "right" : function(e){
26068 this.showNextMonth() :
26069 this.update(this.activeDate.add("d", 1));
26072 "up" : function(e){
26074 this.showNextYear() :
26075 this.update(this.activeDate.add("d", -7));
26078 "down" : function(e){
26080 this.showPrevYear() :
26081 this.update(this.activeDate.add("d", 7));
26084 "pageUp" : function(e){
26085 this.showNextMonth();
26088 "pageDown" : function(e){
26089 this.showPrevMonth();
26092 "enter" : function(e){
26093 e.stopPropagation();
26100 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26102 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26104 this.el.unselectable();
26106 this.cells = this.el.select("table.x-date-inner tbody td");
26107 this.textNodes = this.el.query("table.x-date-inner tbody span");
26109 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26111 tooltip: this.monthYearText
26114 this.mbtn.on('click', this.showMonthPicker, this);
26115 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26118 var today = (new Date()).dateFormat(this.format);
26120 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26121 if (this.showClear) {
26122 baseTb.add( new Roo.Toolbar.Fill());
26125 text: String.format(this.todayText, today),
26126 tooltip: String.format(this.todayTip, today),
26127 handler: this.selectToday,
26131 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26134 if (this.showClear) {
26136 baseTb.add( new Roo.Toolbar.Fill());
26139 cls: 'x-btn-icon x-btn-clear',
26140 handler: function() {
26142 this.fireEvent("select", this, '');
26152 this.update(this.value);
26155 createMonthPicker : function(){
26156 if(!this.monthPicker.dom.firstChild){
26157 var buf = ['<table border="0" cellspacing="0">'];
26158 for(var i = 0; i < 6; i++){
26160 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26161 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26163 '<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>' :
26164 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26168 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26170 '</button><button type="button" class="x-date-mp-cancel">',
26172 '</button></td></tr>',
26175 this.monthPicker.update(buf.join(''));
26176 this.monthPicker.on('click', this.onMonthClick, this);
26177 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26179 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26180 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26182 this.mpMonths.each(function(m, a, i){
26185 m.dom.xmonth = 5 + Math.round(i * .5);
26187 m.dom.xmonth = Math.round((i-1) * .5);
26193 showMonthPicker : function(){
26194 this.createMonthPicker();
26195 var size = this.el.getSize();
26196 this.monthPicker.setSize(size);
26197 this.monthPicker.child('table').setSize(size);
26199 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26200 this.updateMPMonth(this.mpSelMonth);
26201 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26202 this.updateMPYear(this.mpSelYear);
26204 this.monthPicker.slideIn('t', {duration:.2});
26207 updateMPYear : function(y){
26209 var ys = this.mpYears.elements;
26210 for(var i = 1; i <= 10; i++){
26211 var td = ys[i-1], y2;
26213 y2 = y + Math.round(i * .5);
26214 td.firstChild.innerHTML = y2;
26217 y2 = y - (5-Math.round(i * .5));
26218 td.firstChild.innerHTML = y2;
26221 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26225 updateMPMonth : function(sm){
26226 this.mpMonths.each(function(m, a, i){
26227 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26231 selectMPMonth: function(m){
26235 onMonthClick : function(e, t){
26237 var el = new Roo.Element(t), pn;
26238 if(el.is('button.x-date-mp-cancel')){
26239 this.hideMonthPicker();
26241 else if(el.is('button.x-date-mp-ok')){
26242 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26243 this.hideMonthPicker();
26245 else if(pn = el.up('td.x-date-mp-month', 2)){
26246 this.mpMonths.removeClass('x-date-mp-sel');
26247 pn.addClass('x-date-mp-sel');
26248 this.mpSelMonth = pn.dom.xmonth;
26250 else if(pn = el.up('td.x-date-mp-year', 2)){
26251 this.mpYears.removeClass('x-date-mp-sel');
26252 pn.addClass('x-date-mp-sel');
26253 this.mpSelYear = pn.dom.xyear;
26255 else if(el.is('a.x-date-mp-prev')){
26256 this.updateMPYear(this.mpyear-10);
26258 else if(el.is('a.x-date-mp-next')){
26259 this.updateMPYear(this.mpyear+10);
26263 onMonthDblClick : function(e, t){
26265 var el = new Roo.Element(t), pn;
26266 if(pn = el.up('td.x-date-mp-month', 2)){
26267 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26268 this.hideMonthPicker();
26270 else if(pn = el.up('td.x-date-mp-year', 2)){
26271 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26272 this.hideMonthPicker();
26276 hideMonthPicker : function(disableAnim){
26277 if(this.monthPicker){
26278 if(disableAnim === true){
26279 this.monthPicker.hide();
26281 this.monthPicker.slideOut('t', {duration:.2});
26287 showPrevMonth : function(e){
26288 this.update(this.activeDate.add("mo", -1));
26292 showNextMonth : function(e){
26293 this.update(this.activeDate.add("mo", 1));
26297 showPrevYear : function(){
26298 this.update(this.activeDate.add("y", -1));
26302 showNextYear : function(){
26303 this.update(this.activeDate.add("y", 1));
26307 handleMouseWheel : function(e){
26308 var delta = e.getWheelDelta();
26310 this.showPrevMonth();
26312 } else if(delta < 0){
26313 this.showNextMonth();
26319 handleDateClick : function(e, t){
26321 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26322 this.setValue(new Date(t.dateValue));
26323 this.fireEvent("select", this, this.value);
26328 selectToday : function(){
26329 this.setValue(new Date().clearTime());
26330 this.fireEvent("select", this, this.value);
26334 update : function(date)
26336 var vd = this.activeDate;
26337 this.activeDate = date;
26339 var t = date.getTime();
26340 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26341 this.cells.removeClass("x-date-selected");
26342 this.cells.each(function(c){
26343 if(c.dom.firstChild.dateValue == t){
26344 c.addClass("x-date-selected");
26345 setTimeout(function(){
26346 try{c.dom.firstChild.focus();}catch(e){}
26355 var days = date.getDaysInMonth();
26356 var firstOfMonth = date.getFirstDateOfMonth();
26357 var startingPos = firstOfMonth.getDay()-this.startDay;
26359 if(startingPos <= this.startDay){
26363 var pm = date.add("mo", -1);
26364 var prevStart = pm.getDaysInMonth()-startingPos;
26366 var cells = this.cells.elements;
26367 var textEls = this.textNodes;
26368 days += startingPos;
26370 // convert everything to numbers so it's fast
26371 var day = 86400000;
26372 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26373 var today = new Date().clearTime().getTime();
26374 var sel = date.clearTime().getTime();
26375 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26376 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26377 var ddMatch = this.disabledDatesRE;
26378 var ddText = this.disabledDatesText;
26379 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26380 var ddaysText = this.disabledDaysText;
26381 var format = this.format;
26383 var setCellClass = function(cal, cell){
26385 var t = d.getTime();
26386 cell.firstChild.dateValue = t;
26388 cell.className += " x-date-today";
26389 cell.title = cal.todayText;
26392 cell.className += " x-date-selected";
26393 setTimeout(function(){
26394 try{cell.firstChild.focus();}catch(e){}
26399 cell.className = " x-date-disabled";
26400 cell.title = cal.minText;
26404 cell.className = " x-date-disabled";
26405 cell.title = cal.maxText;
26409 if(ddays.indexOf(d.getDay()) != -1){
26410 cell.title = ddaysText;
26411 cell.className = " x-date-disabled";
26414 if(ddMatch && format){
26415 var fvalue = d.dateFormat(format);
26416 if(ddMatch.test(fvalue)){
26417 cell.title = ddText.replace("%0", fvalue);
26418 cell.className = " x-date-disabled";
26424 for(; i < startingPos; i++) {
26425 textEls[i].innerHTML = (++prevStart);
26426 d.setDate(d.getDate()+1);
26427 cells[i].className = "x-date-prevday";
26428 setCellClass(this, cells[i]);
26430 for(; i < days; i++){
26431 intDay = i - startingPos + 1;
26432 textEls[i].innerHTML = (intDay);
26433 d.setDate(d.getDate()+1);
26434 cells[i].className = "x-date-active";
26435 setCellClass(this, cells[i]);
26438 for(; i < 42; i++) {
26439 textEls[i].innerHTML = (++extraDays);
26440 d.setDate(d.getDate()+1);
26441 cells[i].className = "x-date-nextday";
26442 setCellClass(this, cells[i]);
26445 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26446 this.fireEvent('monthchange', this, date);
26448 if(!this.internalRender){
26449 var main = this.el.dom.firstChild;
26450 var w = main.offsetWidth;
26451 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26452 Roo.fly(main).setWidth(w);
26453 this.internalRender = true;
26454 // opera does not respect the auto grow header center column
26455 // then, after it gets a width opera refuses to recalculate
26456 // without a second pass
26457 if(Roo.isOpera && !this.secondPass){
26458 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26459 this.secondPass = true;
26460 this.update.defer(10, this, [date]);
26468 * Ext JS Library 1.1.1
26469 * Copyright(c) 2006-2007, Ext JS, LLC.
26471 * Originally Released Under LGPL - original licence link has changed is not relivant.
26474 * <script type="text/javascript">
26477 * @class Roo.TabPanel
26478 * @extends Roo.util.Observable
26479 * A lightweight tab container.
26483 // basic tabs 1, built from existing content
26484 var tabs = new Roo.TabPanel("tabs1");
26485 tabs.addTab("script", "View Script");
26486 tabs.addTab("markup", "View Markup");
26487 tabs.activate("script");
26489 // more advanced tabs, built from javascript
26490 var jtabs = new Roo.TabPanel("jtabs");
26491 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26493 // set up the UpdateManager
26494 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26495 var updater = tab2.getUpdateManager();
26496 updater.setDefaultUrl("ajax1.htm");
26497 tab2.on('activate', updater.refresh, updater, true);
26499 // Use setUrl for Ajax loading
26500 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26501 tab3.setUrl("ajax2.htm", null, true);
26504 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26507 jtabs.activate("jtabs-1");
26510 * Create a new TabPanel.
26511 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26512 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26514 Roo.TabPanel = function(container, config){
26516 * The container element for this TabPanel.
26517 * @type Roo.Element
26519 this.el = Roo.get(container, true);
26521 if(typeof config == "boolean"){
26522 this.tabPosition = config ? "bottom" : "top";
26524 Roo.apply(this, config);
26527 if(this.tabPosition == "bottom"){
26528 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26529 this.el.addClass("x-tabs-bottom");
26531 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26532 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26533 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26535 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26537 if(this.tabPosition != "bottom"){
26538 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26539 * @type Roo.Element
26541 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26542 this.el.addClass("x-tabs-top");
26546 this.bodyEl.setStyle("position", "relative");
26548 this.active = null;
26549 this.activateDelegate = this.activate.createDelegate(this);
26554 * Fires when the active tab changes
26555 * @param {Roo.TabPanel} this
26556 * @param {Roo.TabPanelItem} activePanel The new active tab
26560 * @event beforetabchange
26561 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26562 * @param {Roo.TabPanel} this
26563 * @param {Object} e Set cancel to true on this object to cancel the tab change
26564 * @param {Roo.TabPanelItem} tab The tab being changed to
26566 "beforetabchange" : true
26569 Roo.EventManager.onWindowResize(this.onResize, this);
26570 this.cpad = this.el.getPadding("lr");
26571 this.hiddenCount = 0;
26574 // toolbar on the tabbar support...
26575 if (this.toolbar) {
26576 var tcfg = this.toolbar;
26577 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26578 this.toolbar = new Roo.Toolbar(tcfg);
26579 if (Roo.isSafari) {
26580 var tbl = tcfg.container.child('table', true);
26581 tbl.setAttribute('width', '100%');
26588 Roo.TabPanel.superclass.constructor.call(this);
26591 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26593 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26595 tabPosition : "top",
26597 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26599 currentTabWidth : 0,
26601 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26605 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26609 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26611 preferredTabWidth : 175,
26613 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26615 resizeTabs : false,
26617 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26619 monitorResize : true,
26621 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26626 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26627 * @param {String} id The id of the div to use <b>or create</b>
26628 * @param {String} text The text for the tab
26629 * @param {String} content (optional) Content to put in the TabPanelItem body
26630 * @param {Boolean} closable (optional) True to create a close icon on the tab
26631 * @return {Roo.TabPanelItem} The created TabPanelItem
26633 addTab : function(id, text, content, closable){
26634 var item = new Roo.TabPanelItem(this, id, text, closable);
26635 this.addTabItem(item);
26637 item.setContent(content);
26643 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26644 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26645 * @return {Roo.TabPanelItem}
26647 getTab : function(id){
26648 return this.items[id];
26652 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26653 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26655 hideTab : function(id){
26656 var t = this.items[id];
26659 this.hiddenCount++;
26660 this.autoSizeTabs();
26665 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26666 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26668 unhideTab : function(id){
26669 var t = this.items[id];
26671 t.setHidden(false);
26672 this.hiddenCount--;
26673 this.autoSizeTabs();
26678 * Adds an existing {@link Roo.TabPanelItem}.
26679 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26681 addTabItem : function(item){
26682 this.items[item.id] = item;
26683 this.items.push(item);
26684 if(this.resizeTabs){
26685 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26686 this.autoSizeTabs();
26693 * Removes a {@link Roo.TabPanelItem}.
26694 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26696 removeTab : function(id){
26697 var items = this.items;
26698 var tab = items[id];
26699 if(!tab) { return; }
26700 var index = items.indexOf(tab);
26701 if(this.active == tab && items.length > 1){
26702 var newTab = this.getNextAvailable(index);
26707 this.stripEl.dom.removeChild(tab.pnode.dom);
26708 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26709 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26711 items.splice(index, 1);
26712 delete this.items[tab.id];
26713 tab.fireEvent("close", tab);
26714 tab.purgeListeners();
26715 this.autoSizeTabs();
26718 getNextAvailable : function(start){
26719 var items = this.items;
26721 // look for a next tab that will slide over to
26722 // replace the one being removed
26723 while(index < items.length){
26724 var item = items[++index];
26725 if(item && !item.isHidden()){
26729 // if one isn't found select the previous tab (on the left)
26732 var item = items[--index];
26733 if(item && !item.isHidden()){
26741 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26742 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26744 disableTab : function(id){
26745 var tab = this.items[id];
26746 if(tab && this.active != tab){
26752 * Enables a {@link Roo.TabPanelItem} that is disabled.
26753 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26755 enableTab : function(id){
26756 var tab = this.items[id];
26761 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26762 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26763 * @return {Roo.TabPanelItem} The TabPanelItem.
26765 activate : function(id){
26766 var tab = this.items[id];
26770 if(tab == this.active || tab.disabled){
26774 this.fireEvent("beforetabchange", this, e, tab);
26775 if(e.cancel !== true && !tab.disabled){
26777 this.active.hide();
26779 this.active = this.items[id];
26780 this.active.show();
26781 this.fireEvent("tabchange", this, this.active);
26787 * Gets the active {@link Roo.TabPanelItem}.
26788 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26790 getActiveTab : function(){
26791 return this.active;
26795 * Updates the tab body element to fit the height of the container element
26796 * for overflow scrolling
26797 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26799 syncHeight : function(targetHeight){
26800 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26801 var bm = this.bodyEl.getMargins();
26802 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26803 this.bodyEl.setHeight(newHeight);
26807 onResize : function(){
26808 if(this.monitorResize){
26809 this.autoSizeTabs();
26814 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26816 beginUpdate : function(){
26817 this.updating = true;
26821 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26823 endUpdate : function(){
26824 this.updating = false;
26825 this.autoSizeTabs();
26829 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26831 autoSizeTabs : function(){
26832 var count = this.items.length;
26833 var vcount = count - this.hiddenCount;
26834 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26835 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26836 var availWidth = Math.floor(w / vcount);
26837 var b = this.stripBody;
26838 if(b.getWidth() > w){
26839 var tabs = this.items;
26840 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26841 if(availWidth < this.minTabWidth){
26842 /*if(!this.sleft){ // incomplete scrolling code
26843 this.createScrollButtons();
26846 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26849 if(this.currentTabWidth < this.preferredTabWidth){
26850 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26856 * Returns the number of tabs in this TabPanel.
26859 getCount : function(){
26860 return this.items.length;
26864 * Resizes all the tabs to the passed width
26865 * @param {Number} The new width
26867 setTabWidth : function(width){
26868 this.currentTabWidth = width;
26869 for(var i = 0, len = this.items.length; i < len; i++) {
26870 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26875 * Destroys this TabPanel
26876 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26878 destroy : function(removeEl){
26879 Roo.EventManager.removeResizeListener(this.onResize, this);
26880 for(var i = 0, len = this.items.length; i < len; i++){
26881 this.items[i].purgeListeners();
26883 if(removeEl === true){
26884 this.el.update("");
26891 * @class Roo.TabPanelItem
26892 * @extends Roo.util.Observable
26893 * Represents an individual item (tab plus body) in a TabPanel.
26894 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26895 * @param {String} id The id of this TabPanelItem
26896 * @param {String} text The text for the tab of this TabPanelItem
26897 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26899 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26901 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26902 * @type Roo.TabPanel
26904 this.tabPanel = tabPanel;
26906 * The id for this TabPanelItem
26911 this.disabled = false;
26915 this.loaded = false;
26916 this.closable = closable;
26919 * The body element for this TabPanelItem.
26920 * @type Roo.Element
26922 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26923 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26924 this.bodyEl.setStyle("display", "block");
26925 this.bodyEl.setStyle("zoom", "1");
26928 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26930 this.el = Roo.get(els.el, true);
26931 this.inner = Roo.get(els.inner, true);
26932 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26933 this.pnode = Roo.get(els.el.parentNode, true);
26934 this.el.on("mousedown", this.onTabMouseDown, this);
26935 this.el.on("click", this.onTabClick, this);
26938 var c = Roo.get(els.close, true);
26939 c.dom.title = this.closeText;
26940 c.addClassOnOver("close-over");
26941 c.on("click", this.closeClick, this);
26947 * Fires when this tab becomes the active tab.
26948 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26949 * @param {Roo.TabPanelItem} this
26953 * @event beforeclose
26954 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26955 * @param {Roo.TabPanelItem} this
26956 * @param {Object} e Set cancel to true on this object to cancel the close.
26958 "beforeclose": true,
26961 * Fires when this tab is closed.
26962 * @param {Roo.TabPanelItem} this
26966 * @event deactivate
26967 * Fires when this tab is no longer the active tab.
26968 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26969 * @param {Roo.TabPanelItem} this
26971 "deactivate" : true
26973 this.hidden = false;
26975 Roo.TabPanelItem.superclass.constructor.call(this);
26978 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
26979 purgeListeners : function(){
26980 Roo.util.Observable.prototype.purgeListeners.call(this);
26981 this.el.removeAllListeners();
26984 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
26987 this.pnode.addClass("on");
26990 this.tabPanel.stripWrap.repaint();
26992 this.fireEvent("activate", this.tabPanel, this);
26996 * Returns true if this tab is the active tab.
26997 * @return {Boolean}
26999 isActive : function(){
27000 return this.tabPanel.getActiveTab() == this;
27004 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27007 this.pnode.removeClass("on");
27009 this.fireEvent("deactivate", this.tabPanel, this);
27012 hideAction : function(){
27013 this.bodyEl.hide();
27014 this.bodyEl.setStyle("position", "absolute");
27015 this.bodyEl.setLeft("-20000px");
27016 this.bodyEl.setTop("-20000px");
27019 showAction : function(){
27020 this.bodyEl.setStyle("position", "relative");
27021 this.bodyEl.setTop("");
27022 this.bodyEl.setLeft("");
27023 this.bodyEl.show();
27027 * Set the tooltip for the tab.
27028 * @param {String} tooltip The tab's tooltip
27030 setTooltip : function(text){
27031 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27032 this.textEl.dom.qtip = text;
27033 this.textEl.dom.removeAttribute('title');
27035 this.textEl.dom.title = text;
27039 onTabClick : function(e){
27040 e.preventDefault();
27041 this.tabPanel.activate(this.id);
27044 onTabMouseDown : function(e){
27045 e.preventDefault();
27046 this.tabPanel.activate(this.id);
27049 getWidth : function(){
27050 return this.inner.getWidth();
27053 setWidth : function(width){
27054 var iwidth = width - this.pnode.getPadding("lr");
27055 this.inner.setWidth(iwidth);
27056 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27057 this.pnode.setWidth(width);
27061 * Show or hide the tab
27062 * @param {Boolean} hidden True to hide or false to show.
27064 setHidden : function(hidden){
27065 this.hidden = hidden;
27066 this.pnode.setStyle("display", hidden ? "none" : "");
27070 * Returns true if this tab is "hidden"
27071 * @return {Boolean}
27073 isHidden : function(){
27074 return this.hidden;
27078 * Returns the text for this tab
27081 getText : function(){
27085 autoSize : function(){
27086 //this.el.beginMeasure();
27087 this.textEl.setWidth(1);
27088 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27089 //this.el.endMeasure();
27093 * Sets the text for the tab (Note: this also sets the tooltip text)
27094 * @param {String} text The tab's text and tooltip
27096 setText : function(text){
27098 this.textEl.update(text);
27099 this.setTooltip(text);
27100 if(!this.tabPanel.resizeTabs){
27105 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27107 activate : function(){
27108 this.tabPanel.activate(this.id);
27112 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27114 disable : function(){
27115 if(this.tabPanel.active != this){
27116 this.disabled = true;
27117 this.pnode.addClass("disabled");
27122 * Enables this TabPanelItem if it was previously disabled.
27124 enable : function(){
27125 this.disabled = false;
27126 this.pnode.removeClass("disabled");
27130 * Sets the content for this TabPanelItem.
27131 * @param {String} content The content
27132 * @param {Boolean} loadScripts true to look for and load scripts
27134 setContent : function(content, loadScripts){
27135 this.bodyEl.update(content, loadScripts);
27139 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27140 * @return {Roo.UpdateManager} The UpdateManager
27142 getUpdateManager : function(){
27143 return this.bodyEl.getUpdateManager();
27147 * Set a URL to be used to load the content for this TabPanelItem.
27148 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27149 * @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)
27150 * @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)
27151 * @return {Roo.UpdateManager} The UpdateManager
27153 setUrl : function(url, params, loadOnce){
27154 if(this.refreshDelegate){
27155 this.un('activate', this.refreshDelegate);
27157 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27158 this.on("activate", this.refreshDelegate);
27159 return this.bodyEl.getUpdateManager();
27163 _handleRefresh : function(url, params, loadOnce){
27164 if(!loadOnce || !this.loaded){
27165 var updater = this.bodyEl.getUpdateManager();
27166 updater.update(url, params, this._setLoaded.createDelegate(this));
27171 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27172 * Will fail silently if the setUrl method has not been called.
27173 * This does not activate the panel, just updates its content.
27175 refresh : function(){
27176 if(this.refreshDelegate){
27177 this.loaded = false;
27178 this.refreshDelegate();
27183 _setLoaded : function(){
27184 this.loaded = true;
27188 closeClick : function(e){
27191 this.fireEvent("beforeclose", this, o);
27192 if(o.cancel !== true){
27193 this.tabPanel.removeTab(this.id);
27197 * The text displayed in the tooltip for the close icon.
27200 closeText : "Close this tab"
27204 Roo.TabPanel.prototype.createStrip = function(container){
27205 var strip = document.createElement("div");
27206 strip.className = "x-tabs-wrap";
27207 container.appendChild(strip);
27211 Roo.TabPanel.prototype.createStripList = function(strip){
27212 // div wrapper for retard IE
27213 // returns the "tr" element.
27214 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27215 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27216 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27217 return strip.firstChild.firstChild.firstChild.firstChild;
27220 Roo.TabPanel.prototype.createBody = function(container){
27221 var body = document.createElement("div");
27222 Roo.id(body, "tab-body");
27223 Roo.fly(body).addClass("x-tabs-body");
27224 container.appendChild(body);
27228 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27229 var body = Roo.getDom(id);
27231 body = document.createElement("div");
27234 Roo.fly(body).addClass("x-tabs-item-body");
27235 bodyEl.insertBefore(body, bodyEl.firstChild);
27239 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27240 var td = document.createElement("td");
27241 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27242 //stripEl.appendChild(td);
27244 td.className = "x-tabs-closable";
27245 if(!this.closeTpl){
27246 this.closeTpl = new Roo.Template(
27247 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27248 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27249 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27252 var el = this.closeTpl.overwrite(td, {"text": text});
27253 var close = el.getElementsByTagName("div")[0];
27254 var inner = el.getElementsByTagName("em")[0];
27255 return {"el": el, "close": close, "inner": inner};
27258 this.tabTpl = new Roo.Template(
27259 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27260 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27263 var el = this.tabTpl.overwrite(td, {"text": text});
27264 var inner = el.getElementsByTagName("em")[0];
27265 return {"el": el, "inner": inner};
27269 * Ext JS Library 1.1.1
27270 * Copyright(c) 2006-2007, Ext JS, LLC.
27272 * Originally Released Under LGPL - original licence link has changed is not relivant.
27275 * <script type="text/javascript">
27279 * @class Roo.Button
27280 * @extends Roo.util.Observable
27281 * Simple Button class
27282 * @cfg {String} text The button text
27283 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27284 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27285 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27286 * @cfg {Object} scope The scope of the handler
27287 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27288 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27289 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27290 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27291 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27292 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27293 applies if enableToggle = true)
27294 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27295 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27296 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27298 * Create a new button
27299 * @param {Object} config The config object
27301 Roo.Button = function(renderTo, config)
27305 renderTo = config.renderTo || false;
27308 Roo.apply(this, config);
27312 * Fires when this button is clicked
27313 * @param {Button} this
27314 * @param {EventObject} e The click event
27319 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27320 * @param {Button} this
27321 * @param {Boolean} pressed
27326 * Fires when the mouse hovers over the button
27327 * @param {Button} this
27328 * @param {Event} e The event object
27330 'mouseover' : true,
27333 * Fires when the mouse exits the button
27334 * @param {Button} this
27335 * @param {Event} e The event object
27340 * Fires when the button is rendered
27341 * @param {Button} this
27346 this.menu = Roo.menu.MenuMgr.get(this.menu);
27348 // register listeners first!! - so render can be captured..
27349 Roo.util.Observable.call(this);
27351 this.render(renderTo);
27357 Roo.extend(Roo.Button, Roo.util.Observable, {
27363 * Read-only. True if this button is hidden
27368 * Read-only. True if this button is disabled
27373 * Read-only. True if this button is pressed (only if enableToggle = true)
27379 * @cfg {Number} tabIndex
27380 * The DOM tabIndex for this button (defaults to undefined)
27382 tabIndex : undefined,
27385 * @cfg {Boolean} enableToggle
27386 * True to enable pressed/not pressed toggling (defaults to false)
27388 enableToggle: false,
27390 * @cfg {Mixed} menu
27391 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27395 * @cfg {String} menuAlign
27396 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27398 menuAlign : "tl-bl?",
27401 * @cfg {String} iconCls
27402 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27404 iconCls : undefined,
27406 * @cfg {String} type
27407 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27412 menuClassTarget: 'tr',
27415 * @cfg {String} clickEvent
27416 * The type of event to map to the button's event handler (defaults to 'click')
27418 clickEvent : 'click',
27421 * @cfg {Boolean} handleMouseEvents
27422 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27424 handleMouseEvents : true,
27427 * @cfg {String} tooltipType
27428 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27430 tooltipType : 'qtip',
27433 * @cfg {String} cls
27434 * A CSS class to apply to the button's main element.
27438 * @cfg {Roo.Template} template (Optional)
27439 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27440 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27441 * require code modifications if required elements (e.g. a button) aren't present.
27445 render : function(renderTo){
27447 if(this.hideParent){
27448 this.parentEl = Roo.get(renderTo);
27450 if(!this.dhconfig){
27451 if(!this.template){
27452 if(!Roo.Button.buttonTemplate){
27453 // hideous table template
27454 Roo.Button.buttonTemplate = new Roo.Template(
27455 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27456 '<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>',
27457 "</tr></tbody></table>");
27459 this.template = Roo.Button.buttonTemplate;
27461 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27462 var btnEl = btn.child("button:first");
27463 btnEl.on('focus', this.onFocus, this);
27464 btnEl.on('blur', this.onBlur, this);
27466 btn.addClass(this.cls);
27469 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27472 btnEl.addClass(this.iconCls);
27474 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27477 if(this.tabIndex !== undefined){
27478 btnEl.dom.tabIndex = this.tabIndex;
27481 if(typeof this.tooltip == 'object'){
27482 Roo.QuickTips.tips(Roo.apply({
27486 btnEl.dom[this.tooltipType] = this.tooltip;
27490 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27494 this.el.dom.id = this.el.id = this.id;
27497 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27498 this.menu.on("show", this.onMenuShow, this);
27499 this.menu.on("hide", this.onMenuHide, this);
27501 btn.addClass("x-btn");
27502 if(Roo.isIE && !Roo.isIE7){
27503 this.autoWidth.defer(1, this);
27507 if(this.handleMouseEvents){
27508 btn.on("mouseover", this.onMouseOver, this);
27509 btn.on("mouseout", this.onMouseOut, this);
27510 btn.on("mousedown", this.onMouseDown, this);
27512 btn.on(this.clickEvent, this.onClick, this);
27513 //btn.on("mouseup", this.onMouseUp, this);
27520 Roo.ButtonToggleMgr.register(this);
27522 this.el.addClass("x-btn-pressed");
27525 var repeater = new Roo.util.ClickRepeater(btn,
27526 typeof this.repeat == "object" ? this.repeat : {}
27528 repeater.on("click", this.onClick, this);
27531 this.fireEvent('render', this);
27535 * Returns the button's underlying element
27536 * @return {Roo.Element} The element
27538 getEl : function(){
27543 * Destroys this Button and removes any listeners.
27545 destroy : function(){
27546 Roo.ButtonToggleMgr.unregister(this);
27547 this.el.removeAllListeners();
27548 this.purgeListeners();
27553 autoWidth : function(){
27555 this.el.setWidth("auto");
27556 if(Roo.isIE7 && Roo.isStrict){
27557 var ib = this.el.child('button');
27558 if(ib && ib.getWidth() > 20){
27560 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27565 this.el.beginMeasure();
27567 if(this.el.getWidth() < this.minWidth){
27568 this.el.setWidth(this.minWidth);
27571 this.el.endMeasure();
27578 * Assigns this button's click handler
27579 * @param {Function} handler The function to call when the button is clicked
27580 * @param {Object} scope (optional) Scope for the function passed in
27582 setHandler : function(handler, scope){
27583 this.handler = handler;
27584 this.scope = scope;
27588 * Sets this button's text
27589 * @param {String} text The button text
27591 setText : function(text){
27594 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27600 * Gets the text for this button
27601 * @return {String} The button text
27603 getText : function(){
27611 this.hidden = false;
27613 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27621 this.hidden = true;
27623 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27628 * Convenience function for boolean show/hide
27629 * @param {Boolean} visible True to show, false to hide
27631 setVisible: function(visible){
27640 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27641 * @param {Boolean} state (optional) Force a particular state
27643 toggle : function(state){
27644 state = state === undefined ? !this.pressed : state;
27645 if(state != this.pressed){
27647 this.el.addClass("x-btn-pressed");
27648 this.pressed = true;
27649 this.fireEvent("toggle", this, true);
27651 this.el.removeClass("x-btn-pressed");
27652 this.pressed = false;
27653 this.fireEvent("toggle", this, false);
27655 if(this.toggleHandler){
27656 this.toggleHandler.call(this.scope || this, this, state);
27664 focus : function(){
27665 this.el.child('button:first').focus();
27669 * Disable this button
27671 disable : function(){
27673 this.el.addClass("x-btn-disabled");
27675 this.disabled = true;
27679 * Enable this button
27681 enable : function(){
27683 this.el.removeClass("x-btn-disabled");
27685 this.disabled = false;
27689 * Convenience function for boolean enable/disable
27690 * @param {Boolean} enabled True to enable, false to disable
27692 setDisabled : function(v){
27693 this[v !== true ? "enable" : "disable"]();
27697 onClick : function(e){
27699 e.preventDefault();
27704 if(!this.disabled){
27705 if(this.enableToggle){
27708 if(this.menu && !this.menu.isVisible()){
27709 this.menu.show(this.el, this.menuAlign);
27711 this.fireEvent("click", this, e);
27713 this.el.removeClass("x-btn-over");
27714 this.handler.call(this.scope || this, this, e);
27719 onMouseOver : function(e){
27720 if(!this.disabled){
27721 this.el.addClass("x-btn-over");
27722 this.fireEvent('mouseover', this, e);
27726 onMouseOut : function(e){
27727 if(!e.within(this.el, true)){
27728 this.el.removeClass("x-btn-over");
27729 this.fireEvent('mouseout', this, e);
27733 onFocus : function(e){
27734 if(!this.disabled){
27735 this.el.addClass("x-btn-focus");
27739 onBlur : function(e){
27740 this.el.removeClass("x-btn-focus");
27743 onMouseDown : function(e){
27744 if(!this.disabled && e.button == 0){
27745 this.el.addClass("x-btn-click");
27746 Roo.get(document).on('mouseup', this.onMouseUp, this);
27750 onMouseUp : function(e){
27752 this.el.removeClass("x-btn-click");
27753 Roo.get(document).un('mouseup', this.onMouseUp, this);
27757 onMenuShow : function(e){
27758 this.el.addClass("x-btn-menu-active");
27761 onMenuHide : function(e){
27762 this.el.removeClass("x-btn-menu-active");
27766 // Private utility class used by Button
27767 Roo.ButtonToggleMgr = function(){
27770 function toggleGroup(btn, state){
27772 var g = groups[btn.toggleGroup];
27773 for(var i = 0, l = g.length; i < l; i++){
27775 g[i].toggle(false);
27782 register : function(btn){
27783 if(!btn.toggleGroup){
27786 var g = groups[btn.toggleGroup];
27788 g = groups[btn.toggleGroup] = [];
27791 btn.on("toggle", toggleGroup);
27794 unregister : function(btn){
27795 if(!btn.toggleGroup){
27798 var g = groups[btn.toggleGroup];
27801 btn.un("toggle", toggleGroup);
27807 * Ext JS Library 1.1.1
27808 * Copyright(c) 2006-2007, Ext JS, LLC.
27810 * Originally Released Under LGPL - original licence link has changed is not relivant.
27813 * <script type="text/javascript">
27817 * @class Roo.SplitButton
27818 * @extends Roo.Button
27819 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27820 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27821 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27822 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27823 * @cfg {String} arrowTooltip The title attribute of the arrow
27825 * Create a new menu button
27826 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27827 * @param {Object} config The config object
27829 Roo.SplitButton = function(renderTo, config){
27830 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27832 * @event arrowclick
27833 * Fires when this button's arrow is clicked
27834 * @param {SplitButton} this
27835 * @param {EventObject} e The click event
27837 this.addEvents({"arrowclick":true});
27840 Roo.extend(Roo.SplitButton, Roo.Button, {
27841 render : function(renderTo){
27842 // this is one sweet looking template!
27843 var tpl = new Roo.Template(
27844 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27845 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27846 '<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>',
27847 "</tbody></table></td><td>",
27848 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27849 '<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>',
27850 "</tbody></table></td></tr></table>"
27852 var btn = tpl.append(renderTo, [this.text, this.type], true);
27853 var btnEl = btn.child("button");
27855 btn.addClass(this.cls);
27858 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27861 btnEl.addClass(this.iconCls);
27863 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27867 if(this.handleMouseEvents){
27868 btn.on("mouseover", this.onMouseOver, this);
27869 btn.on("mouseout", this.onMouseOut, this);
27870 btn.on("mousedown", this.onMouseDown, this);
27871 btn.on("mouseup", this.onMouseUp, this);
27873 btn.on(this.clickEvent, this.onClick, this);
27875 if(typeof this.tooltip == 'object'){
27876 Roo.QuickTips.tips(Roo.apply({
27880 btnEl.dom[this.tooltipType] = this.tooltip;
27883 if(this.arrowTooltip){
27884 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27893 this.el.addClass("x-btn-pressed");
27895 if(Roo.isIE && !Roo.isIE7){
27896 this.autoWidth.defer(1, this);
27901 this.menu.on("show", this.onMenuShow, this);
27902 this.menu.on("hide", this.onMenuHide, this);
27904 this.fireEvent('render', this);
27908 autoWidth : function(){
27910 var tbl = this.el.child("table:first");
27911 var tbl2 = this.el.child("table:last");
27912 this.el.setWidth("auto");
27913 tbl.setWidth("auto");
27914 if(Roo.isIE7 && Roo.isStrict){
27915 var ib = this.el.child('button:first');
27916 if(ib && ib.getWidth() > 20){
27918 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27923 this.el.beginMeasure();
27925 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27926 tbl.setWidth(this.minWidth-tbl2.getWidth());
27929 this.el.endMeasure();
27932 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27936 * Sets this button's click handler
27937 * @param {Function} handler The function to call when the button is clicked
27938 * @param {Object} scope (optional) Scope for the function passed above
27940 setHandler : function(handler, scope){
27941 this.handler = handler;
27942 this.scope = scope;
27946 * Sets this button's arrow click handler
27947 * @param {Function} handler The function to call when the arrow is clicked
27948 * @param {Object} scope (optional) Scope for the function passed above
27950 setArrowHandler : function(handler, scope){
27951 this.arrowHandler = handler;
27952 this.scope = scope;
27958 focus : function(){
27960 this.el.child("button:first").focus();
27965 onClick : function(e){
27966 e.preventDefault();
27967 if(!this.disabled){
27968 if(e.getTarget(".x-btn-menu-arrow-wrap")){
27969 if(this.menu && !this.menu.isVisible()){
27970 this.menu.show(this.el, this.menuAlign);
27972 this.fireEvent("arrowclick", this, e);
27973 if(this.arrowHandler){
27974 this.arrowHandler.call(this.scope || this, this, e);
27977 this.fireEvent("click", this, e);
27979 this.handler.call(this.scope || this, this, e);
27985 onMouseDown : function(e){
27986 if(!this.disabled){
27987 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
27991 onMouseUp : function(e){
27992 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
27997 // backwards compat
27998 Roo.MenuButton = Roo.SplitButton;/*
28000 * Ext JS Library 1.1.1
28001 * Copyright(c) 2006-2007, Ext JS, LLC.
28003 * Originally Released Under LGPL - original licence link has changed is not relivant.
28006 * <script type="text/javascript">
28010 * @class Roo.Toolbar
28011 * Basic Toolbar class.
28013 * Creates a new Toolbar
28014 * @param {Object} container The config object
28016 Roo.Toolbar = function(container, buttons, config)
28018 /// old consturctor format still supported..
28019 if(container instanceof Array){ // omit the container for later rendering
28020 buttons = container;
28024 if (typeof(container) == 'object' && container.xtype) {
28025 config = container;
28026 container = config.container;
28027 buttons = config.buttons || []; // not really - use items!!
28030 if (config && config.items) {
28031 xitems = config.items;
28032 delete config.items;
28034 Roo.apply(this, config);
28035 this.buttons = buttons;
28038 this.render(container);
28040 this.xitems = xitems;
28041 Roo.each(xitems, function(b) {
28047 Roo.Toolbar.prototype = {
28049 * @cfg {Array} items
28050 * array of button configs or elements to add (will be converted to a MixedCollection)
28054 * @cfg {String/HTMLElement/Element} container
28055 * The id or element that will contain the toolbar
28058 render : function(ct){
28059 this.el = Roo.get(ct);
28061 this.el.addClass(this.cls);
28063 // using a table allows for vertical alignment
28064 // 100% width is needed by Safari...
28065 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28066 this.tr = this.el.child("tr", true);
28068 this.items = new Roo.util.MixedCollection(false, function(o){
28069 return o.id || ("item" + (++autoId));
28072 this.add.apply(this, this.buttons);
28073 delete this.buttons;
28078 * Adds element(s) to the toolbar -- this function takes a variable number of
28079 * arguments of mixed type and adds them to the toolbar.
28080 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28082 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28083 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28084 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28085 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28086 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28087 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28088 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28089 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28090 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28092 * @param {Mixed} arg2
28093 * @param {Mixed} etc.
28096 var a = arguments, l = a.length;
28097 for(var i = 0; i < l; i++){
28102 _add : function(el) {
28105 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28108 if (el.applyTo){ // some kind of form field
28109 return this.addField(el);
28111 if (el.render){ // some kind of Toolbar.Item
28112 return this.addItem(el);
28114 if (typeof el == "string"){ // string
28115 if(el == "separator" || el == "-"){
28116 return this.addSeparator();
28119 return this.addSpacer();
28122 return this.addFill();
28124 return this.addText(el);
28127 if(el.tagName){ // element
28128 return this.addElement(el);
28130 if(typeof el == "object"){ // must be button config?
28131 return this.addButton(el);
28133 // and now what?!?!
28139 * Add an Xtype element
28140 * @param {Object} xtype Xtype Object
28141 * @return {Object} created Object
28143 addxtype : function(e){
28144 return this.add(e);
28148 * Returns the Element for this toolbar.
28149 * @return {Roo.Element}
28151 getEl : function(){
28157 * @return {Roo.Toolbar.Item} The separator item
28159 addSeparator : function(){
28160 return this.addItem(new Roo.Toolbar.Separator());
28164 * Adds a spacer element
28165 * @return {Roo.Toolbar.Spacer} The spacer item
28167 addSpacer : function(){
28168 return this.addItem(new Roo.Toolbar.Spacer());
28172 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28173 * @return {Roo.Toolbar.Fill} The fill item
28175 addFill : function(){
28176 return this.addItem(new Roo.Toolbar.Fill());
28180 * Adds any standard HTML element to the toolbar
28181 * @param {String/HTMLElement/Element} el The element or id of the element to add
28182 * @return {Roo.Toolbar.Item} The element's item
28184 addElement : function(el){
28185 return this.addItem(new Roo.Toolbar.Item(el));
28188 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28189 * @type Roo.util.MixedCollection
28194 * Adds any Toolbar.Item or subclass
28195 * @param {Roo.Toolbar.Item} item
28196 * @return {Roo.Toolbar.Item} The item
28198 addItem : function(item){
28199 var td = this.nextBlock();
28201 this.items.add(item);
28206 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28207 * @param {Object/Array} config A button config or array of configs
28208 * @return {Roo.Toolbar.Button/Array}
28210 addButton : function(config){
28211 if(config instanceof Array){
28213 for(var i = 0, len = config.length; i < len; i++) {
28214 buttons.push(this.addButton(config[i]));
28219 if(!(config instanceof Roo.Toolbar.Button)){
28221 new Roo.Toolbar.SplitButton(config) :
28222 new Roo.Toolbar.Button(config);
28224 var td = this.nextBlock();
28231 * Adds text to the toolbar
28232 * @param {String} text The text to add
28233 * @return {Roo.Toolbar.Item} The element's item
28235 addText : function(text){
28236 return this.addItem(new Roo.Toolbar.TextItem(text));
28240 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28241 * @param {Number} index The index where the item is to be inserted
28242 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28243 * @return {Roo.Toolbar.Button/Item}
28245 insertButton : function(index, item){
28246 if(item instanceof Array){
28248 for(var i = 0, len = item.length; i < len; i++) {
28249 buttons.push(this.insertButton(index + i, item[i]));
28253 if (!(item instanceof Roo.Toolbar.Button)){
28254 item = new Roo.Toolbar.Button(item);
28256 var td = document.createElement("td");
28257 this.tr.insertBefore(td, this.tr.childNodes[index]);
28259 this.items.insert(index, item);
28264 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28265 * @param {Object} config
28266 * @return {Roo.Toolbar.Item} The element's item
28268 addDom : function(config, returnEl){
28269 var td = this.nextBlock();
28270 Roo.DomHelper.overwrite(td, config);
28271 var ti = new Roo.Toolbar.Item(td.firstChild);
28273 this.items.add(ti);
28278 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28279 * @type Roo.util.MixedCollection
28284 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28285 * Note: the field should not have been rendered yet. For a field that has already been
28286 * rendered, use {@link #addElement}.
28287 * @param {Roo.form.Field} field
28288 * @return {Roo.ToolbarItem}
28292 addField : function(field) {
28293 if (!this.fields) {
28295 this.fields = new Roo.util.MixedCollection(false, function(o){
28296 return o.id || ("item" + (++autoId));
28301 var td = this.nextBlock();
28303 var ti = new Roo.Toolbar.Item(td.firstChild);
28305 this.items.add(ti);
28306 this.fields.add(field);
28317 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28318 this.el.child('div').hide();
28326 this.el.child('div').show();
28330 nextBlock : function(){
28331 var td = document.createElement("td");
28332 this.tr.appendChild(td);
28337 destroy : function(){
28338 if(this.items){ // rendered?
28339 Roo.destroy.apply(Roo, this.items.items);
28341 if(this.fields){ // rendered?
28342 Roo.destroy.apply(Roo, this.fields.items);
28344 Roo.Element.uncache(this.el, this.tr);
28349 * @class Roo.Toolbar.Item
28350 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28352 * Creates a new Item
28353 * @param {HTMLElement} el
28355 Roo.Toolbar.Item = function(el){
28356 this.el = Roo.getDom(el);
28357 this.id = Roo.id(this.el);
28358 this.hidden = false;
28361 Roo.Toolbar.Item.prototype = {
28364 * Get this item's HTML Element
28365 * @return {HTMLElement}
28367 getEl : function(){
28372 render : function(td){
28374 td.appendChild(this.el);
28378 * Removes and destroys this item.
28380 destroy : function(){
28381 this.td.parentNode.removeChild(this.td);
28388 this.hidden = false;
28389 this.td.style.display = "";
28396 this.hidden = true;
28397 this.td.style.display = "none";
28401 * Convenience function for boolean show/hide.
28402 * @param {Boolean} visible true to show/false to hide
28404 setVisible: function(visible){
28413 * Try to focus this item.
28415 focus : function(){
28416 Roo.fly(this.el).focus();
28420 * Disables this item.
28422 disable : function(){
28423 Roo.fly(this.td).addClass("x-item-disabled");
28424 this.disabled = true;
28425 this.el.disabled = true;
28429 * Enables this item.
28431 enable : function(){
28432 Roo.fly(this.td).removeClass("x-item-disabled");
28433 this.disabled = false;
28434 this.el.disabled = false;
28440 * @class Roo.Toolbar.Separator
28441 * @extends Roo.Toolbar.Item
28442 * A simple toolbar separator class
28444 * Creates a new Separator
28446 Roo.Toolbar.Separator = function(){
28447 var s = document.createElement("span");
28448 s.className = "ytb-sep";
28449 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28451 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28452 enable:Roo.emptyFn,
28453 disable:Roo.emptyFn,
28458 * @class Roo.Toolbar.Spacer
28459 * @extends Roo.Toolbar.Item
28460 * A simple element that adds extra horizontal space to a toolbar.
28462 * Creates a new Spacer
28464 Roo.Toolbar.Spacer = function(){
28465 var s = document.createElement("div");
28466 s.className = "ytb-spacer";
28467 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28469 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28470 enable:Roo.emptyFn,
28471 disable:Roo.emptyFn,
28476 * @class Roo.Toolbar.Fill
28477 * @extends Roo.Toolbar.Spacer
28478 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28480 * Creates a new Spacer
28482 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28484 render : function(td){
28485 td.style.width = '100%';
28486 Roo.Toolbar.Fill.superclass.render.call(this, td);
28491 * @class Roo.Toolbar.TextItem
28492 * @extends Roo.Toolbar.Item
28493 * A simple class that renders text directly into a toolbar.
28495 * Creates a new TextItem
28496 * @param {String} text
28498 Roo.Toolbar.TextItem = function(text){
28499 if (typeof(text) == 'object') {
28502 var s = document.createElement("span");
28503 s.className = "ytb-text";
28504 s.innerHTML = text;
28505 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28507 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28508 enable:Roo.emptyFn,
28509 disable:Roo.emptyFn,
28514 * @class Roo.Toolbar.Button
28515 * @extends Roo.Button
28516 * A button that renders into a toolbar.
28518 * Creates a new Button
28519 * @param {Object} config A standard {@link Roo.Button} config object
28521 Roo.Toolbar.Button = function(config){
28522 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28524 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28525 render : function(td){
28527 Roo.Toolbar.Button.superclass.render.call(this, td);
28531 * Removes and destroys this button
28533 destroy : function(){
28534 Roo.Toolbar.Button.superclass.destroy.call(this);
28535 this.td.parentNode.removeChild(this.td);
28539 * Shows this button
28542 this.hidden = false;
28543 this.td.style.display = "";
28547 * Hides this button
28550 this.hidden = true;
28551 this.td.style.display = "none";
28555 * Disables this item
28557 disable : function(){
28558 Roo.fly(this.td).addClass("x-item-disabled");
28559 this.disabled = true;
28563 * Enables this item
28565 enable : function(){
28566 Roo.fly(this.td).removeClass("x-item-disabled");
28567 this.disabled = false;
28570 // backwards compat
28571 Roo.ToolbarButton = Roo.Toolbar.Button;
28574 * @class Roo.Toolbar.SplitButton
28575 * @extends Roo.SplitButton
28576 * A menu button that renders into a toolbar.
28578 * Creates a new SplitButton
28579 * @param {Object} config A standard {@link Roo.SplitButton} config object
28581 Roo.Toolbar.SplitButton = function(config){
28582 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28584 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28585 render : function(td){
28587 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28591 * Removes and destroys this button
28593 destroy : function(){
28594 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28595 this.td.parentNode.removeChild(this.td);
28599 * Shows this button
28602 this.hidden = false;
28603 this.td.style.display = "";
28607 * Hides this button
28610 this.hidden = true;
28611 this.td.style.display = "none";
28615 // backwards compat
28616 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28618 * Ext JS Library 1.1.1
28619 * Copyright(c) 2006-2007, Ext JS, LLC.
28621 * Originally Released Under LGPL - original licence link has changed is not relivant.
28624 * <script type="text/javascript">
28628 * @class Roo.PagingToolbar
28629 * @extends Roo.Toolbar
28630 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28632 * Create a new PagingToolbar
28633 * @param {Object} config The config object
28635 Roo.PagingToolbar = function(el, ds, config)
28637 // old args format still supported... - xtype is prefered..
28638 if (typeof(el) == 'object' && el.xtype) {
28639 // created from xtype...
28641 ds = el.dataSource;
28642 el = config.container;
28645 if (config.items) {
28646 items = config.items;
28650 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28653 this.renderButtons(this.el);
28656 // supprot items array.
28658 Roo.each(items, function(e) {
28659 this.add(Roo.factory(e));
28664 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28666 * @cfg {Roo.data.Store} dataSource
28667 * The underlying data store providing the paged data
28670 * @cfg {String/HTMLElement/Element} container
28671 * container The id or element that will contain the toolbar
28674 * @cfg {Boolean} displayInfo
28675 * True to display the displayMsg (defaults to false)
28678 * @cfg {Number} pageSize
28679 * The number of records to display per page (defaults to 20)
28683 * @cfg {String} displayMsg
28684 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28686 displayMsg : 'Displaying {0} - {1} of {2}',
28688 * @cfg {String} emptyMsg
28689 * The message to display when no records are found (defaults to "No data to display")
28691 emptyMsg : 'No data to display',
28693 * Customizable piece of the default paging text (defaults to "Page")
28696 beforePageText : "Page",
28698 * Customizable piece of the default paging text (defaults to "of %0")
28701 afterPageText : "of {0}",
28703 * Customizable piece of the default paging text (defaults to "First Page")
28706 firstText : "First Page",
28708 * Customizable piece of the default paging text (defaults to "Previous Page")
28711 prevText : "Previous Page",
28713 * Customizable piece of the default paging text (defaults to "Next Page")
28716 nextText : "Next Page",
28718 * Customizable piece of the default paging text (defaults to "Last Page")
28721 lastText : "Last Page",
28723 * Customizable piece of the default paging text (defaults to "Refresh")
28726 refreshText : "Refresh",
28729 renderButtons : function(el){
28730 Roo.PagingToolbar.superclass.render.call(this, el);
28731 this.first = this.addButton({
28732 tooltip: this.firstText,
28733 cls: "x-btn-icon x-grid-page-first",
28735 handler: this.onClick.createDelegate(this, ["first"])
28737 this.prev = this.addButton({
28738 tooltip: this.prevText,
28739 cls: "x-btn-icon x-grid-page-prev",
28741 handler: this.onClick.createDelegate(this, ["prev"])
28743 //this.addSeparator();
28744 this.add(this.beforePageText);
28745 this.field = Roo.get(this.addDom({
28750 cls: "x-grid-page-number"
28752 this.field.on("keydown", this.onPagingKeydown, this);
28753 this.field.on("focus", function(){this.dom.select();});
28754 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28755 this.field.setHeight(18);
28756 //this.addSeparator();
28757 this.next = this.addButton({
28758 tooltip: this.nextText,
28759 cls: "x-btn-icon x-grid-page-next",
28761 handler: this.onClick.createDelegate(this, ["next"])
28763 this.last = this.addButton({
28764 tooltip: this.lastText,
28765 cls: "x-btn-icon x-grid-page-last",
28767 handler: this.onClick.createDelegate(this, ["last"])
28769 //this.addSeparator();
28770 this.loading = this.addButton({
28771 tooltip: this.refreshText,
28772 cls: "x-btn-icon x-grid-loading",
28773 handler: this.onClick.createDelegate(this, ["refresh"])
28776 if(this.displayInfo){
28777 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28782 updateInfo : function(){
28783 if(this.displayEl){
28784 var count = this.ds.getCount();
28785 var msg = count == 0 ?
28789 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28791 this.displayEl.update(msg);
28796 onLoad : function(ds, r, o){
28797 this.cursor = o.params ? o.params.start : 0;
28798 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28800 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28801 this.field.dom.value = ap;
28802 this.first.setDisabled(ap == 1);
28803 this.prev.setDisabled(ap == 1);
28804 this.next.setDisabled(ap == ps);
28805 this.last.setDisabled(ap == ps);
28806 this.loading.enable();
28811 getPageData : function(){
28812 var total = this.ds.getTotalCount();
28815 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28816 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28821 onLoadError : function(){
28822 this.loading.enable();
28826 onPagingKeydown : function(e){
28827 var k = e.getKey();
28828 var d = this.getPageData();
28830 var v = this.field.dom.value, pageNum;
28831 if(!v || isNaN(pageNum = parseInt(v, 10))){
28832 this.field.dom.value = d.activePage;
28835 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28836 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28839 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))
28841 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28842 this.field.dom.value = pageNum;
28843 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28846 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28848 var v = this.field.dom.value, pageNum;
28849 var increment = (e.shiftKey) ? 10 : 1;
28850 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28852 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28853 this.field.dom.value = d.activePage;
28856 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28858 this.field.dom.value = parseInt(v, 10) + increment;
28859 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28860 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28867 beforeLoad : function(){
28869 this.loading.disable();
28874 onClick : function(which){
28878 ds.load({params:{start: 0, limit: this.pageSize}});
28881 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28884 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28887 var total = ds.getTotalCount();
28888 var extra = total % this.pageSize;
28889 var lastStart = extra ? (total - extra) : total-this.pageSize;
28890 ds.load({params:{start: lastStart, limit: this.pageSize}});
28893 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28899 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28900 * @param {Roo.data.Store} store The data store to unbind
28902 unbind : function(ds){
28903 ds.un("beforeload", this.beforeLoad, this);
28904 ds.un("load", this.onLoad, this);
28905 ds.un("loadexception", this.onLoadError, this);
28906 ds.un("remove", this.updateInfo, this);
28907 ds.un("add", this.updateInfo, this);
28908 this.ds = undefined;
28912 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28913 * @param {Roo.data.Store} store The data store to bind
28915 bind : function(ds){
28916 ds.on("beforeload", this.beforeLoad, this);
28917 ds.on("load", this.onLoad, this);
28918 ds.on("loadexception", this.onLoadError, this);
28919 ds.on("remove", this.updateInfo, this);
28920 ds.on("add", this.updateInfo, this);
28925 * Ext JS Library 1.1.1
28926 * Copyright(c) 2006-2007, Ext JS, LLC.
28928 * Originally Released Under LGPL - original licence link has changed is not relivant.
28931 * <script type="text/javascript">
28935 * @class Roo.Resizable
28936 * @extends Roo.util.Observable
28937 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28938 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28939 * 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
28940 * the element will be wrapped for you automatically.</p>
28941 * <p>Here is the list of valid resize handles:</p>
28944 ------ -------------------
28953 'hd' horizontal drag
28956 * <p>Here's an example showing the creation of a typical Resizable:</p>
28958 var resizer = new Roo.Resizable("element-id", {
28966 resizer.on("resize", myHandler);
28968 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
28969 * resizer.east.setDisplayed(false);</p>
28970 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
28971 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
28972 * resize operation's new size (defaults to [0, 0])
28973 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
28974 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
28975 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
28976 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
28977 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
28978 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
28979 * @cfg {Number} width The width of the element in pixels (defaults to null)
28980 * @cfg {Number} height The height of the element in pixels (defaults to null)
28981 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
28982 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
28983 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
28984 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
28985 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
28986 * in favor of the handles config option (defaults to false)
28987 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
28988 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
28989 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
28990 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
28991 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
28992 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
28993 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
28994 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
28995 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
28996 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
28997 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
28999 * Create a new resizable component
29000 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29001 * @param {Object} config configuration options
29003 Roo.Resizable = function(el, config)
29005 this.el = Roo.get(el);
29007 if(config && config.wrap){
29008 config.resizeChild = this.el;
29009 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29010 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29011 this.el.setStyle("overflow", "hidden");
29012 this.el.setPositioning(config.resizeChild.getPositioning());
29013 config.resizeChild.clearPositioning();
29014 if(!config.width || !config.height){
29015 var csize = config.resizeChild.getSize();
29016 this.el.setSize(csize.width, csize.height);
29018 if(config.pinned && !config.adjustments){
29019 config.adjustments = "auto";
29023 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29024 this.proxy.unselectable();
29025 this.proxy.enableDisplayMode('block');
29027 Roo.apply(this, config);
29030 this.disableTrackOver = true;
29031 this.el.addClass("x-resizable-pinned");
29033 // if the element isn't positioned, make it relative
29034 var position = this.el.getStyle("position");
29035 if(position != "absolute" && position != "fixed"){
29036 this.el.setStyle("position", "relative");
29038 if(!this.handles){ // no handles passed, must be legacy style
29039 this.handles = 's,e,se';
29040 if(this.multiDirectional){
29041 this.handles += ',n,w';
29044 if(this.handles == "all"){
29045 this.handles = "n s e w ne nw se sw";
29047 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29048 var ps = Roo.Resizable.positions;
29049 for(var i = 0, len = hs.length; i < len; i++){
29050 if(hs[i] && ps[hs[i]]){
29051 var pos = ps[hs[i]];
29052 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29056 this.corner = this.southeast;
29058 // updateBox = the box can move..
29059 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29060 this.updateBox = true;
29063 this.activeHandle = null;
29065 if(this.resizeChild){
29066 if(typeof this.resizeChild == "boolean"){
29067 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29069 this.resizeChild = Roo.get(this.resizeChild, true);
29073 if(this.adjustments == "auto"){
29074 var rc = this.resizeChild;
29075 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29076 if(rc && (hw || hn)){
29077 rc.position("relative");
29078 rc.setLeft(hw ? hw.el.getWidth() : 0);
29079 rc.setTop(hn ? hn.el.getHeight() : 0);
29081 this.adjustments = [
29082 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29083 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29087 if(this.draggable){
29088 this.dd = this.dynamic ?
29089 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29090 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29096 * @event beforeresize
29097 * Fired before resize is allowed. Set enabled to false to cancel resize.
29098 * @param {Roo.Resizable} this
29099 * @param {Roo.EventObject} e The mousedown event
29101 "beforeresize" : true,
29104 * Fired a resizing.
29105 * @param {Roo.Resizable} this
29106 * @param {Number} x The new x position
29107 * @param {Number} y The new y position
29108 * @param {Number} w The new w width
29109 * @param {Number} h The new h hight
29110 * @param {Roo.EventObject} e The mouseup event
29115 * Fired after a resize.
29116 * @param {Roo.Resizable} this
29117 * @param {Number} width The new width
29118 * @param {Number} height The new height
29119 * @param {Roo.EventObject} e The mouseup event
29124 if(this.width !== null && this.height !== null){
29125 this.resizeTo(this.width, this.height);
29127 this.updateChildSize();
29130 this.el.dom.style.zoom = 1;
29132 Roo.Resizable.superclass.constructor.call(this);
29135 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29136 resizeChild : false,
29137 adjustments : [0, 0],
29147 multiDirectional : false,
29148 disableTrackOver : false,
29149 easing : 'easeOutStrong',
29150 widthIncrement : 0,
29151 heightIncrement : 0,
29155 preserveRatio : false,
29156 transparent: false,
29162 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29164 constrainTo: undefined,
29166 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29168 resizeRegion: undefined,
29172 * Perform a manual resize
29173 * @param {Number} width
29174 * @param {Number} height
29176 resizeTo : function(width, height){
29177 this.el.setSize(width, height);
29178 this.updateChildSize();
29179 this.fireEvent("resize", this, width, height, null);
29183 startSizing : function(e, handle){
29184 this.fireEvent("beforeresize", this, e);
29185 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29188 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29189 this.overlay.unselectable();
29190 this.overlay.enableDisplayMode("block");
29191 this.overlay.on("mousemove", this.onMouseMove, this);
29192 this.overlay.on("mouseup", this.onMouseUp, this);
29194 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29196 this.resizing = true;
29197 this.startBox = this.el.getBox();
29198 this.startPoint = e.getXY();
29199 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29200 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29202 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29203 this.overlay.show();
29205 if(this.constrainTo) {
29206 var ct = Roo.get(this.constrainTo);
29207 this.resizeRegion = ct.getRegion().adjust(
29208 ct.getFrameWidth('t'),
29209 ct.getFrameWidth('l'),
29210 -ct.getFrameWidth('b'),
29211 -ct.getFrameWidth('r')
29215 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29217 this.proxy.setBox(this.startBox);
29219 this.proxy.setStyle('visibility', 'visible');
29225 onMouseDown : function(handle, e){
29228 this.activeHandle = handle;
29229 this.startSizing(e, handle);
29234 onMouseUp : function(e){
29235 var size = this.resizeElement();
29236 this.resizing = false;
29238 this.overlay.hide();
29240 this.fireEvent("resize", this, size.width, size.height, e);
29244 updateChildSize : function(){
29246 if(this.resizeChild){
29248 var child = this.resizeChild;
29249 var adj = this.adjustments;
29250 if(el.dom.offsetWidth){
29251 var b = el.getSize(true);
29252 child.setSize(b.width+adj[0], b.height+adj[1]);
29254 // Second call here for IE
29255 // The first call enables instant resizing and
29256 // the second call corrects scroll bars if they
29259 setTimeout(function(){
29260 if(el.dom.offsetWidth){
29261 var b = el.getSize(true);
29262 child.setSize(b.width+adj[0], b.height+adj[1]);
29270 snap : function(value, inc, min){
29271 if(!inc || !value) return value;
29272 var newValue = value;
29273 var m = value % inc;
29276 newValue = value + (inc-m);
29278 newValue = value - m;
29281 return Math.max(min, newValue);
29285 resizeElement : function(){
29286 var box = this.proxy.getBox();
29287 if(this.updateBox){
29288 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29290 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29292 this.updateChildSize();
29300 constrain : function(v, diff, m, mx){
29303 }else if(v - diff > mx){
29310 onMouseMove : function(e){
29313 try{// try catch so if something goes wrong the user doesn't get hung
29315 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29319 //var curXY = this.startPoint;
29320 var curSize = this.curSize || this.startBox;
29321 var x = this.startBox.x, y = this.startBox.y;
29322 var ox = x, oy = y;
29323 var w = curSize.width, h = curSize.height;
29324 var ow = w, oh = h;
29325 var mw = this.minWidth, mh = this.minHeight;
29326 var mxw = this.maxWidth, mxh = this.maxHeight;
29327 var wi = this.widthIncrement;
29328 var hi = this.heightIncrement;
29330 var eventXY = e.getXY();
29331 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29332 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29334 var pos = this.activeHandle.position;
29339 w = Math.min(Math.max(mw, w), mxw);
29344 h = Math.min(Math.max(mh, h), mxh);
29349 w = Math.min(Math.max(mw, w), mxw);
29350 h = Math.min(Math.max(mh, h), mxh);
29353 diffY = this.constrain(h, diffY, mh, mxh);
29360 var adiffX = Math.abs(diffX);
29361 var sub = (adiffX % wi); // how much
29362 if (sub > (wi/2)) { // far enough to snap
29363 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29365 // remove difference..
29366 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29370 x = Math.max(this.minX, x);
29373 diffX = this.constrain(w, diffX, mw, mxw);
29379 w = Math.min(Math.max(mw, w), mxw);
29380 diffY = this.constrain(h, diffY, mh, mxh);
29385 diffX = this.constrain(w, diffX, mw, mxw);
29386 diffY = this.constrain(h, diffY, mh, mxh);
29393 diffX = this.constrain(w, diffX, mw, mxw);
29395 h = Math.min(Math.max(mh, h), mxh);
29401 var sw = this.snap(w, wi, mw);
29402 var sh = this.snap(h, hi, mh);
29403 if(sw != w || sh != h){
29426 if(this.preserveRatio){
29431 h = Math.min(Math.max(mh, h), mxh);
29436 w = Math.min(Math.max(mw, w), mxw);
29441 w = Math.min(Math.max(mw, w), mxw);
29447 w = Math.min(Math.max(mw, w), mxw);
29453 h = Math.min(Math.max(mh, h), mxh);
29461 h = Math.min(Math.max(mh, h), mxh);
29471 h = Math.min(Math.max(mh, h), mxh);
29479 if (pos == 'hdrag') {
29482 this.proxy.setBounds(x, y, w, h);
29484 this.resizeElement();
29488 this.fireEvent("resizing", this, x, y, w, h, e);
29492 handleOver : function(){
29494 this.el.addClass("x-resizable-over");
29499 handleOut : function(){
29500 if(!this.resizing){
29501 this.el.removeClass("x-resizable-over");
29506 * Returns the element this component is bound to.
29507 * @return {Roo.Element}
29509 getEl : function(){
29514 * Returns the resizeChild element (or null).
29515 * @return {Roo.Element}
29517 getResizeChild : function(){
29518 return this.resizeChild;
29520 groupHandler : function()
29525 * Destroys this resizable. If the element was wrapped and
29526 * removeEl is not true then the element remains.
29527 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29529 destroy : function(removeEl){
29530 this.proxy.remove();
29532 this.overlay.removeAllListeners();
29533 this.overlay.remove();
29535 var ps = Roo.Resizable.positions;
29537 if(typeof ps[k] != "function" && this[ps[k]]){
29538 var h = this[ps[k]];
29539 h.el.removeAllListeners();
29544 this.el.update("");
29551 // hash to map config positions to true positions
29552 Roo.Resizable.positions = {
29553 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29558 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29560 // only initialize the template if resizable is used
29561 var tpl = Roo.DomHelper.createTemplate(
29562 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29565 Roo.Resizable.Handle.prototype.tpl = tpl;
29567 this.position = pos;
29569 // show north drag fro topdra
29570 var handlepos = pos == 'hdrag' ? 'north' : pos;
29572 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29573 if (pos == 'hdrag') {
29574 this.el.setStyle('cursor', 'pointer');
29576 this.el.unselectable();
29578 this.el.setOpacity(0);
29580 this.el.on("mousedown", this.onMouseDown, this);
29581 if(!disableTrackOver){
29582 this.el.on("mouseover", this.onMouseOver, this);
29583 this.el.on("mouseout", this.onMouseOut, this);
29588 Roo.Resizable.Handle.prototype = {
29589 afterResize : function(rz){
29594 onMouseDown : function(e){
29595 this.rz.onMouseDown(this, e);
29598 onMouseOver : function(e){
29599 this.rz.handleOver(this, e);
29602 onMouseOut : function(e){
29603 this.rz.handleOut(this, e);
29607 * Ext JS Library 1.1.1
29608 * Copyright(c) 2006-2007, Ext JS, LLC.
29610 * Originally Released Under LGPL - original licence link has changed is not relivant.
29613 * <script type="text/javascript">
29617 * @class Roo.Editor
29618 * @extends Roo.Component
29619 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29621 * Create a new Editor
29622 * @param {Roo.form.Field} field The Field object (or descendant)
29623 * @param {Object} config The config object
29625 Roo.Editor = function(field, config){
29626 Roo.Editor.superclass.constructor.call(this, config);
29627 this.field = field;
29630 * @event beforestartedit
29631 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29632 * false from the handler of this event.
29633 * @param {Editor} this
29634 * @param {Roo.Element} boundEl The underlying element bound to this editor
29635 * @param {Mixed} value The field value being set
29637 "beforestartedit" : true,
29640 * Fires when this editor is displayed
29641 * @param {Roo.Element} boundEl The underlying element bound to this editor
29642 * @param {Mixed} value The starting field value
29644 "startedit" : true,
29646 * @event beforecomplete
29647 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29648 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29649 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29650 * event will not fire since no edit actually occurred.
29651 * @param {Editor} this
29652 * @param {Mixed} value The current field value
29653 * @param {Mixed} startValue The original field value
29655 "beforecomplete" : true,
29658 * Fires after editing is complete and any changed value has been written to the underlying field.
29659 * @param {Editor} this
29660 * @param {Mixed} value The current field value
29661 * @param {Mixed} startValue The original field value
29665 * @event specialkey
29666 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29667 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29668 * @param {Roo.form.Field} this
29669 * @param {Roo.EventObject} e The event object
29671 "specialkey" : true
29675 Roo.extend(Roo.Editor, Roo.Component, {
29677 * @cfg {Boolean/String} autosize
29678 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29679 * or "height" to adopt the height only (defaults to false)
29682 * @cfg {Boolean} revertInvalid
29683 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29684 * validation fails (defaults to true)
29687 * @cfg {Boolean} ignoreNoChange
29688 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29689 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29690 * will never be ignored.
29693 * @cfg {Boolean} hideEl
29694 * False to keep the bound element visible while the editor is displayed (defaults to true)
29697 * @cfg {Mixed} value
29698 * The data value of the underlying field (defaults to "")
29702 * @cfg {String} alignment
29703 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29707 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29708 * for bottom-right shadow (defaults to "frame")
29712 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29716 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29718 completeOnEnter : false,
29720 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29722 cancelOnEsc : false,
29724 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29729 onRender : function(ct, position){
29730 this.el = new Roo.Layer({
29731 shadow: this.shadow,
29737 constrain: this.constrain
29739 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29740 if(this.field.msgTarget != 'title'){
29741 this.field.msgTarget = 'qtip';
29743 this.field.render(this.el);
29745 this.field.el.dom.setAttribute('autocomplete', 'off');
29747 this.field.on("specialkey", this.onSpecialKey, this);
29748 if(this.swallowKeys){
29749 this.field.el.swallowEvent(['keydown','keypress']);
29752 this.field.on("blur", this.onBlur, this);
29753 if(this.field.grow){
29754 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29758 onSpecialKey : function(field, e)
29760 //Roo.log('editor onSpecialKey');
29761 if(this.completeOnEnter && e.getKey() == e.ENTER){
29763 this.completeEdit();
29766 // do not fire special key otherwise it might hide close the editor...
29767 if(e.getKey() == e.ENTER){
29770 if(this.cancelOnEsc && e.getKey() == e.ESC){
29774 this.fireEvent('specialkey', field, e);
29779 * Starts the editing process and shows the editor.
29780 * @param {String/HTMLElement/Element} el The element to edit
29781 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29782 * to the innerHTML of el.
29784 startEdit : function(el, value){
29786 this.completeEdit();
29788 this.boundEl = Roo.get(el);
29789 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29790 if(!this.rendered){
29791 this.render(this.parentEl || document.body);
29793 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29796 this.startValue = v;
29797 this.field.setValue(v);
29799 var sz = this.boundEl.getSize();
29800 switch(this.autoSize){
29802 this.setSize(sz.width, "");
29805 this.setSize("", sz.height);
29808 this.setSize(sz.width, sz.height);
29811 this.el.alignTo(this.boundEl, this.alignment);
29812 this.editing = true;
29814 Roo.QuickTips.disable();
29820 * Sets the height and width of this editor.
29821 * @param {Number} width The new width
29822 * @param {Number} height The new height
29824 setSize : function(w, h){
29825 this.field.setSize(w, h);
29832 * Realigns the editor to the bound field based on the current alignment config value.
29834 realign : function(){
29835 this.el.alignTo(this.boundEl, this.alignment);
29839 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29840 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29842 completeEdit : function(remainVisible){
29846 var v = this.getValue();
29847 if(this.revertInvalid !== false && !this.field.isValid()){
29848 v = this.startValue;
29849 this.cancelEdit(true);
29851 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29852 this.editing = false;
29856 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29857 this.editing = false;
29858 if(this.updateEl && this.boundEl){
29859 this.boundEl.update(v);
29861 if(remainVisible !== true){
29864 this.fireEvent("complete", this, v, this.startValue);
29869 onShow : function(){
29871 if(this.hideEl !== false){
29872 this.boundEl.hide();
29875 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29876 this.fixIEFocus = true;
29877 this.deferredFocus.defer(50, this);
29879 this.field.focus();
29881 this.fireEvent("startedit", this.boundEl, this.startValue);
29884 deferredFocus : function(){
29886 this.field.focus();
29891 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29892 * reverted to the original starting value.
29893 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29894 * cancel (defaults to false)
29896 cancelEdit : function(remainVisible){
29898 this.setValue(this.startValue);
29899 if(remainVisible !== true){
29906 onBlur : function(){
29907 if(this.allowBlur !== true && this.editing){
29908 this.completeEdit();
29913 onHide : function(){
29915 this.completeEdit();
29919 if(this.field.collapse){
29920 this.field.collapse();
29923 if(this.hideEl !== false){
29924 this.boundEl.show();
29927 Roo.QuickTips.enable();
29932 * Sets the data value of the editor
29933 * @param {Mixed} value Any valid value supported by the underlying field
29935 setValue : function(v){
29936 this.field.setValue(v);
29940 * Gets the data value of the editor
29941 * @return {Mixed} The data value
29943 getValue : function(){
29944 return this.field.getValue();
29948 * Ext JS Library 1.1.1
29949 * Copyright(c) 2006-2007, Ext JS, LLC.
29951 * Originally Released Under LGPL - original licence link has changed is not relivant.
29954 * <script type="text/javascript">
29958 * @class Roo.BasicDialog
29959 * @extends Roo.util.Observable
29960 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29962 var dlg = new Roo.BasicDialog("my-dlg", {
29971 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
29972 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
29973 dlg.addButton('Cancel', dlg.hide, dlg);
29976 <b>A Dialog should always be a direct child of the body element.</b>
29977 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
29978 * @cfg {String} title Default text to display in the title bar (defaults to null)
29979 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29980 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
29981 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
29982 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
29983 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
29984 * (defaults to null with no animation)
29985 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
29986 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
29987 * property for valid values (defaults to 'all')
29988 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
29989 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
29990 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
29991 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
29992 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
29993 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
29994 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
29995 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
29996 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
29997 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
29998 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
29999 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30000 * draggable = true (defaults to false)
30001 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30002 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30003 * shadow (defaults to false)
30004 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30005 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30006 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30007 * @cfg {Array} buttons Array of buttons
30008 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30010 * Create a new BasicDialog.
30011 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30012 * @param {Object} config Configuration options
30014 Roo.BasicDialog = function(el, config){
30015 this.el = Roo.get(el);
30016 var dh = Roo.DomHelper;
30017 if(!this.el && config && config.autoCreate){
30018 if(typeof config.autoCreate == "object"){
30019 if(!config.autoCreate.id){
30020 config.autoCreate.id = el;
30022 this.el = dh.append(document.body,
30023 config.autoCreate, true);
30025 this.el = dh.append(document.body,
30026 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30030 el.setDisplayed(true);
30031 el.hide = this.hideAction;
30033 el.addClass("x-dlg");
30035 Roo.apply(this, config);
30037 this.proxy = el.createProxy("x-dlg-proxy");
30038 this.proxy.hide = this.hideAction;
30039 this.proxy.setOpacity(.5);
30043 el.setWidth(config.width);
30046 el.setHeight(config.height);
30048 this.size = el.getSize();
30049 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30050 this.xy = [config.x,config.y];
30052 this.xy = el.getCenterXY(true);
30054 /** The header element @type Roo.Element */
30055 this.header = el.child("> .x-dlg-hd");
30056 /** The body element @type Roo.Element */
30057 this.body = el.child("> .x-dlg-bd");
30058 /** The footer element @type Roo.Element */
30059 this.footer = el.child("> .x-dlg-ft");
30062 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30065 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30068 this.header.unselectable();
30070 this.header.update(this.title);
30072 // this element allows the dialog to be focused for keyboard event
30073 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30074 this.focusEl.swallowEvent("click", true);
30076 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30078 // wrap the body and footer for special rendering
30079 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30081 this.bwrap.dom.appendChild(this.footer.dom);
30084 this.bg = this.el.createChild({
30085 tag: "div", cls:"x-dlg-bg",
30086 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30088 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30091 if(this.autoScroll !== false && !this.autoTabs){
30092 this.body.setStyle("overflow", "auto");
30095 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30097 if(this.closable !== false){
30098 this.el.addClass("x-dlg-closable");
30099 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30100 this.close.on("click", this.closeClick, this);
30101 this.close.addClassOnOver("x-dlg-close-over");
30103 if(this.collapsible !== false){
30104 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30105 this.collapseBtn.on("click", this.collapseClick, this);
30106 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30107 this.header.on("dblclick", this.collapseClick, this);
30109 if(this.resizable !== false){
30110 this.el.addClass("x-dlg-resizable");
30111 this.resizer = new Roo.Resizable(el, {
30112 minWidth: this.minWidth || 80,
30113 minHeight:this.minHeight || 80,
30114 handles: this.resizeHandles || "all",
30117 this.resizer.on("beforeresize", this.beforeResize, this);
30118 this.resizer.on("resize", this.onResize, this);
30120 if(this.draggable !== false){
30121 el.addClass("x-dlg-draggable");
30122 if (!this.proxyDrag) {
30123 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30126 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30128 dd.setHandleElId(this.header.id);
30129 dd.endDrag = this.endMove.createDelegate(this);
30130 dd.startDrag = this.startMove.createDelegate(this);
30131 dd.onDrag = this.onDrag.createDelegate(this);
30136 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30137 this.mask.enableDisplayMode("block");
30139 this.el.addClass("x-dlg-modal");
30142 this.shadow = new Roo.Shadow({
30143 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30144 offset : this.shadowOffset
30147 this.shadowOffset = 0;
30149 if(Roo.useShims && this.shim !== false){
30150 this.shim = this.el.createShim();
30151 this.shim.hide = this.hideAction;
30159 if (this.buttons) {
30160 var bts= this.buttons;
30162 Roo.each(bts, function(b) {
30171 * Fires when a key is pressed
30172 * @param {Roo.BasicDialog} this
30173 * @param {Roo.EventObject} e
30178 * Fires when this dialog is moved by the user.
30179 * @param {Roo.BasicDialog} this
30180 * @param {Number} x The new page X
30181 * @param {Number} y The new page Y
30186 * Fires when this dialog is resized by the user.
30187 * @param {Roo.BasicDialog} this
30188 * @param {Number} width The new width
30189 * @param {Number} height The new height
30193 * @event beforehide
30194 * Fires before this dialog is hidden.
30195 * @param {Roo.BasicDialog} this
30197 "beforehide" : true,
30200 * Fires when this dialog is hidden.
30201 * @param {Roo.BasicDialog} this
30205 * @event beforeshow
30206 * Fires before this dialog is shown.
30207 * @param {Roo.BasicDialog} this
30209 "beforeshow" : true,
30212 * Fires when this dialog is shown.
30213 * @param {Roo.BasicDialog} this
30217 el.on("keydown", this.onKeyDown, this);
30218 el.on("mousedown", this.toFront, this);
30219 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30221 Roo.DialogManager.register(this);
30222 Roo.BasicDialog.superclass.constructor.call(this);
30225 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30226 shadowOffset: Roo.isIE ? 6 : 5,
30229 minButtonWidth: 75,
30230 defaultButton: null,
30231 buttonAlign: "right",
30236 * Sets the dialog title text
30237 * @param {String} text The title text to display
30238 * @return {Roo.BasicDialog} this
30240 setTitle : function(text){
30241 this.header.update(text);
30246 closeClick : function(){
30251 collapseClick : function(){
30252 this[this.collapsed ? "expand" : "collapse"]();
30256 * Collapses the dialog to its minimized state (only the title bar is visible).
30257 * Equivalent to the user clicking the collapse dialog button.
30259 collapse : function(){
30260 if(!this.collapsed){
30261 this.collapsed = true;
30262 this.el.addClass("x-dlg-collapsed");
30263 this.restoreHeight = this.el.getHeight();
30264 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30269 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30270 * clicking the expand dialog button.
30272 expand : function(){
30273 if(this.collapsed){
30274 this.collapsed = false;
30275 this.el.removeClass("x-dlg-collapsed");
30276 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30281 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30282 * @return {Roo.TabPanel} The tabs component
30284 initTabs : function(){
30285 var tabs = this.getTabs();
30286 while(tabs.getTab(0)){
30289 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30291 tabs.addTab(Roo.id(dom), dom.title);
30299 beforeResize : function(){
30300 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30304 onResize : function(){
30305 this.refreshSize();
30306 this.syncBodyHeight();
30307 this.adjustAssets();
30309 this.fireEvent("resize", this, this.size.width, this.size.height);
30313 onKeyDown : function(e){
30314 if(this.isVisible()){
30315 this.fireEvent("keydown", this, e);
30320 * Resizes the dialog.
30321 * @param {Number} width
30322 * @param {Number} height
30323 * @return {Roo.BasicDialog} this
30325 resizeTo : function(width, height){
30326 this.el.setSize(width, height);
30327 this.size = {width: width, height: height};
30328 this.syncBodyHeight();
30329 if(this.fixedcenter){
30332 if(this.isVisible()){
30333 this.constrainXY();
30334 this.adjustAssets();
30336 this.fireEvent("resize", this, width, height);
30342 * Resizes the dialog to fit the specified content size.
30343 * @param {Number} width
30344 * @param {Number} height
30345 * @return {Roo.BasicDialog} this
30347 setContentSize : function(w, h){
30348 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30349 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30350 //if(!this.el.isBorderBox()){
30351 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30352 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30355 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30356 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30358 this.resizeTo(w, h);
30363 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30364 * executed in response to a particular key being pressed while the dialog is active.
30365 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30366 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30367 * @param {Function} fn The function to call
30368 * @param {Object} scope (optional) The scope of the function
30369 * @return {Roo.BasicDialog} this
30371 addKeyListener : function(key, fn, scope){
30372 var keyCode, shift, ctrl, alt;
30373 if(typeof key == "object" && !(key instanceof Array)){
30374 keyCode = key["key"];
30375 shift = key["shift"];
30376 ctrl = key["ctrl"];
30381 var handler = function(dlg, e){
30382 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30383 var k = e.getKey();
30384 if(keyCode instanceof Array){
30385 for(var i = 0, len = keyCode.length; i < len; i++){
30386 if(keyCode[i] == k){
30387 fn.call(scope || window, dlg, k, e);
30393 fn.call(scope || window, dlg, k, e);
30398 this.on("keydown", handler);
30403 * Returns the TabPanel component (creates it if it doesn't exist).
30404 * Note: If you wish to simply check for the existence of tabs without creating them,
30405 * check for a null 'tabs' property.
30406 * @return {Roo.TabPanel} The tabs component
30408 getTabs : function(){
30410 this.el.addClass("x-dlg-auto-tabs");
30411 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30412 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30418 * Adds a button to the footer section of the dialog.
30419 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30420 * object or a valid Roo.DomHelper element config
30421 * @param {Function} handler The function called when the button is clicked
30422 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30423 * @return {Roo.Button} The new button
30425 addButton : function(config, handler, scope){
30426 var dh = Roo.DomHelper;
30428 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30430 if(!this.btnContainer){
30431 var tb = this.footer.createChild({
30433 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30434 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30436 this.btnContainer = tb.firstChild.firstChild.firstChild;
30441 minWidth: this.minButtonWidth,
30444 if(typeof config == "string"){
30445 bconfig.text = config;
30448 bconfig.dhconfig = config;
30450 Roo.apply(bconfig, config);
30454 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30455 bconfig.position = Math.max(0, bconfig.position);
30456 fc = this.btnContainer.childNodes[bconfig.position];
30459 var btn = new Roo.Button(
30461 this.btnContainer.insertBefore(document.createElement("td"),fc)
30462 : this.btnContainer.appendChild(document.createElement("td")),
30463 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30466 this.syncBodyHeight();
30469 * Array of all the buttons that have been added to this dialog via addButton
30474 this.buttons.push(btn);
30479 * Sets the default button to be focused when the dialog is displayed.
30480 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30481 * @return {Roo.BasicDialog} this
30483 setDefaultButton : function(btn){
30484 this.defaultButton = btn;
30489 getHeaderFooterHeight : function(safe){
30492 height += this.header.getHeight();
30495 var fm = this.footer.getMargins();
30496 height += (this.footer.getHeight()+fm.top+fm.bottom);
30498 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30499 height += this.centerBg.getPadding("tb");
30504 syncBodyHeight : function()
30506 var bd = this.body, // the text
30507 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30509 var height = this.size.height - this.getHeaderFooterHeight(false);
30510 bd.setHeight(height-bd.getMargins("tb"));
30511 var hh = this.header.getHeight();
30512 var h = this.size.height-hh;
30515 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30516 bw.setHeight(h-cb.getPadding("tb"));
30518 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30519 bd.setWidth(bw.getWidth(true));
30521 this.tabs.syncHeight();
30523 this.tabs.el.repaint();
30529 * Restores the previous state of the dialog if Roo.state is configured.
30530 * @return {Roo.BasicDialog} this
30532 restoreState : function(){
30533 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30534 if(box && box.width){
30535 this.xy = [box.x, box.y];
30536 this.resizeTo(box.width, box.height);
30542 beforeShow : function(){
30544 if(this.fixedcenter){
30545 this.xy = this.el.getCenterXY(true);
30548 Roo.get(document.body).addClass("x-body-masked");
30549 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30552 this.constrainXY();
30556 animShow : function(){
30557 var b = Roo.get(this.animateTarget).getBox();
30558 this.proxy.setSize(b.width, b.height);
30559 this.proxy.setLocation(b.x, b.y);
30561 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30562 true, .35, this.showEl.createDelegate(this));
30566 * Shows the dialog.
30567 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30568 * @return {Roo.BasicDialog} this
30570 show : function(animateTarget){
30571 if (this.fireEvent("beforeshow", this) === false){
30574 if(this.syncHeightBeforeShow){
30575 this.syncBodyHeight();
30576 }else if(this.firstShow){
30577 this.firstShow = false;
30578 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30580 this.animateTarget = animateTarget || this.animateTarget;
30581 if(!this.el.isVisible()){
30583 if(this.animateTarget && Roo.get(this.animateTarget)){
30593 showEl : function(){
30595 this.el.setXY(this.xy);
30597 this.adjustAssets(true);
30600 // IE peekaboo bug - fix found by Dave Fenwick
30604 this.fireEvent("show", this);
30608 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30609 * dialog itself will receive focus.
30611 focus : function(){
30612 if(this.defaultButton){
30613 this.defaultButton.focus();
30615 this.focusEl.focus();
30620 constrainXY : function(){
30621 if(this.constraintoviewport !== false){
30622 if(!this.viewSize){
30623 if(this.container){
30624 var s = this.container.getSize();
30625 this.viewSize = [s.width, s.height];
30627 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30630 var s = Roo.get(this.container||document).getScroll();
30632 var x = this.xy[0], y = this.xy[1];
30633 var w = this.size.width, h = this.size.height;
30634 var vw = this.viewSize[0], vh = this.viewSize[1];
30635 // only move it if it needs it
30637 // first validate right/bottom
30638 if(x + w > vw+s.left){
30642 if(y + h > vh+s.top){
30646 // then make sure top/left isn't negative
30658 if(this.isVisible()){
30659 this.el.setLocation(x, y);
30660 this.adjustAssets();
30667 onDrag : function(){
30668 if(!this.proxyDrag){
30669 this.xy = this.el.getXY();
30670 this.adjustAssets();
30675 adjustAssets : function(doShow){
30676 var x = this.xy[0], y = this.xy[1];
30677 var w = this.size.width, h = this.size.height;
30678 if(doShow === true){
30680 this.shadow.show(this.el);
30686 if(this.shadow && this.shadow.isVisible()){
30687 this.shadow.show(this.el);
30689 if(this.shim && this.shim.isVisible()){
30690 this.shim.setBounds(x, y, w, h);
30695 adjustViewport : function(w, h){
30697 w = Roo.lib.Dom.getViewWidth();
30698 h = Roo.lib.Dom.getViewHeight();
30701 this.viewSize = [w, h];
30702 if(this.modal && this.mask.isVisible()){
30703 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30704 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30706 if(this.isVisible()){
30707 this.constrainXY();
30712 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30713 * shadow, proxy, mask, etc.) Also removes all event listeners.
30714 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30716 destroy : function(removeEl){
30717 if(this.isVisible()){
30718 this.animateTarget = null;
30721 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30723 this.tabs.destroy(removeEl);
30736 for(var i = 0, len = this.buttons.length; i < len; i++){
30737 this.buttons[i].destroy();
30740 this.el.removeAllListeners();
30741 if(removeEl === true){
30742 this.el.update("");
30745 Roo.DialogManager.unregister(this);
30749 startMove : function(){
30750 if(this.proxyDrag){
30753 if(this.constraintoviewport !== false){
30754 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30759 endMove : function(){
30760 if(!this.proxyDrag){
30761 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30763 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30766 this.refreshSize();
30767 this.adjustAssets();
30769 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30773 * Brings this dialog to the front of any other visible dialogs
30774 * @return {Roo.BasicDialog} this
30776 toFront : function(){
30777 Roo.DialogManager.bringToFront(this);
30782 * Sends this dialog to the back (under) of any other visible dialogs
30783 * @return {Roo.BasicDialog} this
30785 toBack : function(){
30786 Roo.DialogManager.sendToBack(this);
30791 * Centers this dialog in the viewport
30792 * @return {Roo.BasicDialog} this
30794 center : function(){
30795 var xy = this.el.getCenterXY(true);
30796 this.moveTo(xy[0], xy[1]);
30801 * Moves the dialog's top-left corner to the specified point
30802 * @param {Number} x
30803 * @param {Number} y
30804 * @return {Roo.BasicDialog} this
30806 moveTo : function(x, y){
30808 if(this.isVisible()){
30809 this.el.setXY(this.xy);
30810 this.adjustAssets();
30816 * Aligns the dialog to the specified element
30817 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30818 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30819 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30820 * @return {Roo.BasicDialog} this
30822 alignTo : function(element, position, offsets){
30823 this.xy = this.el.getAlignToXY(element, position, offsets);
30824 if(this.isVisible()){
30825 this.el.setXY(this.xy);
30826 this.adjustAssets();
30832 * Anchors an element to another element and realigns it when the window is resized.
30833 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30834 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30835 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30836 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30837 * is a number, it is used as the buffer delay (defaults to 50ms).
30838 * @return {Roo.BasicDialog} this
30840 anchorTo : function(el, alignment, offsets, monitorScroll){
30841 var action = function(){
30842 this.alignTo(el, alignment, offsets);
30844 Roo.EventManager.onWindowResize(action, this);
30845 var tm = typeof monitorScroll;
30846 if(tm != 'undefined'){
30847 Roo.EventManager.on(window, 'scroll', action, this,
30848 {buffer: tm == 'number' ? monitorScroll : 50});
30855 * Returns true if the dialog is visible
30856 * @return {Boolean}
30858 isVisible : function(){
30859 return this.el.isVisible();
30863 animHide : function(callback){
30864 var b = Roo.get(this.animateTarget).getBox();
30866 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30868 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30869 this.hideEl.createDelegate(this, [callback]));
30873 * Hides the dialog.
30874 * @param {Function} callback (optional) Function to call when the dialog is hidden
30875 * @return {Roo.BasicDialog} this
30877 hide : function(callback){
30878 if (this.fireEvent("beforehide", this) === false){
30882 this.shadow.hide();
30887 // sometimes animateTarget seems to get set.. causing problems...
30888 // this just double checks..
30889 if(this.animateTarget && Roo.get(this.animateTarget)) {
30890 this.animHide(callback);
30893 this.hideEl(callback);
30899 hideEl : function(callback){
30903 Roo.get(document.body).removeClass("x-body-masked");
30905 this.fireEvent("hide", this);
30906 if(typeof callback == "function"){
30912 hideAction : function(){
30913 this.setLeft("-10000px");
30914 this.setTop("-10000px");
30915 this.setStyle("visibility", "hidden");
30919 refreshSize : function(){
30920 this.size = this.el.getSize();
30921 this.xy = this.el.getXY();
30922 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30926 // z-index is managed by the DialogManager and may be overwritten at any time
30927 setZIndex : function(index){
30929 this.mask.setStyle("z-index", index);
30932 this.shim.setStyle("z-index", ++index);
30935 this.shadow.setZIndex(++index);
30937 this.el.setStyle("z-index", ++index);
30939 this.proxy.setStyle("z-index", ++index);
30942 this.resizer.proxy.setStyle("z-index", ++index);
30945 this.lastZIndex = index;
30949 * Returns the element for this dialog
30950 * @return {Roo.Element} The underlying dialog Element
30952 getEl : function(){
30958 * @class Roo.DialogManager
30959 * Provides global access to BasicDialogs that have been created and
30960 * support for z-indexing (layering) multiple open dialogs.
30962 Roo.DialogManager = function(){
30964 var accessList = [];
30968 var sortDialogs = function(d1, d2){
30969 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
30973 var orderDialogs = function(){
30974 accessList.sort(sortDialogs);
30975 var seed = Roo.DialogManager.zseed;
30976 for(var i = 0, len = accessList.length; i < len; i++){
30977 var dlg = accessList[i];
30979 dlg.setZIndex(seed + (i*10));
30986 * The starting z-index for BasicDialogs (defaults to 9000)
30987 * @type Number The z-index value
30992 register : function(dlg){
30993 list[dlg.id] = dlg;
30994 accessList.push(dlg);
30998 unregister : function(dlg){
30999 delete list[dlg.id];
31002 if(!accessList.indexOf){
31003 for( i = 0, len = accessList.length; i < len; i++){
31004 if(accessList[i] == dlg){
31005 accessList.splice(i, 1);
31010 i = accessList.indexOf(dlg);
31012 accessList.splice(i, 1);
31018 * Gets a registered dialog by id
31019 * @param {String/Object} id The id of the dialog or a dialog
31020 * @return {Roo.BasicDialog} this
31022 get : function(id){
31023 return typeof id == "object" ? id : list[id];
31027 * Brings the specified dialog to the front
31028 * @param {String/Object} dlg The id of the dialog or a dialog
31029 * @return {Roo.BasicDialog} this
31031 bringToFront : function(dlg){
31032 dlg = this.get(dlg);
31035 dlg._lastAccess = new Date().getTime();
31042 * Sends the specified dialog to the back
31043 * @param {String/Object} dlg The id of the dialog or a dialog
31044 * @return {Roo.BasicDialog} this
31046 sendToBack : function(dlg){
31047 dlg = this.get(dlg);
31048 dlg._lastAccess = -(new Date().getTime());
31054 * Hides all dialogs
31056 hideAll : function(){
31057 for(var id in list){
31058 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31067 * @class Roo.LayoutDialog
31068 * @extends Roo.BasicDialog
31069 * Dialog which provides adjustments for working with a layout in a Dialog.
31070 * Add your necessary layout config options to the dialog's config.<br>
31071 * Example usage (including a nested layout):
31074 dialog = new Roo.LayoutDialog("download-dlg", {
31083 // layout config merges with the dialog config
31085 tabPosition: "top",
31086 alwaysShowTabs: true
31089 dialog.addKeyListener(27, dialog.hide, dialog);
31090 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31091 dialog.addButton("Build It!", this.getDownload, this);
31093 // we can even add nested layouts
31094 var innerLayout = new Roo.BorderLayout("dl-inner", {
31104 innerLayout.beginUpdate();
31105 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31106 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31107 innerLayout.endUpdate(true);
31109 var layout = dialog.getLayout();
31110 layout.beginUpdate();
31111 layout.add("center", new Roo.ContentPanel("standard-panel",
31112 {title: "Download the Source", fitToFrame:true}));
31113 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31114 {title: "Build your own roo.js"}));
31115 layout.getRegion("center").showPanel(sp);
31116 layout.endUpdate();
31120 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31121 * @param {Object} config configuration options
31123 Roo.LayoutDialog = function(el, cfg){
31126 if (typeof(cfg) == 'undefined') {
31127 config = Roo.apply({}, el);
31128 // not sure why we use documentElement here.. - it should always be body.
31129 // IE7 borks horribly if we use documentElement.
31130 // webkit also does not like documentElement - it creates a body element...
31131 el = Roo.get( document.body || document.documentElement ).createChild();
31132 //config.autoCreate = true;
31136 config.autoTabs = false;
31137 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31138 this.body.setStyle({overflow:"hidden", position:"relative"});
31139 this.layout = new Roo.BorderLayout(this.body.dom, config);
31140 this.layout.monitorWindowResize = false;
31141 this.el.addClass("x-dlg-auto-layout");
31142 // fix case when center region overwrites center function
31143 this.center = Roo.BasicDialog.prototype.center;
31144 this.on("show", this.layout.layout, this.layout, true);
31145 if (config.items) {
31146 var xitems = config.items;
31147 delete config.items;
31148 Roo.each(xitems, this.addxtype, this);
31153 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31155 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31158 endUpdate : function(){
31159 this.layout.endUpdate();
31163 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31166 beginUpdate : function(){
31167 this.layout.beginUpdate();
31171 * Get the BorderLayout for this dialog
31172 * @return {Roo.BorderLayout}
31174 getLayout : function(){
31175 return this.layout;
31178 showEl : function(){
31179 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31181 this.layout.layout();
31186 // Use the syncHeightBeforeShow config option to control this automatically
31187 syncBodyHeight : function(){
31188 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31189 if(this.layout){this.layout.layout();}
31193 * Add an xtype element (actually adds to the layout.)
31194 * @return {Object} xdata xtype object data.
31197 addxtype : function(c) {
31198 return this.layout.addxtype(c);
31202 * Ext JS Library 1.1.1
31203 * Copyright(c) 2006-2007, Ext JS, LLC.
31205 * Originally Released Under LGPL - original licence link has changed is not relivant.
31208 * <script type="text/javascript">
31212 * @class Roo.MessageBox
31213 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31217 Roo.Msg.alert('Status', 'Changes saved successfully.');
31219 // Prompt for user data:
31220 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31222 // process text value...
31226 // Show a dialog using config options:
31228 title:'Save Changes?',
31229 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31230 buttons: Roo.Msg.YESNOCANCEL,
31237 Roo.MessageBox = function(){
31238 var dlg, opt, mask, waitTimer;
31239 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31240 var buttons, activeTextEl, bwidth;
31243 var handleButton = function(button){
31245 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31249 var handleHide = function(){
31250 if(opt && opt.cls){
31251 dlg.el.removeClass(opt.cls);
31254 Roo.TaskMgr.stop(waitTimer);
31260 var updateButtons = function(b){
31263 buttons["ok"].hide();
31264 buttons["cancel"].hide();
31265 buttons["yes"].hide();
31266 buttons["no"].hide();
31267 dlg.footer.dom.style.display = 'none';
31270 dlg.footer.dom.style.display = '';
31271 for(var k in buttons){
31272 if(typeof buttons[k] != "function"){
31275 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31276 width += buttons[k].el.getWidth()+15;
31286 var handleEsc = function(d, k, e){
31287 if(opt && opt.closable !== false){
31297 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31298 * @return {Roo.BasicDialog} The BasicDialog element
31300 getDialog : function(){
31302 dlg = new Roo.BasicDialog("x-msg-box", {
31307 constraintoviewport:false,
31309 collapsible : false,
31312 width:400, height:100,
31313 buttonAlign:"center",
31314 closeClick : function(){
31315 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31316 handleButton("no");
31318 handleButton("cancel");
31322 dlg.on("hide", handleHide);
31324 dlg.addKeyListener(27, handleEsc);
31326 var bt = this.buttonText;
31327 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31328 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31329 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31330 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31331 bodyEl = dlg.body.createChild({
31333 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>'
31335 msgEl = bodyEl.dom.firstChild;
31336 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31337 textboxEl.enableDisplayMode();
31338 textboxEl.addKeyListener([10,13], function(){
31339 if(dlg.isVisible() && opt && opt.buttons){
31340 if(opt.buttons.ok){
31341 handleButton("ok");
31342 }else if(opt.buttons.yes){
31343 handleButton("yes");
31347 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31348 textareaEl.enableDisplayMode();
31349 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31350 progressEl.enableDisplayMode();
31351 var pf = progressEl.dom.firstChild;
31353 pp = Roo.get(pf.firstChild);
31354 pp.setHeight(pf.offsetHeight);
31362 * Updates the message box body text
31363 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31364 * the XHTML-compliant non-breaking space character '&#160;')
31365 * @return {Roo.MessageBox} This message box
31367 updateText : function(text){
31368 if(!dlg.isVisible() && !opt.width){
31369 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31371 msgEl.innerHTML = text || ' ';
31373 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31374 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31376 Math.min(opt.width || cw , this.maxWidth),
31377 Math.max(opt.minWidth || this.minWidth, bwidth)
31380 activeTextEl.setWidth(w);
31382 if(dlg.isVisible()){
31383 dlg.fixedcenter = false;
31385 // to big, make it scroll. = But as usual stupid IE does not support
31388 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31389 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31390 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31392 bodyEl.dom.style.height = '';
31393 bodyEl.dom.style.overflowY = '';
31396 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31398 bodyEl.dom.style.overflowX = '';
31401 dlg.setContentSize(w, bodyEl.getHeight());
31402 if(dlg.isVisible()){
31403 dlg.fixedcenter = true;
31409 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31410 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31411 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31412 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31413 * @return {Roo.MessageBox} This message box
31415 updateProgress : function(value, text){
31417 this.updateText(text);
31419 if (pp) { // weird bug on my firefox - for some reason this is not defined
31420 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31426 * Returns true if the message box is currently displayed
31427 * @return {Boolean} True if the message box is visible, else false
31429 isVisible : function(){
31430 return dlg && dlg.isVisible();
31434 * Hides the message box if it is displayed
31437 if(this.isVisible()){
31443 * Displays a new message box, or reinitializes an existing message box, based on the config options
31444 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31445 * The following config object properties are supported:
31447 Property Type Description
31448 ---------- --------------- ------------------------------------------------------------------------------------
31449 animEl String/Element An id or Element from which the message box should animate as it opens and
31450 closes (defaults to undefined)
31451 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31452 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31453 closable Boolean False to hide the top-right close button (defaults to true). Note that
31454 progress and wait dialogs will ignore this property and always hide the
31455 close button as they can only be closed programmatically.
31456 cls String A custom CSS class to apply to the message box element
31457 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31458 displayed (defaults to 75)
31459 fn Function A callback function to execute after closing the dialog. The arguments to the
31460 function will be btn (the name of the button that was clicked, if applicable,
31461 e.g. "ok"), and text (the value of the active text field, if applicable).
31462 Progress and wait dialogs will ignore this option since they do not respond to
31463 user actions and can only be closed programmatically, so any required function
31464 should be called by the same code after it closes the dialog.
31465 icon String A CSS class that provides a background image to be used as an icon for
31466 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31467 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31468 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31469 modal Boolean False to allow user interaction with the page while the message box is
31470 displayed (defaults to true)
31471 msg String A string that will replace the existing message box body text (defaults
31472 to the XHTML-compliant non-breaking space character ' ')
31473 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31474 progress Boolean True to display a progress bar (defaults to false)
31475 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31476 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31477 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31478 title String The title text
31479 value String The string value to set into the active textbox element if displayed
31480 wait Boolean True to display a progress bar (defaults to false)
31481 width Number The width of the dialog in pixels
31488 msg: 'Please enter your address:',
31490 buttons: Roo.MessageBox.OKCANCEL,
31493 animEl: 'addAddressBtn'
31496 * @param {Object} config Configuration options
31497 * @return {Roo.MessageBox} This message box
31499 show : function(options)
31502 // this causes nightmares if you show one dialog after another
31503 // especially on callbacks..
31505 if(this.isVisible()){
31508 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31509 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31510 Roo.log("New Dialog Message:" + options.msg )
31511 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31512 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31515 var d = this.getDialog();
31517 d.setTitle(opt.title || " ");
31518 d.close.setDisplayed(opt.closable !== false);
31519 activeTextEl = textboxEl;
31520 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31525 textareaEl.setHeight(typeof opt.multiline == "number" ?
31526 opt.multiline : this.defaultTextHeight);
31527 activeTextEl = textareaEl;
31536 progressEl.setDisplayed(opt.progress === true);
31537 this.updateProgress(0);
31538 activeTextEl.dom.value = opt.value || "";
31540 dlg.setDefaultButton(activeTextEl);
31542 var bs = opt.buttons;
31545 db = buttons["ok"];
31546 }else if(bs && bs.yes){
31547 db = buttons["yes"];
31549 dlg.setDefaultButton(db);
31551 bwidth = updateButtons(opt.buttons);
31552 this.updateText(opt.msg);
31554 d.el.addClass(opt.cls);
31556 d.proxyDrag = opt.proxyDrag === true;
31557 d.modal = opt.modal !== false;
31558 d.mask = opt.modal !== false ? mask : false;
31559 if(!d.isVisible()){
31560 // force it to the end of the z-index stack so it gets a cursor in FF
31561 document.body.appendChild(dlg.el.dom);
31562 d.animateTarget = null;
31563 d.show(options.animEl);
31569 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31570 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31571 * and closing the message box when the process is complete.
31572 * @param {String} title The title bar text
31573 * @param {String} msg The message box body text
31574 * @return {Roo.MessageBox} This message box
31576 progress : function(title, msg){
31583 minWidth: this.minProgressWidth,
31590 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31591 * If a callback function is passed it will be called after the user clicks the button, and the
31592 * id of the button that was clicked will be passed as the only parameter to the callback
31593 * (could also be the top-right close button).
31594 * @param {String} title The title bar text
31595 * @param {String} msg The message box body text
31596 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31597 * @param {Object} scope (optional) The scope of the callback function
31598 * @return {Roo.MessageBox} This message box
31600 alert : function(title, msg, fn, scope){
31613 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31614 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31615 * You are responsible for closing the message box when the process is complete.
31616 * @param {String} msg The message box body text
31617 * @param {String} title (optional) The title bar text
31618 * @return {Roo.MessageBox} This message box
31620 wait : function(msg, title){
31631 waitTimer = Roo.TaskMgr.start({
31633 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31641 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31642 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31643 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31644 * @param {String} title The title bar text
31645 * @param {String} msg The message box body text
31646 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31647 * @param {Object} scope (optional) The scope of the callback function
31648 * @return {Roo.MessageBox} This message box
31650 confirm : function(title, msg, fn, scope){
31654 buttons: this.YESNO,
31663 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31664 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31665 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31666 * (could also be the top-right close button) and the text that was entered will be passed as the two
31667 * parameters to the callback.
31668 * @param {String} title The title bar text
31669 * @param {String} msg The message box body text
31670 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31671 * @param {Object} scope (optional) The scope of the callback function
31672 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31673 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31674 * @return {Roo.MessageBox} This message box
31676 prompt : function(title, msg, fn, scope, multiline){
31680 buttons: this.OKCANCEL,
31685 multiline: multiline,
31692 * Button config that displays a single OK button
31697 * Button config that displays Yes and No buttons
31700 YESNO : {yes:true, no:true},
31702 * Button config that displays OK and Cancel buttons
31705 OKCANCEL : {ok:true, cancel:true},
31707 * Button config that displays Yes, No and Cancel buttons
31710 YESNOCANCEL : {yes:true, no:true, cancel:true},
31713 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31716 defaultTextHeight : 75,
31718 * The maximum width in pixels of the message box (defaults to 600)
31723 * The minimum width in pixels of the message box (defaults to 100)
31728 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31729 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31732 minProgressWidth : 250,
31734 * An object containing the default button text strings that can be overriden for localized language support.
31735 * Supported properties are: ok, cancel, yes and no.
31736 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31749 * Shorthand for {@link Roo.MessageBox}
31751 Roo.Msg = Roo.MessageBox;/*
31753 * Ext JS Library 1.1.1
31754 * Copyright(c) 2006-2007, Ext JS, LLC.
31756 * Originally Released Under LGPL - original licence link has changed is not relivant.
31759 * <script type="text/javascript">
31762 * @class Roo.QuickTips
31763 * Provides attractive and customizable tooltips for any element.
31766 Roo.QuickTips = function(){
31767 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31768 var ce, bd, xy, dd;
31769 var visible = false, disabled = true, inited = false;
31770 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31772 var onOver = function(e){
31776 var t = e.getTarget();
31777 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31780 if(ce && t == ce.el){
31781 clearTimeout(hideProc);
31784 if(t && tagEls[t.id]){
31785 tagEls[t.id].el = t;
31786 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31789 var ttp, et = Roo.fly(t);
31790 var ns = cfg.namespace;
31791 if(tm.interceptTitles && t.title){
31794 t.removeAttribute("title");
31795 e.preventDefault();
31797 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31800 showProc = show.defer(tm.showDelay, tm, [{
31803 width: et.getAttributeNS(ns, cfg.width),
31804 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31805 title: et.getAttributeNS(ns, cfg.title),
31806 cls: et.getAttributeNS(ns, cfg.cls)
31811 var onOut = function(e){
31812 clearTimeout(showProc);
31813 var t = e.getTarget();
31814 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31815 hideProc = setTimeout(hide, tm.hideDelay);
31819 var onMove = function(e){
31825 if(tm.trackMouse && ce){
31830 var onDown = function(e){
31831 clearTimeout(showProc);
31832 clearTimeout(hideProc);
31834 if(tm.hideOnClick){
31837 tm.enable.defer(100, tm);
31842 var getPad = function(){
31843 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31846 var show = function(o){
31850 clearTimeout(dismissProc);
31852 if(removeCls){ // in case manually hidden
31853 el.removeClass(removeCls);
31857 el.addClass(ce.cls);
31858 removeCls = ce.cls;
31861 tipTitle.update(ce.title);
31864 tipTitle.update('');
31867 el.dom.style.width = tm.maxWidth+'px';
31868 //tipBody.dom.style.width = '';
31869 tipBodyText.update(o.text);
31870 var p = getPad(), w = ce.width;
31872 var td = tipBodyText.dom;
31873 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31874 if(aw > tm.maxWidth){
31876 }else if(aw < tm.minWidth){
31882 //tipBody.setWidth(w);
31883 el.setWidth(parseInt(w, 10) + p);
31884 if(ce.autoHide === false){
31885 close.setDisplayed(true);
31890 close.setDisplayed(false);
31896 el.avoidY = xy[1]-18;
31901 el.setStyle("visibility", "visible");
31902 el.fadeIn({callback: afterShow});
31908 var afterShow = function(){
31912 if(tm.autoDismiss && ce.autoHide !== false){
31913 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31918 var hide = function(noanim){
31919 clearTimeout(dismissProc);
31920 clearTimeout(hideProc);
31922 if(el.isVisible()){
31924 if(noanim !== true && tm.animate){
31925 el.fadeOut({callback: afterHide});
31932 var afterHide = function(){
31935 el.removeClass(removeCls);
31942 * @cfg {Number} minWidth
31943 * The minimum width of the quick tip (defaults to 40)
31947 * @cfg {Number} maxWidth
31948 * The maximum width of the quick tip (defaults to 300)
31952 * @cfg {Boolean} interceptTitles
31953 * True to automatically use the element's DOM title value if available (defaults to false)
31955 interceptTitles : false,
31957 * @cfg {Boolean} trackMouse
31958 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31960 trackMouse : false,
31962 * @cfg {Boolean} hideOnClick
31963 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
31965 hideOnClick : true,
31967 * @cfg {Number} showDelay
31968 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
31972 * @cfg {Number} hideDelay
31973 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
31977 * @cfg {Boolean} autoHide
31978 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
31979 * Used in conjunction with hideDelay.
31984 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
31985 * (defaults to true). Used in conjunction with autoDismissDelay.
31987 autoDismiss : true,
31990 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
31992 autoDismissDelay : 5000,
31994 * @cfg {Boolean} animate
31995 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32000 * @cfg {String} title
32001 * Title text to display (defaults to ''). This can be any valid HTML markup.
32005 * @cfg {String} text
32006 * Body text to display (defaults to ''). This can be any valid HTML markup.
32010 * @cfg {String} cls
32011 * A CSS class to apply to the base quick tip element (defaults to '').
32015 * @cfg {Number} width
32016 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32017 * minWidth or maxWidth.
32022 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32023 * or display QuickTips in a page.
32026 tm = Roo.QuickTips;
32027 cfg = tm.tagConfig;
32029 if(!Roo.isReady){ // allow calling of init() before onReady
32030 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32033 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32034 el.fxDefaults = {stopFx: true};
32035 // maximum custom styling
32036 //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>');
32037 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>');
32038 tipTitle = el.child('h3');
32039 tipTitle.enableDisplayMode("block");
32040 tipBody = el.child('div.x-tip-bd');
32041 tipBodyText = el.child('div.x-tip-bd-inner');
32042 //bdLeft = el.child('div.x-tip-bd-left');
32043 //bdRight = el.child('div.x-tip-bd-right');
32044 close = el.child('div.x-tip-close');
32045 close.enableDisplayMode("block");
32046 close.on("click", hide);
32047 var d = Roo.get(document);
32048 d.on("mousedown", onDown);
32049 d.on("mouseover", onOver);
32050 d.on("mouseout", onOut);
32051 d.on("mousemove", onMove);
32052 esc = d.addKeyListener(27, hide);
32055 dd = el.initDD("default", null, {
32056 onDrag : function(){
32060 dd.setHandleElId(tipTitle.id);
32069 * Configures a new quick tip instance and assigns it to a target element. The following config options
32072 Property Type Description
32073 ---------- --------------------- ------------------------------------------------------------------------
32074 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32076 * @param {Object} config The config object
32078 register : function(config){
32079 var cs = config instanceof Array ? config : arguments;
32080 for(var i = 0, len = cs.length; i < len; i++) {
32082 var target = c.target;
32084 if(target instanceof Array){
32085 for(var j = 0, jlen = target.length; j < jlen; j++){
32086 tagEls[target[j]] = c;
32089 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32096 * Removes this quick tip from its element and destroys it.
32097 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32099 unregister : function(el){
32100 delete tagEls[Roo.id(el)];
32104 * Enable this quick tip.
32106 enable : function(){
32107 if(inited && disabled){
32109 if(locks.length < 1){
32116 * Disable this quick tip.
32118 disable : function(){
32120 clearTimeout(showProc);
32121 clearTimeout(hideProc);
32122 clearTimeout(dismissProc);
32130 * Returns true if the quick tip is enabled, else false.
32132 isEnabled : function(){
32139 attribute : "qtip",
32149 // backwards compat
32150 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32152 * Ext JS Library 1.1.1
32153 * Copyright(c) 2006-2007, Ext JS, LLC.
32155 * Originally Released Under LGPL - original licence link has changed is not relivant.
32158 * <script type="text/javascript">
32163 * @class Roo.tree.TreePanel
32164 * @extends Roo.data.Tree
32166 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32167 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32168 * @cfg {Boolean} enableDD true to enable drag and drop
32169 * @cfg {Boolean} enableDrag true to enable just drag
32170 * @cfg {Boolean} enableDrop true to enable just drop
32171 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32172 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32173 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32174 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32175 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32176 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32177 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32178 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32179 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32180 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32181 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32182 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32183 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32184 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32185 * @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>
32186 * @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>
32189 * @param {String/HTMLElement/Element} el The container element
32190 * @param {Object} config
32192 Roo.tree.TreePanel = function(el, config){
32194 var loader = false;
32196 root = config.root;
32197 delete config.root;
32199 if (config.loader) {
32200 loader = config.loader;
32201 delete config.loader;
32204 Roo.apply(this, config);
32205 Roo.tree.TreePanel.superclass.constructor.call(this);
32206 this.el = Roo.get(el);
32207 this.el.addClass('x-tree');
32208 //console.log(root);
32210 this.setRootNode( Roo.factory(root, Roo.tree));
32213 this.loader = Roo.factory(loader, Roo.tree);
32216 * Read-only. The id of the container element becomes this TreePanel's id.
32218 this.id = this.el.id;
32221 * @event beforeload
32222 * Fires before a node is loaded, return false to cancel
32223 * @param {Node} node The node being loaded
32225 "beforeload" : true,
32228 * Fires when a node is loaded
32229 * @param {Node} node The node that was loaded
32233 * @event textchange
32234 * Fires when the text for a node is changed
32235 * @param {Node} node The node
32236 * @param {String} text The new text
32237 * @param {String} oldText The old text
32239 "textchange" : true,
32241 * @event beforeexpand
32242 * Fires before a node is expanded, return false to cancel.
32243 * @param {Node} node The node
32244 * @param {Boolean} deep
32245 * @param {Boolean} anim
32247 "beforeexpand" : true,
32249 * @event beforecollapse
32250 * Fires before a node is collapsed, return false to cancel.
32251 * @param {Node} node The node
32252 * @param {Boolean} deep
32253 * @param {Boolean} anim
32255 "beforecollapse" : true,
32258 * Fires when a node is expanded
32259 * @param {Node} node The node
32263 * @event disabledchange
32264 * Fires when the disabled status of a node changes
32265 * @param {Node} node The node
32266 * @param {Boolean} disabled
32268 "disabledchange" : true,
32271 * Fires when a node is collapsed
32272 * @param {Node} node The node
32276 * @event beforeclick
32277 * Fires before click processing on a node. Return false to cancel the default action.
32278 * @param {Node} node The node
32279 * @param {Roo.EventObject} e The event object
32281 "beforeclick":true,
32283 * @event checkchange
32284 * Fires when a node with a checkbox's checked property changes
32285 * @param {Node} this This node
32286 * @param {Boolean} checked
32288 "checkchange":true,
32291 * Fires when a node is clicked
32292 * @param {Node} node The node
32293 * @param {Roo.EventObject} e The event object
32298 * Fires when a node is double clicked
32299 * @param {Node} node The node
32300 * @param {Roo.EventObject} e The event object
32304 * @event contextmenu
32305 * Fires when a node is right clicked
32306 * @param {Node} node The node
32307 * @param {Roo.EventObject} e The event object
32309 "contextmenu":true,
32311 * @event beforechildrenrendered
32312 * Fires right before the child nodes for a node are rendered
32313 * @param {Node} node The node
32315 "beforechildrenrendered":true,
32318 * Fires when a node starts being dragged
32319 * @param {Roo.tree.TreePanel} this
32320 * @param {Roo.tree.TreeNode} node
32321 * @param {event} e The raw browser event
32323 "startdrag" : true,
32326 * Fires when a drag operation is complete
32327 * @param {Roo.tree.TreePanel} this
32328 * @param {Roo.tree.TreeNode} node
32329 * @param {event} e The raw browser event
32334 * Fires when a dragged node is dropped on a valid DD target
32335 * @param {Roo.tree.TreePanel} this
32336 * @param {Roo.tree.TreeNode} node
32337 * @param {DD} dd The dd it was dropped on
32338 * @param {event} e The raw browser event
32342 * @event beforenodedrop
32343 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32344 * passed to handlers has the following properties:<br />
32345 * <ul style="padding:5px;padding-left:16px;">
32346 * <li>tree - The TreePanel</li>
32347 * <li>target - The node being targeted for the drop</li>
32348 * <li>data - The drag data from the drag source</li>
32349 * <li>point - The point of the drop - append, above or below</li>
32350 * <li>source - The drag source</li>
32351 * <li>rawEvent - Raw mouse event</li>
32352 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32353 * to be inserted by setting them on this object.</li>
32354 * <li>cancel - Set this to true to cancel the drop.</li>
32356 * @param {Object} dropEvent
32358 "beforenodedrop" : true,
32361 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32362 * passed to handlers has the following properties:<br />
32363 * <ul style="padding:5px;padding-left:16px;">
32364 * <li>tree - The TreePanel</li>
32365 * <li>target - The node being targeted for the drop</li>
32366 * <li>data - The drag data from the drag source</li>
32367 * <li>point - The point of the drop - append, above or below</li>
32368 * <li>source - The drag source</li>
32369 * <li>rawEvent - Raw mouse event</li>
32370 * <li>dropNode - Dropped node(s).</li>
32372 * @param {Object} dropEvent
32376 * @event nodedragover
32377 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32378 * passed to handlers has the following properties:<br />
32379 * <ul style="padding:5px;padding-left:16px;">
32380 * <li>tree - The TreePanel</li>
32381 * <li>target - The node being targeted for the drop</li>
32382 * <li>data - The drag data from the drag source</li>
32383 * <li>point - The point of the drop - append, above or below</li>
32384 * <li>source - The drag source</li>
32385 * <li>rawEvent - Raw mouse event</li>
32386 * <li>dropNode - Drop node(s) provided by the source.</li>
32387 * <li>cancel - Set this to true to signal drop not allowed.</li>
32389 * @param {Object} dragOverEvent
32391 "nodedragover" : true
32394 if(this.singleExpand){
32395 this.on("beforeexpand", this.restrictExpand, this);
32398 this.editor.tree = this;
32399 this.editor = Roo.factory(this.editor, Roo.tree);
32402 if (this.selModel) {
32403 this.selModel = Roo.factory(this.selModel, Roo.tree);
32407 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32408 rootVisible : true,
32409 animate: Roo.enableFx,
32412 hlDrop : Roo.enableFx,
32416 rendererTip: false,
32418 restrictExpand : function(node){
32419 var p = node.parentNode;
32421 if(p.expandedChild && p.expandedChild.parentNode == p){
32422 p.expandedChild.collapse();
32424 p.expandedChild = node;
32428 // private override
32429 setRootNode : function(node){
32430 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32431 if(!this.rootVisible){
32432 node.ui = new Roo.tree.RootTreeNodeUI(node);
32438 * Returns the container element for this TreePanel
32440 getEl : function(){
32445 * Returns the default TreeLoader for this TreePanel
32447 getLoader : function(){
32448 return this.loader;
32454 expandAll : function(){
32455 this.root.expand(true);
32459 * Collapse all nodes
32461 collapseAll : function(){
32462 this.root.collapse(true);
32466 * Returns the selection model used by this TreePanel
32468 getSelectionModel : function(){
32469 if(!this.selModel){
32470 this.selModel = new Roo.tree.DefaultSelectionModel();
32472 return this.selModel;
32476 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32477 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32478 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32481 getChecked : function(a, startNode){
32482 startNode = startNode || this.root;
32484 var f = function(){
32485 if(this.attributes.checked){
32486 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32489 startNode.cascade(f);
32494 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32495 * @param {String} path
32496 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32497 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32498 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32500 expandPath : function(path, attr, callback){
32501 attr = attr || "id";
32502 var keys = path.split(this.pathSeparator);
32503 var curNode = this.root;
32504 if(curNode.attributes[attr] != keys[1]){ // invalid root
32506 callback(false, null);
32511 var f = function(){
32512 if(++index == keys.length){
32514 callback(true, curNode);
32518 var c = curNode.findChild(attr, keys[index]);
32521 callback(false, curNode);
32526 c.expand(false, false, f);
32528 curNode.expand(false, false, f);
32532 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32533 * @param {String} path
32534 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32535 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32536 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32538 selectPath : function(path, attr, callback){
32539 attr = attr || "id";
32540 var keys = path.split(this.pathSeparator);
32541 var v = keys.pop();
32542 if(keys.length > 0){
32543 var f = function(success, node){
32544 if(success && node){
32545 var n = node.findChild(attr, v);
32551 }else if(callback){
32552 callback(false, n);
32556 callback(false, n);
32560 this.expandPath(keys.join(this.pathSeparator), attr, f);
32562 this.root.select();
32564 callback(true, this.root);
32569 getTreeEl : function(){
32574 * Trigger rendering of this TreePanel
32576 render : function(){
32577 if (this.innerCt) {
32578 return this; // stop it rendering more than once!!
32581 this.innerCt = this.el.createChild({tag:"ul",
32582 cls:"x-tree-root-ct " +
32583 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32585 if(this.containerScroll){
32586 Roo.dd.ScrollManager.register(this.el);
32588 if((this.enableDD || this.enableDrop) && !this.dropZone){
32590 * The dropZone used by this tree if drop is enabled
32591 * @type Roo.tree.TreeDropZone
32593 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32594 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32597 if((this.enableDD || this.enableDrag) && !this.dragZone){
32599 * The dragZone used by this tree if drag is enabled
32600 * @type Roo.tree.TreeDragZone
32602 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32603 ddGroup: this.ddGroup || "TreeDD",
32604 scroll: this.ddScroll
32607 this.getSelectionModel().init(this);
32609 Roo.log("ROOT not set in tree");
32612 this.root.render();
32613 if(!this.rootVisible){
32614 this.root.renderChildren();
32620 * Ext JS Library 1.1.1
32621 * Copyright(c) 2006-2007, Ext JS, LLC.
32623 * Originally Released Under LGPL - original licence link has changed is not relivant.
32626 * <script type="text/javascript">
32631 * @class Roo.tree.DefaultSelectionModel
32632 * @extends Roo.util.Observable
32633 * The default single selection for a TreePanel.
32634 * @param {Object} cfg Configuration
32636 Roo.tree.DefaultSelectionModel = function(cfg){
32637 this.selNode = null;
32643 * @event selectionchange
32644 * Fires when the selected node changes
32645 * @param {DefaultSelectionModel} this
32646 * @param {TreeNode} node the new selection
32648 "selectionchange" : true,
32651 * @event beforeselect
32652 * Fires before the selected node changes, return false to cancel the change
32653 * @param {DefaultSelectionModel} this
32654 * @param {TreeNode} node the new selection
32655 * @param {TreeNode} node the old selection
32657 "beforeselect" : true
32660 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32663 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32664 init : function(tree){
32666 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32667 tree.on("click", this.onNodeClick, this);
32670 onNodeClick : function(node, e){
32671 if (e.ctrlKey && this.selNode == node) {
32672 this.unselect(node);
32680 * @param {TreeNode} node The node to select
32681 * @return {TreeNode} The selected node
32683 select : function(node){
32684 var last = this.selNode;
32685 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32687 last.ui.onSelectedChange(false);
32689 this.selNode = node;
32690 node.ui.onSelectedChange(true);
32691 this.fireEvent("selectionchange", this, node, last);
32698 * @param {TreeNode} node The node to unselect
32700 unselect : function(node){
32701 if(this.selNode == node){
32702 this.clearSelections();
32707 * Clear all selections
32709 clearSelections : function(){
32710 var n = this.selNode;
32712 n.ui.onSelectedChange(false);
32713 this.selNode = null;
32714 this.fireEvent("selectionchange", this, null);
32720 * Get the selected node
32721 * @return {TreeNode} The selected node
32723 getSelectedNode : function(){
32724 return this.selNode;
32728 * Returns true if the node is selected
32729 * @param {TreeNode} node The node to check
32730 * @return {Boolean}
32732 isSelected : function(node){
32733 return this.selNode == node;
32737 * Selects the node above the selected node in the tree, intelligently walking the nodes
32738 * @return TreeNode The new selection
32740 selectPrevious : function(){
32741 var s = this.selNode || this.lastSelNode;
32745 var ps = s.previousSibling;
32747 if(!ps.isExpanded() || ps.childNodes.length < 1){
32748 return this.select(ps);
32750 var lc = ps.lastChild;
32751 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32754 return this.select(lc);
32756 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32757 return this.select(s.parentNode);
32763 * Selects the node above the selected node in the tree, intelligently walking the nodes
32764 * @return TreeNode The new selection
32766 selectNext : function(){
32767 var s = this.selNode || this.lastSelNode;
32771 if(s.firstChild && s.isExpanded()){
32772 return this.select(s.firstChild);
32773 }else if(s.nextSibling){
32774 return this.select(s.nextSibling);
32775 }else if(s.parentNode){
32777 s.parentNode.bubble(function(){
32778 if(this.nextSibling){
32779 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32788 onKeyDown : function(e){
32789 var s = this.selNode || this.lastSelNode;
32790 // undesirable, but required
32795 var k = e.getKey();
32803 this.selectPrevious();
32806 e.preventDefault();
32807 if(s.hasChildNodes()){
32808 if(!s.isExpanded()){
32810 }else if(s.firstChild){
32811 this.select(s.firstChild, e);
32816 e.preventDefault();
32817 if(s.hasChildNodes() && s.isExpanded()){
32819 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32820 this.select(s.parentNode, e);
32828 * @class Roo.tree.MultiSelectionModel
32829 * @extends Roo.util.Observable
32830 * Multi selection for a TreePanel.
32831 * @param {Object} cfg Configuration
32833 Roo.tree.MultiSelectionModel = function(){
32834 this.selNodes = [];
32838 * @event selectionchange
32839 * Fires when the selected nodes change
32840 * @param {MultiSelectionModel} this
32841 * @param {Array} nodes Array of the selected nodes
32843 "selectionchange" : true
32845 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32849 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32850 init : function(tree){
32852 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32853 tree.on("click", this.onNodeClick, this);
32856 onNodeClick : function(node, e){
32857 this.select(node, e, e.ctrlKey);
32862 * @param {TreeNode} node The node to select
32863 * @param {EventObject} e (optional) An event associated with the selection
32864 * @param {Boolean} keepExisting True to retain existing selections
32865 * @return {TreeNode} The selected node
32867 select : function(node, e, keepExisting){
32868 if(keepExisting !== true){
32869 this.clearSelections(true);
32871 if(this.isSelected(node)){
32872 this.lastSelNode = node;
32875 this.selNodes.push(node);
32876 this.selMap[node.id] = node;
32877 this.lastSelNode = node;
32878 node.ui.onSelectedChange(true);
32879 this.fireEvent("selectionchange", this, this.selNodes);
32885 * @param {TreeNode} node The node to unselect
32887 unselect : function(node){
32888 if(this.selMap[node.id]){
32889 node.ui.onSelectedChange(false);
32890 var sn = this.selNodes;
32893 index = sn.indexOf(node);
32895 for(var i = 0, len = sn.length; i < len; i++){
32903 this.selNodes.splice(index, 1);
32905 delete this.selMap[node.id];
32906 this.fireEvent("selectionchange", this, this.selNodes);
32911 * Clear all selections
32913 clearSelections : function(suppressEvent){
32914 var sn = this.selNodes;
32916 for(var i = 0, len = sn.length; i < len; i++){
32917 sn[i].ui.onSelectedChange(false);
32919 this.selNodes = [];
32921 if(suppressEvent !== true){
32922 this.fireEvent("selectionchange", this, this.selNodes);
32928 * Returns true if the node is selected
32929 * @param {TreeNode} node The node to check
32930 * @return {Boolean}
32932 isSelected : function(node){
32933 return this.selMap[node.id] ? true : false;
32937 * Returns an array of the selected nodes
32940 getSelectedNodes : function(){
32941 return this.selNodes;
32944 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32946 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32948 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32951 * Ext JS Library 1.1.1
32952 * Copyright(c) 2006-2007, Ext JS, LLC.
32954 * Originally Released Under LGPL - original licence link has changed is not relivant.
32957 * <script type="text/javascript">
32961 * @class Roo.tree.TreeNode
32962 * @extends Roo.data.Node
32963 * @cfg {String} text The text for this node
32964 * @cfg {Boolean} expanded true to start the node expanded
32965 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
32966 * @cfg {Boolean} allowDrop false if this node cannot be drop on
32967 * @cfg {Boolean} disabled true to start the node disabled
32968 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
32969 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
32970 * @cfg {String} cls A css class to be added to the node
32971 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
32972 * @cfg {String} href URL of the link used for the node (defaults to #)
32973 * @cfg {String} hrefTarget target frame for the link
32974 * @cfg {String} qtip An Ext QuickTip for the node
32975 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
32976 * @cfg {Boolean} singleClickExpand True for single click expand on this node
32977 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
32978 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
32979 * (defaults to undefined with no checkbox rendered)
32981 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
32983 Roo.tree.TreeNode = function(attributes){
32984 attributes = attributes || {};
32985 if(typeof attributes == "string"){
32986 attributes = {text: attributes};
32988 this.childrenRendered = false;
32989 this.rendered = false;
32990 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
32991 this.expanded = attributes.expanded === true;
32992 this.isTarget = attributes.isTarget !== false;
32993 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
32994 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
32997 * Read-only. The text for this node. To change it use setText().
33000 this.text = attributes.text;
33002 * True if this node is disabled.
33005 this.disabled = attributes.disabled === true;
33009 * @event textchange
33010 * Fires when the text for this node is changed
33011 * @param {Node} this This node
33012 * @param {String} text The new text
33013 * @param {String} oldText The old text
33015 "textchange" : true,
33017 * @event beforeexpand
33018 * Fires before this node is expanded, return false to cancel.
33019 * @param {Node} this This node
33020 * @param {Boolean} deep
33021 * @param {Boolean} anim
33023 "beforeexpand" : true,
33025 * @event beforecollapse
33026 * Fires before this node is collapsed, return false to cancel.
33027 * @param {Node} this This node
33028 * @param {Boolean} deep
33029 * @param {Boolean} anim
33031 "beforecollapse" : true,
33034 * Fires when this node is expanded
33035 * @param {Node} this This node
33039 * @event disabledchange
33040 * Fires when the disabled status of this node changes
33041 * @param {Node} this This node
33042 * @param {Boolean} disabled
33044 "disabledchange" : true,
33047 * Fires when this node is collapsed
33048 * @param {Node} this This node
33052 * @event beforeclick
33053 * Fires before click processing. Return false to cancel the default action.
33054 * @param {Node} this This node
33055 * @param {Roo.EventObject} e The event object
33057 "beforeclick":true,
33059 * @event checkchange
33060 * Fires when a node with a checkbox's checked property changes
33061 * @param {Node} this This node
33062 * @param {Boolean} checked
33064 "checkchange":true,
33067 * Fires when this node is clicked
33068 * @param {Node} this This node
33069 * @param {Roo.EventObject} e The event object
33074 * Fires when this node is double clicked
33075 * @param {Node} this This node
33076 * @param {Roo.EventObject} e The event object
33080 * @event contextmenu
33081 * Fires when this node is right clicked
33082 * @param {Node} this This node
33083 * @param {Roo.EventObject} e The event object
33085 "contextmenu":true,
33087 * @event beforechildrenrendered
33088 * Fires right before the child nodes for this node are rendered
33089 * @param {Node} this This node
33091 "beforechildrenrendered":true
33094 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33097 * Read-only. The UI for this node
33100 this.ui = new uiClass(this);
33102 // finally support items[]
33103 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33108 Roo.each(this.attributes.items, function(c) {
33109 this.appendChild(Roo.factory(c,Roo.Tree));
33111 delete this.attributes.items;
33116 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33117 preventHScroll: true,
33119 * Returns true if this node is expanded
33120 * @return {Boolean}
33122 isExpanded : function(){
33123 return this.expanded;
33127 * Returns the UI object for this node
33128 * @return {TreeNodeUI}
33130 getUI : function(){
33134 // private override
33135 setFirstChild : function(node){
33136 var of = this.firstChild;
33137 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33138 if(this.childrenRendered && of && node != of){
33139 of.renderIndent(true, true);
33142 this.renderIndent(true, true);
33146 // private override
33147 setLastChild : function(node){
33148 var ol = this.lastChild;
33149 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33150 if(this.childrenRendered && ol && node != ol){
33151 ol.renderIndent(true, true);
33154 this.renderIndent(true, true);
33158 // these methods are overridden to provide lazy rendering support
33159 // private override
33160 appendChild : function()
33162 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33163 if(node && this.childrenRendered){
33166 this.ui.updateExpandIcon();
33170 // private override
33171 removeChild : function(node){
33172 this.ownerTree.getSelectionModel().unselect(node);
33173 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33174 // if it's been rendered remove dom node
33175 if(this.childrenRendered){
33178 if(this.childNodes.length < 1){
33179 this.collapse(false, false);
33181 this.ui.updateExpandIcon();
33183 if(!this.firstChild) {
33184 this.childrenRendered = false;
33189 // private override
33190 insertBefore : function(node, refNode){
33191 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33192 if(newNode && refNode && this.childrenRendered){
33195 this.ui.updateExpandIcon();
33200 * Sets the text for this node
33201 * @param {String} text
33203 setText : function(text){
33204 var oldText = this.text;
33206 this.attributes.text = text;
33207 if(this.rendered){ // event without subscribing
33208 this.ui.onTextChange(this, text, oldText);
33210 this.fireEvent("textchange", this, text, oldText);
33214 * Triggers selection of this node
33216 select : function(){
33217 this.getOwnerTree().getSelectionModel().select(this);
33221 * Triggers deselection of this node
33223 unselect : function(){
33224 this.getOwnerTree().getSelectionModel().unselect(this);
33228 * Returns true if this node is selected
33229 * @return {Boolean}
33231 isSelected : function(){
33232 return this.getOwnerTree().getSelectionModel().isSelected(this);
33236 * Expand this node.
33237 * @param {Boolean} deep (optional) True to expand all children as well
33238 * @param {Boolean} anim (optional) false to cancel the default animation
33239 * @param {Function} callback (optional) A callback to be called when
33240 * expanding this node completes (does not wait for deep expand to complete).
33241 * Called with 1 parameter, this node.
33243 expand : function(deep, anim, callback){
33244 if(!this.expanded){
33245 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33248 if(!this.childrenRendered){
33249 this.renderChildren();
33251 this.expanded = true;
33252 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33253 this.ui.animExpand(function(){
33254 this.fireEvent("expand", this);
33255 if(typeof callback == "function"){
33259 this.expandChildNodes(true);
33261 }.createDelegate(this));
33265 this.fireEvent("expand", this);
33266 if(typeof callback == "function"){
33271 if(typeof callback == "function"){
33276 this.expandChildNodes(true);
33280 isHiddenRoot : function(){
33281 return this.isRoot && !this.getOwnerTree().rootVisible;
33285 * Collapse this node.
33286 * @param {Boolean} deep (optional) True to collapse all children as well
33287 * @param {Boolean} anim (optional) false to cancel the default animation
33289 collapse : function(deep, anim){
33290 if(this.expanded && !this.isHiddenRoot()){
33291 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33294 this.expanded = false;
33295 if((this.getOwnerTree().animate && anim !== false) || anim){
33296 this.ui.animCollapse(function(){
33297 this.fireEvent("collapse", this);
33299 this.collapseChildNodes(true);
33301 }.createDelegate(this));
33304 this.ui.collapse();
33305 this.fireEvent("collapse", this);
33309 var cs = this.childNodes;
33310 for(var i = 0, len = cs.length; i < len; i++) {
33311 cs[i].collapse(true, false);
33317 delayedExpand : function(delay){
33318 if(!this.expandProcId){
33319 this.expandProcId = this.expand.defer(delay, this);
33324 cancelExpand : function(){
33325 if(this.expandProcId){
33326 clearTimeout(this.expandProcId);
33328 this.expandProcId = false;
33332 * Toggles expanded/collapsed state of the node
33334 toggle : function(){
33343 * Ensures all parent nodes are expanded
33345 ensureVisible : function(callback){
33346 var tree = this.getOwnerTree();
33347 tree.expandPath(this.parentNode.getPath(), false, function(){
33348 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33349 Roo.callback(callback);
33350 }.createDelegate(this));
33354 * Expand all child nodes
33355 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33357 expandChildNodes : function(deep){
33358 var cs = this.childNodes;
33359 for(var i = 0, len = cs.length; i < len; i++) {
33360 cs[i].expand(deep);
33365 * Collapse all child nodes
33366 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33368 collapseChildNodes : function(deep){
33369 var cs = this.childNodes;
33370 for(var i = 0, len = cs.length; i < len; i++) {
33371 cs[i].collapse(deep);
33376 * Disables this node
33378 disable : function(){
33379 this.disabled = true;
33381 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33382 this.ui.onDisableChange(this, true);
33384 this.fireEvent("disabledchange", this, true);
33388 * Enables this node
33390 enable : function(){
33391 this.disabled = false;
33392 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33393 this.ui.onDisableChange(this, false);
33395 this.fireEvent("disabledchange", this, false);
33399 renderChildren : function(suppressEvent){
33400 if(suppressEvent !== false){
33401 this.fireEvent("beforechildrenrendered", this);
33403 var cs = this.childNodes;
33404 for(var i = 0, len = cs.length; i < len; i++){
33405 cs[i].render(true);
33407 this.childrenRendered = true;
33411 sort : function(fn, scope){
33412 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33413 if(this.childrenRendered){
33414 var cs = this.childNodes;
33415 for(var i = 0, len = cs.length; i < len; i++){
33416 cs[i].render(true);
33422 render : function(bulkRender){
33423 this.ui.render(bulkRender);
33424 if(!this.rendered){
33425 this.rendered = true;
33427 this.expanded = false;
33428 this.expand(false, false);
33434 renderIndent : function(deep, refresh){
33436 this.ui.childIndent = null;
33438 this.ui.renderIndent();
33439 if(deep === true && this.childrenRendered){
33440 var cs = this.childNodes;
33441 for(var i = 0, len = cs.length; i < len; i++){
33442 cs[i].renderIndent(true, refresh);
33448 * Ext JS Library 1.1.1
33449 * Copyright(c) 2006-2007, Ext JS, LLC.
33451 * Originally Released Under LGPL - original licence link has changed is not relivant.
33454 * <script type="text/javascript">
33458 * @class Roo.tree.AsyncTreeNode
33459 * @extends Roo.tree.TreeNode
33460 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33462 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33464 Roo.tree.AsyncTreeNode = function(config){
33465 this.loaded = false;
33466 this.loading = false;
33467 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33469 * @event beforeload
33470 * Fires before this node is loaded, return false to cancel
33471 * @param {Node} this This node
33473 this.addEvents({'beforeload':true, 'load': true});
33476 * Fires when this node is loaded
33477 * @param {Node} this This node
33480 * The loader used by this node (defaults to using the tree's defined loader)
33485 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33486 expand : function(deep, anim, callback){
33487 if(this.loading){ // if an async load is already running, waiting til it's done
33489 var f = function(){
33490 if(!this.loading){ // done loading
33491 clearInterval(timer);
33492 this.expand(deep, anim, callback);
33494 }.createDelegate(this);
33495 timer = setInterval(f, 200);
33499 if(this.fireEvent("beforeload", this) === false){
33502 this.loading = true;
33503 this.ui.beforeLoad(this);
33504 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33506 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33510 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33514 * Returns true if this node is currently loading
33515 * @return {Boolean}
33517 isLoading : function(){
33518 return this.loading;
33521 loadComplete : function(deep, anim, callback){
33522 this.loading = false;
33523 this.loaded = true;
33524 this.ui.afterLoad(this);
33525 this.fireEvent("load", this);
33526 this.expand(deep, anim, callback);
33530 * Returns true if this node has been loaded
33531 * @return {Boolean}
33533 isLoaded : function(){
33534 return this.loaded;
33537 hasChildNodes : function(){
33538 if(!this.isLeaf() && !this.loaded){
33541 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33546 * Trigger a reload for this node
33547 * @param {Function} callback
33549 reload : function(callback){
33550 this.collapse(false, false);
33551 while(this.firstChild){
33552 this.removeChild(this.firstChild);
33554 this.childrenRendered = false;
33555 this.loaded = false;
33556 if(this.isHiddenRoot()){
33557 this.expanded = false;
33559 this.expand(false, false, callback);
33563 * Ext JS Library 1.1.1
33564 * Copyright(c) 2006-2007, Ext JS, LLC.
33566 * Originally Released Under LGPL - original licence link has changed is not relivant.
33569 * <script type="text/javascript">
33573 * @class Roo.tree.TreeNodeUI
33575 * @param {Object} node The node to render
33576 * The TreeNode UI implementation is separate from the
33577 * tree implementation. Unless you are customizing the tree UI,
33578 * you should never have to use this directly.
33580 Roo.tree.TreeNodeUI = function(node){
33582 this.rendered = false;
33583 this.animating = false;
33584 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33587 Roo.tree.TreeNodeUI.prototype = {
33588 removeChild : function(node){
33590 this.ctNode.removeChild(node.ui.getEl());
33594 beforeLoad : function(){
33595 this.addClass("x-tree-node-loading");
33598 afterLoad : function(){
33599 this.removeClass("x-tree-node-loading");
33602 onTextChange : function(node, text, oldText){
33604 this.textNode.innerHTML = text;
33608 onDisableChange : function(node, state){
33609 this.disabled = state;
33611 this.addClass("x-tree-node-disabled");
33613 this.removeClass("x-tree-node-disabled");
33617 onSelectedChange : function(state){
33620 this.addClass("x-tree-selected");
33623 this.removeClass("x-tree-selected");
33627 onMove : function(tree, node, oldParent, newParent, index, refNode){
33628 this.childIndent = null;
33630 var targetNode = newParent.ui.getContainer();
33631 if(!targetNode){//target not rendered
33632 this.holder = document.createElement("div");
33633 this.holder.appendChild(this.wrap);
33636 var insertBefore = refNode ? refNode.ui.getEl() : null;
33638 targetNode.insertBefore(this.wrap, insertBefore);
33640 targetNode.appendChild(this.wrap);
33642 this.node.renderIndent(true);
33646 addClass : function(cls){
33648 Roo.fly(this.elNode).addClass(cls);
33652 removeClass : function(cls){
33654 Roo.fly(this.elNode).removeClass(cls);
33658 remove : function(){
33660 this.holder = document.createElement("div");
33661 this.holder.appendChild(this.wrap);
33665 fireEvent : function(){
33666 return this.node.fireEvent.apply(this.node, arguments);
33669 initEvents : function(){
33670 this.node.on("move", this.onMove, this);
33671 var E = Roo.EventManager;
33672 var a = this.anchor;
33674 var el = Roo.fly(a, '_treeui');
33676 if(Roo.isOpera){ // opera render bug ignores the CSS
33677 el.setStyle("text-decoration", "none");
33680 el.on("click", this.onClick, this);
33681 el.on("dblclick", this.onDblClick, this);
33684 Roo.EventManager.on(this.checkbox,
33685 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33688 el.on("contextmenu", this.onContextMenu, this);
33690 var icon = Roo.fly(this.iconNode);
33691 icon.on("click", this.onClick, this);
33692 icon.on("dblclick", this.onDblClick, this);
33693 icon.on("contextmenu", this.onContextMenu, this);
33694 E.on(this.ecNode, "click", this.ecClick, this, true);
33696 if(this.node.disabled){
33697 this.addClass("x-tree-node-disabled");
33699 if(this.node.hidden){
33700 this.addClass("x-tree-node-disabled");
33702 var ot = this.node.getOwnerTree();
33703 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33704 if(dd && (!this.node.isRoot || ot.rootVisible)){
33705 Roo.dd.Registry.register(this.elNode, {
33707 handles: this.getDDHandles(),
33713 getDDHandles : function(){
33714 return [this.iconNode, this.textNode];
33719 this.wrap.style.display = "none";
33725 this.wrap.style.display = "";
33729 onContextMenu : function(e){
33730 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33731 e.preventDefault();
33733 this.fireEvent("contextmenu", this.node, e);
33737 onClick : function(e){
33742 if(this.fireEvent("beforeclick", this.node, e) !== false){
33743 if(!this.disabled && this.node.attributes.href){
33744 this.fireEvent("click", this.node, e);
33747 e.preventDefault();
33752 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33753 this.node.toggle();
33756 this.fireEvent("click", this.node, e);
33762 onDblClick : function(e){
33763 e.preventDefault();
33768 this.toggleCheck();
33770 if(!this.animating && this.node.hasChildNodes()){
33771 this.node.toggle();
33773 this.fireEvent("dblclick", this.node, e);
33776 onCheckChange : function(){
33777 var checked = this.checkbox.checked;
33778 this.node.attributes.checked = checked;
33779 this.fireEvent('checkchange', this.node, checked);
33782 ecClick : function(e){
33783 if(!this.animating && this.node.hasChildNodes()){
33784 this.node.toggle();
33788 startDrop : function(){
33789 this.dropping = true;
33792 // delayed drop so the click event doesn't get fired on a drop
33793 endDrop : function(){
33794 setTimeout(function(){
33795 this.dropping = false;
33796 }.createDelegate(this), 50);
33799 expand : function(){
33800 this.updateExpandIcon();
33801 this.ctNode.style.display = "";
33804 focus : function(){
33805 if(!this.node.preventHScroll){
33806 try{this.anchor.focus();
33808 }else if(!Roo.isIE){
33810 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33811 var l = noscroll.scrollLeft;
33812 this.anchor.focus();
33813 noscroll.scrollLeft = l;
33818 toggleCheck : function(value){
33819 var cb = this.checkbox;
33821 cb.checked = (value === undefined ? !cb.checked : value);
33827 this.anchor.blur();
33831 animExpand : function(callback){
33832 var ct = Roo.get(this.ctNode);
33834 if(!this.node.hasChildNodes()){
33835 this.updateExpandIcon();
33836 this.ctNode.style.display = "";
33837 Roo.callback(callback);
33840 this.animating = true;
33841 this.updateExpandIcon();
33844 callback : function(){
33845 this.animating = false;
33846 Roo.callback(callback);
33849 duration: this.node.ownerTree.duration || .25
33853 highlight : function(){
33854 var tree = this.node.getOwnerTree();
33855 Roo.fly(this.wrap).highlight(
33856 tree.hlColor || "C3DAF9",
33857 {endColor: tree.hlBaseColor}
33861 collapse : function(){
33862 this.updateExpandIcon();
33863 this.ctNode.style.display = "none";
33866 animCollapse : function(callback){
33867 var ct = Roo.get(this.ctNode);
33868 ct.enableDisplayMode('block');
33871 this.animating = true;
33872 this.updateExpandIcon();
33875 callback : function(){
33876 this.animating = false;
33877 Roo.callback(callback);
33880 duration: this.node.ownerTree.duration || .25
33884 getContainer : function(){
33885 return this.ctNode;
33888 getEl : function(){
33892 appendDDGhost : function(ghostNode){
33893 ghostNode.appendChild(this.elNode.cloneNode(true));
33896 getDDRepairXY : function(){
33897 return Roo.lib.Dom.getXY(this.iconNode);
33900 onRender : function(){
33904 render : function(bulkRender){
33905 var n = this.node, a = n.attributes;
33906 var targetNode = n.parentNode ?
33907 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33909 if(!this.rendered){
33910 this.rendered = true;
33912 this.renderElements(n, a, targetNode, bulkRender);
33915 if(this.textNode.setAttributeNS){
33916 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33918 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33921 this.textNode.setAttribute("ext:qtip", a.qtip);
33923 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33926 }else if(a.qtipCfg){
33927 a.qtipCfg.target = Roo.id(this.textNode);
33928 Roo.QuickTips.register(a.qtipCfg);
33931 if(!this.node.expanded){
33932 this.updateExpandIcon();
33935 if(bulkRender === true) {
33936 targetNode.appendChild(this.wrap);
33941 renderElements : function(n, a, targetNode, bulkRender)
33943 // add some indent caching, this helps performance when rendering a large tree
33944 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33945 var t = n.getOwnerTree();
33946 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33947 if (typeof(n.attributes.html) != 'undefined') {
33948 txt = n.attributes.html;
33950 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33951 var cb = typeof a.checked == 'boolean';
33952 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33953 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33954 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33955 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33956 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33957 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33958 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33959 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33960 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33961 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33964 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
33965 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
33966 n.nextSibling.ui.getEl(), buf.join(""));
33968 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
33971 this.elNode = this.wrap.childNodes[0];
33972 this.ctNode = this.wrap.childNodes[1];
33973 var cs = this.elNode.childNodes;
33974 this.indentNode = cs[0];
33975 this.ecNode = cs[1];
33976 this.iconNode = cs[2];
33979 this.checkbox = cs[3];
33982 this.anchor = cs[index];
33983 this.textNode = cs[index].firstChild;
33986 getAnchor : function(){
33987 return this.anchor;
33990 getTextEl : function(){
33991 return this.textNode;
33994 getIconEl : function(){
33995 return this.iconNode;
33998 isChecked : function(){
33999 return this.checkbox ? this.checkbox.checked : false;
34002 updateExpandIcon : function(){
34004 var n = this.node, c1, c2;
34005 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34006 var hasChild = n.hasChildNodes();
34010 c1 = "x-tree-node-collapsed";
34011 c2 = "x-tree-node-expanded";
34014 c1 = "x-tree-node-expanded";
34015 c2 = "x-tree-node-collapsed";
34018 this.removeClass("x-tree-node-leaf");
34019 this.wasLeaf = false;
34021 if(this.c1 != c1 || this.c2 != c2){
34022 Roo.fly(this.elNode).replaceClass(c1, c2);
34023 this.c1 = c1; this.c2 = c2;
34026 // this changes non-leafs into leafs if they have no children.
34027 // it's not very rational behaviour..
34029 if(!this.wasLeaf && this.node.leaf){
34030 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34033 this.wasLeaf = true;
34036 var ecc = "x-tree-ec-icon "+cls;
34037 if(this.ecc != ecc){
34038 this.ecNode.className = ecc;
34044 getChildIndent : function(){
34045 if(!this.childIndent){
34049 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34051 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34053 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34058 this.childIndent = buf.join("");
34060 return this.childIndent;
34063 renderIndent : function(){
34066 var p = this.node.parentNode;
34068 indent = p.ui.getChildIndent();
34070 if(this.indentMarkup != indent){ // don't rerender if not required
34071 this.indentNode.innerHTML = indent;
34072 this.indentMarkup = indent;
34074 this.updateExpandIcon();
34079 Roo.tree.RootTreeNodeUI = function(){
34080 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34082 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34083 render : function(){
34084 if(!this.rendered){
34085 var targetNode = this.node.ownerTree.innerCt.dom;
34086 this.node.expanded = true;
34087 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34088 this.wrap = this.ctNode = targetNode.firstChild;
34091 collapse : function(){
34093 expand : function(){
34097 * Ext JS Library 1.1.1
34098 * Copyright(c) 2006-2007, Ext JS, LLC.
34100 * Originally Released Under LGPL - original licence link has changed is not relivant.
34103 * <script type="text/javascript">
34106 * @class Roo.tree.TreeLoader
34107 * @extends Roo.util.Observable
34108 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34109 * nodes from a specified URL. The response must be a javascript Array definition
34110 * who's elements are node definition objects. eg:
34115 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34116 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34123 * The old style respose with just an array is still supported, but not recommended.
34126 * A server request is sent, and child nodes are loaded only when a node is expanded.
34127 * The loading node's id is passed to the server under the parameter name "node" to
34128 * enable the server to produce the correct child nodes.
34130 * To pass extra parameters, an event handler may be attached to the "beforeload"
34131 * event, and the parameters specified in the TreeLoader's baseParams property:
34133 myTreeLoader.on("beforeload", function(treeLoader, node) {
34134 this.baseParams.category = node.attributes.category;
34137 * This would pass an HTTP parameter called "category" to the server containing
34138 * the value of the Node's "category" attribute.
34140 * Creates a new Treeloader.
34141 * @param {Object} config A config object containing config properties.
34143 Roo.tree.TreeLoader = function(config){
34144 this.baseParams = {};
34145 this.requestMethod = "POST";
34146 Roo.apply(this, config);
34151 * @event beforeload
34152 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34153 * @param {Object} This TreeLoader object.
34154 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34155 * @param {Object} callback The callback function specified in the {@link #load} call.
34160 * Fires when the node has been successfuly loaded.
34161 * @param {Object} This TreeLoader object.
34162 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34163 * @param {Object} response The response object containing the data from the server.
34167 * @event loadexception
34168 * Fires if the network request failed.
34169 * @param {Object} This TreeLoader object.
34170 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34171 * @param {Object} response The response object containing the data from the server.
34173 loadexception : true,
34176 * Fires before a node is created, enabling you to return custom Node types
34177 * @param {Object} This TreeLoader object.
34178 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34183 Roo.tree.TreeLoader.superclass.constructor.call(this);
34186 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34188 * @cfg {String} dataUrl The URL from which to request a Json string which
34189 * specifies an array of node definition object representing the child nodes
34193 * @cfg {String} requestMethod either GET or POST
34194 * defaults to POST (due to BC)
34198 * @cfg {Object} baseParams (optional) An object containing properties which
34199 * specify HTTP parameters to be passed to each request for child nodes.
34202 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34203 * created by this loader. If the attributes sent by the server have an attribute in this object,
34204 * they take priority.
34207 * @cfg {Object} uiProviders (optional) An object containing properties which
34209 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34210 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34211 * <i>uiProvider</i> attribute of a returned child node is a string rather
34212 * than a reference to a TreeNodeUI implementation, this that string value
34213 * is used as a property name in the uiProviders object. You can define the provider named
34214 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34219 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34220 * child nodes before loading.
34222 clearOnLoad : true,
34225 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34226 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34227 * Grid query { data : [ .....] }
34232 * @cfg {String} queryParam (optional)
34233 * Name of the query as it will be passed on the querystring (defaults to 'node')
34234 * eg. the request will be ?node=[id]
34241 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34242 * This is called automatically when a node is expanded, but may be used to reload
34243 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34244 * @param {Roo.tree.TreeNode} node
34245 * @param {Function} callback
34247 load : function(node, callback){
34248 if(this.clearOnLoad){
34249 while(node.firstChild){
34250 node.removeChild(node.firstChild);
34253 if(node.attributes.children){ // preloaded json children
34254 var cs = node.attributes.children;
34255 for(var i = 0, len = cs.length; i < len; i++){
34256 node.appendChild(this.createNode(cs[i]));
34258 if(typeof callback == "function"){
34261 }else if(this.dataUrl){
34262 this.requestData(node, callback);
34266 getParams: function(node){
34267 var buf = [], bp = this.baseParams;
34268 for(var key in bp){
34269 if(typeof bp[key] != "function"){
34270 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34273 var n = this.queryParam === false ? 'node' : this.queryParam;
34274 buf.push(n + "=", encodeURIComponent(node.id));
34275 return buf.join("");
34278 requestData : function(node, callback){
34279 if(this.fireEvent("beforeload", this, node, callback) !== false){
34280 this.transId = Roo.Ajax.request({
34281 method:this.requestMethod,
34282 url: this.dataUrl||this.url,
34283 success: this.handleResponse,
34284 failure: this.handleFailure,
34286 argument: {callback: callback, node: node},
34287 params: this.getParams(node)
34290 // if the load is cancelled, make sure we notify
34291 // the node that we are done
34292 if(typeof callback == "function"){
34298 isLoading : function(){
34299 return this.transId ? true : false;
34302 abort : function(){
34303 if(this.isLoading()){
34304 Roo.Ajax.abort(this.transId);
34309 createNode : function(attr)
34311 // apply baseAttrs, nice idea Corey!
34312 if(this.baseAttrs){
34313 Roo.applyIf(attr, this.baseAttrs);
34315 if(this.applyLoader !== false){
34316 attr.loader = this;
34318 // uiProvider = depreciated..
34320 if(typeof(attr.uiProvider) == 'string'){
34321 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34322 /** eval:var:attr */ eval(attr.uiProvider);
34324 if(typeof(this.uiProviders['default']) != 'undefined') {
34325 attr.uiProvider = this.uiProviders['default'];
34328 this.fireEvent('create', this, attr);
34330 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34332 new Roo.tree.TreeNode(attr) :
34333 new Roo.tree.AsyncTreeNode(attr));
34336 processResponse : function(response, node, callback)
34338 var json = response.responseText;
34341 var o = Roo.decode(json);
34343 if (this.root === false && typeof(o.success) != undefined) {
34344 this.root = 'data'; // the default behaviour for list like data..
34347 if (this.root !== false && !o.success) {
34348 // it's a failure condition.
34349 var a = response.argument;
34350 this.fireEvent("loadexception", this, a.node, response);
34351 Roo.log("Load failed - should have a handler really");
34357 if (this.root !== false) {
34361 for(var i = 0, len = o.length; i < len; i++){
34362 var n = this.createNode(o[i]);
34364 node.appendChild(n);
34367 if(typeof callback == "function"){
34368 callback(this, node);
34371 this.handleFailure(response);
34375 handleResponse : function(response){
34376 this.transId = false;
34377 var a = response.argument;
34378 this.processResponse(response, a.node, a.callback);
34379 this.fireEvent("load", this, a.node, response);
34382 handleFailure : function(response)
34384 // should handle failure better..
34385 this.transId = false;
34386 var a = response.argument;
34387 this.fireEvent("loadexception", this, a.node, response);
34388 if(typeof a.callback == "function"){
34389 a.callback(this, a.node);
34394 * Ext JS Library 1.1.1
34395 * Copyright(c) 2006-2007, Ext JS, LLC.
34397 * Originally Released Under LGPL - original licence link has changed is not relivant.
34400 * <script type="text/javascript">
34404 * @class Roo.tree.TreeFilter
34405 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34406 * @param {TreePanel} tree
34407 * @param {Object} config (optional)
34409 Roo.tree.TreeFilter = function(tree, config){
34411 this.filtered = {};
34412 Roo.apply(this, config);
34415 Roo.tree.TreeFilter.prototype = {
34422 * Filter the data by a specific attribute.
34423 * @param {String/RegExp} value Either string that the attribute value
34424 * should start with or a RegExp to test against the attribute
34425 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34426 * @param {TreeNode} startNode (optional) The node to start the filter at.
34428 filter : function(value, attr, startNode){
34429 attr = attr || "text";
34431 if(typeof value == "string"){
34432 var vlen = value.length;
34433 // auto clear empty filter
34434 if(vlen == 0 && this.clearBlank){
34438 value = value.toLowerCase();
34440 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34442 }else if(value.exec){ // regex?
34444 return value.test(n.attributes[attr]);
34447 throw 'Illegal filter type, must be string or regex';
34449 this.filterBy(f, null, startNode);
34453 * Filter by a function. The passed function will be called with each
34454 * node in the tree (or from the startNode). If the function returns true, the node is kept
34455 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34456 * @param {Function} fn The filter function
34457 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34459 filterBy : function(fn, scope, startNode){
34460 startNode = startNode || this.tree.root;
34461 if(this.autoClear){
34464 var af = this.filtered, rv = this.reverse;
34465 var f = function(n){
34466 if(n == startNode){
34472 var m = fn.call(scope || n, n);
34480 startNode.cascade(f);
34483 if(typeof id != "function"){
34485 if(n && n.parentNode){
34486 n.parentNode.removeChild(n);
34494 * Clears the current filter. Note: with the "remove" option
34495 * set a filter cannot be cleared.
34497 clear : function(){
34499 var af = this.filtered;
34501 if(typeof id != "function"){
34508 this.filtered = {};
34513 * Ext JS Library 1.1.1
34514 * Copyright(c) 2006-2007, Ext JS, LLC.
34516 * Originally Released Under LGPL - original licence link has changed is not relivant.
34519 * <script type="text/javascript">
34524 * @class Roo.tree.TreeSorter
34525 * Provides sorting of nodes in a TreePanel
34527 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34528 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34529 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34530 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34531 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34532 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34534 * @param {TreePanel} tree
34535 * @param {Object} config
34537 Roo.tree.TreeSorter = function(tree, config){
34538 Roo.apply(this, config);
34539 tree.on("beforechildrenrendered", this.doSort, this);
34540 tree.on("append", this.updateSort, this);
34541 tree.on("insert", this.updateSort, this);
34543 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34544 var p = this.property || "text";
34545 var sortType = this.sortType;
34546 var fs = this.folderSort;
34547 var cs = this.caseSensitive === true;
34548 var leafAttr = this.leafAttr || 'leaf';
34550 this.sortFn = function(n1, n2){
34552 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34555 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34559 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34560 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34562 return dsc ? +1 : -1;
34564 return dsc ? -1 : +1;
34571 Roo.tree.TreeSorter.prototype = {
34572 doSort : function(node){
34573 node.sort(this.sortFn);
34576 compareNodes : function(n1, n2){
34577 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34580 updateSort : function(tree, node){
34581 if(node.childrenRendered){
34582 this.doSort.defer(1, this, [node]);
34587 * Ext JS Library 1.1.1
34588 * Copyright(c) 2006-2007, Ext JS, LLC.
34590 * Originally Released Under LGPL - original licence link has changed is not relivant.
34593 * <script type="text/javascript">
34596 if(Roo.dd.DropZone){
34598 Roo.tree.TreeDropZone = function(tree, config){
34599 this.allowParentInsert = false;
34600 this.allowContainerDrop = false;
34601 this.appendOnly = false;
34602 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34604 this.lastInsertClass = "x-tree-no-status";
34605 this.dragOverData = {};
34608 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34609 ddGroup : "TreeDD",
34612 expandDelay : 1000,
34614 expandNode : function(node){
34615 if(node.hasChildNodes() && !node.isExpanded()){
34616 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34620 queueExpand : function(node){
34621 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34624 cancelExpand : function(){
34625 if(this.expandProcId){
34626 clearTimeout(this.expandProcId);
34627 this.expandProcId = false;
34631 isValidDropPoint : function(n, pt, dd, e, data){
34632 if(!n || !data){ return false; }
34633 var targetNode = n.node;
34634 var dropNode = data.node;
34635 // default drop rules
34636 if(!(targetNode && targetNode.isTarget && pt)){
34639 if(pt == "append" && targetNode.allowChildren === false){
34642 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34645 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34648 // reuse the object
34649 var overEvent = this.dragOverData;
34650 overEvent.tree = this.tree;
34651 overEvent.target = targetNode;
34652 overEvent.data = data;
34653 overEvent.point = pt;
34654 overEvent.source = dd;
34655 overEvent.rawEvent = e;
34656 overEvent.dropNode = dropNode;
34657 overEvent.cancel = false;
34658 var result = this.tree.fireEvent("nodedragover", overEvent);
34659 return overEvent.cancel === false && result !== false;
34662 getDropPoint : function(e, n, dd)
34666 return tn.allowChildren !== false ? "append" : false; // always append for root
34668 var dragEl = n.ddel;
34669 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34670 var y = Roo.lib.Event.getPageY(e);
34671 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34673 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34674 var noAppend = tn.allowChildren === false;
34675 if(this.appendOnly || tn.parentNode.allowChildren === false){
34676 return noAppend ? false : "append";
34678 var noBelow = false;
34679 if(!this.allowParentInsert){
34680 noBelow = tn.hasChildNodes() && tn.isExpanded();
34682 var q = (b - t) / (noAppend ? 2 : 3);
34683 if(y >= t && y < (t + q)){
34685 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34692 onNodeEnter : function(n, dd, e, data)
34694 this.cancelExpand();
34697 onNodeOver : function(n, dd, e, data)
34700 var pt = this.getDropPoint(e, n, dd);
34703 // auto node expand check
34704 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34705 this.queueExpand(node);
34706 }else if(pt != "append"){
34707 this.cancelExpand();
34710 // set the insert point style on the target node
34711 var returnCls = this.dropNotAllowed;
34712 if(this.isValidDropPoint(n, pt, dd, e, data)){
34717 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34718 cls = "x-tree-drag-insert-above";
34719 }else if(pt == "below"){
34720 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34721 cls = "x-tree-drag-insert-below";
34723 returnCls = "x-tree-drop-ok-append";
34724 cls = "x-tree-drag-append";
34726 if(this.lastInsertClass != cls){
34727 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34728 this.lastInsertClass = cls;
34735 onNodeOut : function(n, dd, e, data){
34737 this.cancelExpand();
34738 this.removeDropIndicators(n);
34741 onNodeDrop : function(n, dd, e, data){
34742 var point = this.getDropPoint(e, n, dd);
34743 var targetNode = n.node;
34744 targetNode.ui.startDrop();
34745 if(!this.isValidDropPoint(n, point, dd, e, data)){
34746 targetNode.ui.endDrop();
34749 // first try to find the drop node
34750 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34753 target: targetNode,
34758 dropNode: dropNode,
34761 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34762 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34763 targetNode.ui.endDrop();
34766 // allow target changing
34767 targetNode = dropEvent.target;
34768 if(point == "append" && !targetNode.isExpanded()){
34769 targetNode.expand(false, null, function(){
34770 this.completeDrop(dropEvent);
34771 }.createDelegate(this));
34773 this.completeDrop(dropEvent);
34778 completeDrop : function(de){
34779 var ns = de.dropNode, p = de.point, t = de.target;
34780 if(!(ns instanceof Array)){
34784 for(var i = 0, len = ns.length; i < len; i++){
34787 t.parentNode.insertBefore(n, t);
34788 }else if(p == "below"){
34789 t.parentNode.insertBefore(n, t.nextSibling);
34795 if(this.tree.hlDrop){
34799 this.tree.fireEvent("nodedrop", de);
34802 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34803 if(this.tree.hlDrop){
34804 dropNode.ui.focus();
34805 dropNode.ui.highlight();
34807 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34810 getTree : function(){
34814 removeDropIndicators : function(n){
34817 Roo.fly(el).removeClass([
34818 "x-tree-drag-insert-above",
34819 "x-tree-drag-insert-below",
34820 "x-tree-drag-append"]);
34821 this.lastInsertClass = "_noclass";
34825 beforeDragDrop : function(target, e, id){
34826 this.cancelExpand();
34830 afterRepair : function(data){
34831 if(data && Roo.enableFx){
34832 data.node.ui.highlight();
34842 * Ext JS Library 1.1.1
34843 * Copyright(c) 2006-2007, Ext JS, LLC.
34845 * Originally Released Under LGPL - original licence link has changed is not relivant.
34848 * <script type="text/javascript">
34852 if(Roo.dd.DragZone){
34853 Roo.tree.TreeDragZone = function(tree, config){
34854 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34858 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34859 ddGroup : "TreeDD",
34861 onBeforeDrag : function(data, e){
34863 return n && n.draggable && !n.disabled;
34867 onInitDrag : function(e){
34868 var data = this.dragData;
34869 this.tree.getSelectionModel().select(data.node);
34870 this.proxy.update("");
34871 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34872 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34875 getRepairXY : function(e, data){
34876 return data.node.ui.getDDRepairXY();
34879 onEndDrag : function(data, e){
34880 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34885 onValidDrop : function(dd, e, id){
34886 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34890 beforeInvalidDrop : function(e, id){
34891 // this scrolls the original position back into view
34892 var sm = this.tree.getSelectionModel();
34893 sm.clearSelections();
34894 sm.select(this.dragData.node);
34899 * Ext JS Library 1.1.1
34900 * Copyright(c) 2006-2007, Ext JS, LLC.
34902 * Originally Released Under LGPL - original licence link has changed is not relivant.
34905 * <script type="text/javascript">
34908 * @class Roo.tree.TreeEditor
34909 * @extends Roo.Editor
34910 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34911 * as the editor field.
34913 * @param {Object} config (used to be the tree panel.)
34914 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34916 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34917 * @cfg {Roo.form.TextField|Object} field The field configuration
34921 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34924 if (oldconfig) { // old style..
34925 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34928 tree = config.tree;
34929 config.field = config.field || {};
34930 config.field.xtype = 'TextField';
34931 field = Roo.factory(config.field, Roo.form);
34933 config = config || {};
34938 * @event beforenodeedit
34939 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34940 * false from the handler of this event.
34941 * @param {Editor} this
34942 * @param {Roo.tree.Node} node
34944 "beforenodeedit" : true
34948 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34952 tree.on('beforeclick', this.beforeNodeClick, this);
34953 tree.getTreeEl().on('mousedown', this.hide, this);
34954 this.on('complete', this.updateNode, this);
34955 this.on('beforestartedit', this.fitToTree, this);
34956 this.on('startedit', this.bindScroll, this, {delay:10});
34957 this.on('specialkey', this.onSpecialKey, this);
34960 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34962 * @cfg {String} alignment
34963 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
34969 * @cfg {Boolean} hideEl
34970 * True to hide the bound element while the editor is displayed (defaults to false)
34974 * @cfg {String} cls
34975 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
34977 cls: "x-small-editor x-tree-editor",
34979 * @cfg {Boolean} shim
34980 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
34986 * @cfg {Number} maxWidth
34987 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
34988 * the containing tree element's size, it will be automatically limited for you to the container width, taking
34989 * scroll and client offsets into account prior to each edit.
34996 fitToTree : function(ed, el){
34997 var td = this.tree.getTreeEl().dom, nd = el.dom;
34998 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
34999 td.scrollLeft = nd.offsetLeft;
35003 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35004 this.setSize(w, '');
35006 return this.fireEvent('beforenodeedit', this, this.editNode);
35011 triggerEdit : function(node){
35012 this.completeEdit();
35013 this.editNode = node;
35014 this.startEdit(node.ui.textNode, node.text);
35018 bindScroll : function(){
35019 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35023 beforeNodeClick : function(node, e){
35024 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35025 this.lastClick = new Date();
35026 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35028 this.triggerEdit(node);
35035 updateNode : function(ed, value){
35036 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35037 this.editNode.setText(value);
35041 onHide : function(){
35042 Roo.tree.TreeEditor.superclass.onHide.call(this);
35044 this.editNode.ui.focus();
35049 onSpecialKey : function(field, e){
35050 var k = e.getKey();
35054 }else if(k == e.ENTER && !e.hasModifier()){
35056 this.completeEdit();
35059 });//<Script type="text/javascript">
35062 * Ext JS Library 1.1.1
35063 * Copyright(c) 2006-2007, Ext JS, LLC.
35065 * Originally Released Under LGPL - original licence link has changed is not relivant.
35068 * <script type="text/javascript">
35072 * Not documented??? - probably should be...
35075 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35076 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35078 renderElements : function(n, a, targetNode, bulkRender){
35079 //consel.log("renderElements?");
35080 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35082 var t = n.getOwnerTree();
35083 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35085 var cols = t.columns;
35086 var bw = t.borderWidth;
35088 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35089 var cb = typeof a.checked == "boolean";
35090 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35091 var colcls = 'x-t-' + tid + '-c0';
35093 '<li class="x-tree-node">',
35096 '<div class="x-tree-node-el ', a.cls,'">',
35098 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35101 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35102 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35103 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35104 (a.icon ? ' x-tree-node-inline-icon' : ''),
35105 (a.iconCls ? ' '+a.iconCls : ''),
35106 '" unselectable="on" />',
35107 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35108 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35110 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35111 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35112 '<span unselectable="on" qtip="' + tx + '">',
35116 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35117 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35119 for(var i = 1, len = cols.length; i < len; i++){
35121 colcls = 'x-t-' + tid + '-c' +i;
35122 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35123 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35124 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35130 '<div class="x-clear"></div></div>',
35131 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35134 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35135 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35136 n.nextSibling.ui.getEl(), buf.join(""));
35138 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35140 var el = this.wrap.firstChild;
35142 this.elNode = el.firstChild;
35143 this.ranchor = el.childNodes[1];
35144 this.ctNode = this.wrap.childNodes[1];
35145 var cs = el.firstChild.childNodes;
35146 this.indentNode = cs[0];
35147 this.ecNode = cs[1];
35148 this.iconNode = cs[2];
35151 this.checkbox = cs[3];
35154 this.anchor = cs[index];
35156 this.textNode = cs[index].firstChild;
35158 //el.on("click", this.onClick, this);
35159 //el.on("dblclick", this.onDblClick, this);
35162 // console.log(this);
35164 initEvents : function(){
35165 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35168 var a = this.ranchor;
35170 var el = Roo.get(a);
35172 if(Roo.isOpera){ // opera render bug ignores the CSS
35173 el.setStyle("text-decoration", "none");
35176 el.on("click", this.onClick, this);
35177 el.on("dblclick", this.onDblClick, this);
35178 el.on("contextmenu", this.onContextMenu, this);
35182 /*onSelectedChange : function(state){
35185 this.addClass("x-tree-selected");
35188 this.removeClass("x-tree-selected");
35191 addClass : function(cls){
35193 Roo.fly(this.elRow).addClass(cls);
35199 removeClass : function(cls){
35201 Roo.fly(this.elRow).removeClass(cls);
35207 });//<Script type="text/javascript">
35211 * Ext JS Library 1.1.1
35212 * Copyright(c) 2006-2007, Ext JS, LLC.
35214 * Originally Released Under LGPL - original licence link has changed is not relivant.
35217 * <script type="text/javascript">
35222 * @class Roo.tree.ColumnTree
35223 * @extends Roo.data.TreePanel
35224 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35225 * @cfg {int} borderWidth compined right/left border allowance
35227 * @param {String/HTMLElement/Element} el The container element
35228 * @param {Object} config
35230 Roo.tree.ColumnTree = function(el, config)
35232 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35236 * Fire this event on a container when it resizes
35237 * @param {int} w Width
35238 * @param {int} h Height
35242 this.on('resize', this.onResize, this);
35245 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35249 borderWidth: Roo.isBorderBox ? 0 : 2,
35252 render : function(){
35253 // add the header.....
35255 Roo.tree.ColumnTree.superclass.render.apply(this);
35257 this.el.addClass('x-column-tree');
35259 this.headers = this.el.createChild(
35260 {cls:'x-tree-headers'},this.innerCt.dom);
35262 var cols = this.columns, c;
35263 var totalWidth = 0;
35265 var len = cols.length;
35266 for(var i = 0; i < len; i++){
35268 totalWidth += c.width;
35269 this.headEls.push(this.headers.createChild({
35270 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35272 cls:'x-tree-hd-text',
35275 style:'width:'+(c.width-this.borderWidth)+'px;'
35278 this.headers.createChild({cls:'x-clear'});
35279 // prevent floats from wrapping when clipped
35280 this.headers.setWidth(totalWidth);
35281 //this.innerCt.setWidth(totalWidth);
35282 this.innerCt.setStyle({ overflow: 'auto' });
35283 this.onResize(this.width, this.height);
35287 onResize : function(w,h)
35292 this.innerCt.setWidth(this.width);
35293 this.innerCt.setHeight(this.height-20);
35296 var cols = this.columns, c;
35297 var totalWidth = 0;
35299 var len = cols.length;
35300 for(var i = 0; i < len; i++){
35302 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35303 // it's the expander..
35304 expEl = this.headEls[i];
35307 totalWidth += c.width;
35311 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35313 this.headers.setWidth(w-20);
35322 * Ext JS Library 1.1.1
35323 * Copyright(c) 2006-2007, Ext JS, LLC.
35325 * Originally Released Under LGPL - original licence link has changed is not relivant.
35328 * <script type="text/javascript">
35332 * @class Roo.menu.Menu
35333 * @extends Roo.util.Observable
35334 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35335 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35337 * Creates a new Menu
35338 * @param {Object} config Configuration options
35340 Roo.menu.Menu = function(config){
35341 Roo.apply(this, config);
35342 this.id = this.id || Roo.id();
35345 * @event beforeshow
35346 * Fires before this menu is displayed
35347 * @param {Roo.menu.Menu} this
35351 * @event beforehide
35352 * Fires before this menu is hidden
35353 * @param {Roo.menu.Menu} this
35358 * Fires after this menu is displayed
35359 * @param {Roo.menu.Menu} this
35364 * Fires after this menu is hidden
35365 * @param {Roo.menu.Menu} this
35370 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35371 * @param {Roo.menu.Menu} this
35372 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35373 * @param {Roo.EventObject} e
35378 * Fires when the mouse is hovering over this menu
35379 * @param {Roo.menu.Menu} this
35380 * @param {Roo.EventObject} e
35381 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35386 * Fires when the mouse exits this menu
35387 * @param {Roo.menu.Menu} this
35388 * @param {Roo.EventObject} e
35389 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35394 * Fires when a menu item contained in this menu is clicked
35395 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35396 * @param {Roo.EventObject} e
35400 if (this.registerMenu) {
35401 Roo.menu.MenuMgr.register(this);
35404 var mis = this.items;
35405 this.items = new Roo.util.MixedCollection();
35407 this.add.apply(this, mis);
35411 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35413 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35417 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35418 * for bottom-right shadow (defaults to "sides")
35422 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35423 * this menu (defaults to "tl-tr?")
35425 subMenuAlign : "tl-tr?",
35427 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35428 * relative to its element of origin (defaults to "tl-bl?")
35430 defaultAlign : "tl-bl?",
35432 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35434 allowOtherMenus : false,
35436 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35438 registerMenu : true,
35443 render : function(){
35447 var el = this.el = new Roo.Layer({
35449 shadow:this.shadow,
35451 parentEl: this.parentEl || document.body,
35455 this.keyNav = new Roo.menu.MenuNav(this);
35458 el.addClass("x-menu-plain");
35461 el.addClass(this.cls);
35463 // generic focus element
35464 this.focusEl = el.createChild({
35465 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35467 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35468 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35470 ul.on("mouseover", this.onMouseOver, this);
35471 ul.on("mouseout", this.onMouseOut, this);
35472 this.items.each(function(item){
35477 var li = document.createElement("li");
35478 li.className = "x-menu-list-item";
35479 ul.dom.appendChild(li);
35480 item.render(li, this);
35487 autoWidth : function(){
35488 var el = this.el, ul = this.ul;
35492 var w = this.width;
35495 }else if(Roo.isIE){
35496 el.setWidth(this.minWidth);
35497 var t = el.dom.offsetWidth; // force recalc
35498 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35503 delayAutoWidth : function(){
35506 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35508 this.awTask.delay(20);
35513 findTargetItem : function(e){
35514 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35515 if(t && t.menuItemId){
35516 return this.items.get(t.menuItemId);
35521 onClick : function(e){
35522 Roo.log("menu.onClick");
35523 var t = this.findTargetItem(e);
35528 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35529 if(t == this.activeItem && t.shouldDeactivate(e)){
35530 this.activeItem.deactivate();
35531 delete this.activeItem;
35535 this.setActiveItem(t, true);
35543 this.fireEvent("click", this, t, e);
35547 setActiveItem : function(item, autoExpand){
35548 if(item != this.activeItem){
35549 if(this.activeItem){
35550 this.activeItem.deactivate();
35552 this.activeItem = item;
35553 item.activate(autoExpand);
35554 }else if(autoExpand){
35560 tryActivate : function(start, step){
35561 var items = this.items;
35562 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35563 var item = items.get(i);
35564 if(!item.disabled && item.canActivate){
35565 this.setActiveItem(item, false);
35573 onMouseOver : function(e){
35575 if(t = this.findTargetItem(e)){
35576 if(t.canActivate && !t.disabled){
35577 this.setActiveItem(t, true);
35580 this.fireEvent("mouseover", this, e, t);
35584 onMouseOut : function(e){
35586 if(t = this.findTargetItem(e)){
35587 if(t == this.activeItem && t.shouldDeactivate(e)){
35588 this.activeItem.deactivate();
35589 delete this.activeItem;
35592 this.fireEvent("mouseout", this, e, t);
35596 * Read-only. Returns true if the menu is currently displayed, else false.
35599 isVisible : function(){
35600 return this.el && !this.hidden;
35604 * Displays this menu relative to another element
35605 * @param {String/HTMLElement/Roo.Element} element The element to align to
35606 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35607 * the element (defaults to this.defaultAlign)
35608 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35610 show : function(el, pos, parentMenu){
35611 this.parentMenu = parentMenu;
35615 this.fireEvent("beforeshow", this);
35616 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35620 * Displays this menu at a specific xy position
35621 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35622 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35624 showAt : function(xy, parentMenu, /* private: */_e){
35625 this.parentMenu = parentMenu;
35630 this.fireEvent("beforeshow", this);
35631 xy = this.el.adjustForConstraints(xy);
35635 this.hidden = false;
35637 this.fireEvent("show", this);
35640 focus : function(){
35642 this.doFocus.defer(50, this);
35646 doFocus : function(){
35648 this.focusEl.focus();
35653 * Hides this menu and optionally all parent menus
35654 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35656 hide : function(deep){
35657 if(this.el && this.isVisible()){
35658 this.fireEvent("beforehide", this);
35659 if(this.activeItem){
35660 this.activeItem.deactivate();
35661 this.activeItem = null;
35664 this.hidden = true;
35665 this.fireEvent("hide", this);
35667 if(deep === true && this.parentMenu){
35668 this.parentMenu.hide(true);
35673 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35674 * Any of the following are valid:
35676 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35677 * <li>An HTMLElement object which will be converted to a menu item</li>
35678 * <li>A menu item config object that will be created as a new menu item</li>
35679 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35680 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35685 var menu = new Roo.menu.Menu();
35687 // Create a menu item to add by reference
35688 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35690 // Add a bunch of items at once using different methods.
35691 // Only the last item added will be returned.
35692 var item = menu.add(
35693 menuItem, // add existing item by ref
35694 'Dynamic Item', // new TextItem
35695 '-', // new separator
35696 { text: 'Config Item' } // new item by config
35699 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35700 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35703 var a = arguments, l = a.length, item;
35704 for(var i = 0; i < l; i++){
35706 if ((typeof(el) == "object") && el.xtype && el.xns) {
35707 el = Roo.factory(el, Roo.menu);
35710 if(el.render){ // some kind of Item
35711 item = this.addItem(el);
35712 }else if(typeof el == "string"){ // string
35713 if(el == "separator" || el == "-"){
35714 item = this.addSeparator();
35716 item = this.addText(el);
35718 }else if(el.tagName || el.el){ // element
35719 item = this.addElement(el);
35720 }else if(typeof el == "object"){ // must be menu item config?
35721 item = this.addMenuItem(el);
35728 * Returns this menu's underlying {@link Roo.Element} object
35729 * @return {Roo.Element} The element
35731 getEl : function(){
35739 * Adds a separator bar to the menu
35740 * @return {Roo.menu.Item} The menu item that was added
35742 addSeparator : function(){
35743 return this.addItem(new Roo.menu.Separator());
35747 * Adds an {@link Roo.Element} object to the menu
35748 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35749 * @return {Roo.menu.Item} The menu item that was added
35751 addElement : function(el){
35752 return this.addItem(new Roo.menu.BaseItem(el));
35756 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35757 * @param {Roo.menu.Item} item The menu item to add
35758 * @return {Roo.menu.Item} The menu item that was added
35760 addItem : function(item){
35761 this.items.add(item);
35763 var li = document.createElement("li");
35764 li.className = "x-menu-list-item";
35765 this.ul.dom.appendChild(li);
35766 item.render(li, this);
35767 this.delayAutoWidth();
35773 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35774 * @param {Object} config A MenuItem config object
35775 * @return {Roo.menu.Item} The menu item that was added
35777 addMenuItem : function(config){
35778 if(!(config instanceof Roo.menu.Item)){
35779 if(typeof config.checked == "boolean"){ // must be check menu item config?
35780 config = new Roo.menu.CheckItem(config);
35782 config = new Roo.menu.Item(config);
35785 return this.addItem(config);
35789 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35790 * @param {String} text The text to display in the menu item
35791 * @return {Roo.menu.Item} The menu item that was added
35793 addText : function(text){
35794 return this.addItem(new Roo.menu.TextItem({ text : text }));
35798 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35799 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35800 * @param {Roo.menu.Item} item The menu item to add
35801 * @return {Roo.menu.Item} The menu item that was added
35803 insert : function(index, item){
35804 this.items.insert(index, item);
35806 var li = document.createElement("li");
35807 li.className = "x-menu-list-item";
35808 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35809 item.render(li, this);
35810 this.delayAutoWidth();
35816 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35817 * @param {Roo.menu.Item} item The menu item to remove
35819 remove : function(item){
35820 this.items.removeKey(item.id);
35825 * Removes and destroys all items in the menu
35827 removeAll : function(){
35829 while(f = this.items.first()){
35835 // MenuNav is a private utility class used internally by the Menu
35836 Roo.menu.MenuNav = function(menu){
35837 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35838 this.scope = this.menu = menu;
35841 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35842 doRelay : function(e, h){
35843 var k = e.getKey();
35844 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35845 this.menu.tryActivate(0, 1);
35848 return h.call(this.scope || this, e, this.menu);
35851 up : function(e, m){
35852 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35853 m.tryActivate(m.items.length-1, -1);
35857 down : function(e, m){
35858 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35859 m.tryActivate(0, 1);
35863 right : function(e, m){
35865 m.activeItem.expandMenu(true);
35869 left : function(e, m){
35871 if(m.parentMenu && m.parentMenu.activeItem){
35872 m.parentMenu.activeItem.activate();
35876 enter : function(e, m){
35878 e.stopPropagation();
35879 m.activeItem.onClick(e);
35880 m.fireEvent("click", this, m.activeItem);
35886 * Ext JS Library 1.1.1
35887 * Copyright(c) 2006-2007, Ext JS, LLC.
35889 * Originally Released Under LGPL - original licence link has changed is not relivant.
35892 * <script type="text/javascript">
35896 * @class Roo.menu.MenuMgr
35897 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35900 Roo.menu.MenuMgr = function(){
35901 var menus, active, groups = {}, attached = false, lastShow = new Date();
35903 // private - called when first menu is created
35906 active = new Roo.util.MixedCollection();
35907 Roo.get(document).addKeyListener(27, function(){
35908 if(active.length > 0){
35915 function hideAll(){
35916 if(active && active.length > 0){
35917 var c = active.clone();
35918 c.each(function(m){
35925 function onHide(m){
35927 if(active.length < 1){
35928 Roo.get(document).un("mousedown", onMouseDown);
35934 function onShow(m){
35935 var last = active.last();
35936 lastShow = new Date();
35939 Roo.get(document).on("mousedown", onMouseDown);
35943 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35944 m.parentMenu.activeChild = m;
35945 }else if(last && last.isVisible()){
35946 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35951 function onBeforeHide(m){
35953 m.activeChild.hide();
35955 if(m.autoHideTimer){
35956 clearTimeout(m.autoHideTimer);
35957 delete m.autoHideTimer;
35962 function onBeforeShow(m){
35963 var pm = m.parentMenu;
35964 if(!pm && !m.allowOtherMenus){
35966 }else if(pm && pm.activeChild && active != m){
35967 pm.activeChild.hide();
35972 function onMouseDown(e){
35973 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
35979 function onBeforeCheck(mi, state){
35981 var g = groups[mi.group];
35982 for(var i = 0, l = g.length; i < l; i++){
35984 g[i].setChecked(false);
35993 * Hides all menus that are currently visible
35995 hideAll : function(){
36000 register : function(menu){
36004 menus[menu.id] = menu;
36005 menu.on("beforehide", onBeforeHide);
36006 menu.on("hide", onHide);
36007 menu.on("beforeshow", onBeforeShow);
36008 menu.on("show", onShow);
36009 var g = menu.group;
36010 if(g && menu.events["checkchange"]){
36014 groups[g].push(menu);
36015 menu.on("checkchange", onCheck);
36020 * Returns a {@link Roo.menu.Menu} object
36021 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36022 * be used to generate and return a new Menu instance.
36024 get : function(menu){
36025 if(typeof menu == "string"){ // menu id
36026 return menus[menu];
36027 }else if(menu.events){ // menu instance
36029 }else if(typeof menu.length == 'number'){ // array of menu items?
36030 return new Roo.menu.Menu({items:menu});
36031 }else{ // otherwise, must be a config
36032 return new Roo.menu.Menu(menu);
36037 unregister : function(menu){
36038 delete menus[menu.id];
36039 menu.un("beforehide", onBeforeHide);
36040 menu.un("hide", onHide);
36041 menu.un("beforeshow", onBeforeShow);
36042 menu.un("show", onShow);
36043 var g = menu.group;
36044 if(g && menu.events["checkchange"]){
36045 groups[g].remove(menu);
36046 menu.un("checkchange", onCheck);
36051 registerCheckable : function(menuItem){
36052 var g = menuItem.group;
36057 groups[g].push(menuItem);
36058 menuItem.on("beforecheckchange", onBeforeCheck);
36063 unregisterCheckable : function(menuItem){
36064 var g = menuItem.group;
36066 groups[g].remove(menuItem);
36067 menuItem.un("beforecheckchange", onBeforeCheck);
36073 * Ext JS Library 1.1.1
36074 * Copyright(c) 2006-2007, Ext JS, LLC.
36076 * Originally Released Under LGPL - original licence link has changed is not relivant.
36079 * <script type="text/javascript">
36084 * @class Roo.menu.BaseItem
36085 * @extends Roo.Component
36086 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36087 * management and base configuration options shared by all menu components.
36089 * Creates a new BaseItem
36090 * @param {Object} config Configuration options
36092 Roo.menu.BaseItem = function(config){
36093 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36098 * Fires when this item is clicked
36099 * @param {Roo.menu.BaseItem} this
36100 * @param {Roo.EventObject} e
36105 * Fires when this item is activated
36106 * @param {Roo.menu.BaseItem} this
36110 * @event deactivate
36111 * Fires when this item is deactivated
36112 * @param {Roo.menu.BaseItem} this
36118 this.on("click", this.handler, this.scope, true);
36122 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36124 * @cfg {Function} handler
36125 * A function that will handle the click event of this menu item (defaults to undefined)
36128 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36130 canActivate : false,
36133 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36138 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36140 activeClass : "x-menu-item-active",
36142 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36144 hideOnClick : true,
36146 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36151 ctype: "Roo.menu.BaseItem",
36154 actionMode : "container",
36157 render : function(container, parentMenu){
36158 this.parentMenu = parentMenu;
36159 Roo.menu.BaseItem.superclass.render.call(this, container);
36160 this.container.menuItemId = this.id;
36164 onRender : function(container, position){
36165 this.el = Roo.get(this.el);
36166 container.dom.appendChild(this.el.dom);
36170 onClick : function(e){
36171 if(!this.disabled && this.fireEvent("click", this, e) !== false
36172 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36173 this.handleClick(e);
36180 activate : function(){
36184 var li = this.container;
36185 li.addClass(this.activeClass);
36186 this.region = li.getRegion().adjust(2, 2, -2, -2);
36187 this.fireEvent("activate", this);
36192 deactivate : function(){
36193 this.container.removeClass(this.activeClass);
36194 this.fireEvent("deactivate", this);
36198 shouldDeactivate : function(e){
36199 return !this.region || !this.region.contains(e.getPoint());
36203 handleClick : function(e){
36204 if(this.hideOnClick){
36205 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36210 expandMenu : function(autoActivate){
36215 hideMenu : function(){
36220 * Ext JS Library 1.1.1
36221 * Copyright(c) 2006-2007, Ext JS, LLC.
36223 * Originally Released Under LGPL - original licence link has changed is not relivant.
36226 * <script type="text/javascript">
36230 * @class Roo.menu.Adapter
36231 * @extends Roo.menu.BaseItem
36232 * 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.
36233 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36235 * Creates a new Adapter
36236 * @param {Object} config Configuration options
36238 Roo.menu.Adapter = function(component, config){
36239 Roo.menu.Adapter.superclass.constructor.call(this, config);
36240 this.component = component;
36242 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36244 canActivate : true,
36247 onRender : function(container, position){
36248 this.component.render(container);
36249 this.el = this.component.getEl();
36253 activate : function(){
36257 this.component.focus();
36258 this.fireEvent("activate", this);
36263 deactivate : function(){
36264 this.fireEvent("deactivate", this);
36268 disable : function(){
36269 this.component.disable();
36270 Roo.menu.Adapter.superclass.disable.call(this);
36274 enable : function(){
36275 this.component.enable();
36276 Roo.menu.Adapter.superclass.enable.call(this);
36280 * Ext JS Library 1.1.1
36281 * Copyright(c) 2006-2007, Ext JS, LLC.
36283 * Originally Released Under LGPL - original licence link has changed is not relivant.
36286 * <script type="text/javascript">
36290 * @class Roo.menu.TextItem
36291 * @extends Roo.menu.BaseItem
36292 * Adds a static text string to a menu, usually used as either a heading or group separator.
36293 * Note: old style constructor with text is still supported.
36296 * Creates a new TextItem
36297 * @param {Object} cfg Configuration
36299 Roo.menu.TextItem = function(cfg){
36300 if (typeof(cfg) == 'string') {
36303 Roo.apply(this,cfg);
36306 Roo.menu.TextItem.superclass.constructor.call(this);
36309 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36311 * @cfg {Boolean} text Text to show on item.
36316 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36318 hideOnClick : false,
36320 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36322 itemCls : "x-menu-text",
36325 onRender : function(){
36326 var s = document.createElement("span");
36327 s.className = this.itemCls;
36328 s.innerHTML = this.text;
36330 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36334 * Ext JS Library 1.1.1
36335 * Copyright(c) 2006-2007, Ext JS, LLC.
36337 * Originally Released Under LGPL - original licence link has changed is not relivant.
36340 * <script type="text/javascript">
36344 * @class Roo.menu.Separator
36345 * @extends Roo.menu.BaseItem
36346 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36347 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36349 * @param {Object} config Configuration options
36351 Roo.menu.Separator = function(config){
36352 Roo.menu.Separator.superclass.constructor.call(this, config);
36355 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36357 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36359 itemCls : "x-menu-sep",
36361 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36363 hideOnClick : false,
36366 onRender : function(li){
36367 var s = document.createElement("span");
36368 s.className = this.itemCls;
36369 s.innerHTML = " ";
36371 li.addClass("x-menu-sep-li");
36372 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36376 * Ext JS Library 1.1.1
36377 * Copyright(c) 2006-2007, Ext JS, LLC.
36379 * Originally Released Under LGPL - original licence link has changed is not relivant.
36382 * <script type="text/javascript">
36385 * @class Roo.menu.Item
36386 * @extends Roo.menu.BaseItem
36387 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36388 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36389 * activation and click handling.
36391 * Creates a new Item
36392 * @param {Object} config Configuration options
36394 Roo.menu.Item = function(config){
36395 Roo.menu.Item.superclass.constructor.call(this, config);
36397 this.menu = Roo.menu.MenuMgr.get(this.menu);
36400 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36403 * @cfg {String} text
36404 * The text to show on the menu item.
36408 * @cfg {String} HTML to render in menu
36409 * The text to show on the menu item (HTML version).
36413 * @cfg {String} icon
36414 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36418 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36420 itemCls : "x-menu-item",
36422 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36424 canActivate : true,
36426 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36429 // doc'd in BaseItem
36433 ctype: "Roo.menu.Item",
36436 onRender : function(container, position){
36437 var el = document.createElement("a");
36438 el.hideFocus = true;
36439 el.unselectable = "on";
36440 el.href = this.href || "#";
36441 if(this.hrefTarget){
36442 el.target = this.hrefTarget;
36444 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36446 var html = this.html.length ? this.html : String.format('{0}',this.text);
36448 el.innerHTML = String.format(
36449 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36450 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36452 Roo.menu.Item.superclass.onRender.call(this, container, position);
36456 * Sets the text to display in this menu item
36457 * @param {String} text The text to display
36458 * @param {Boolean} isHTML true to indicate text is pure html.
36460 setText : function(text, isHTML){
36468 var html = this.html.length ? this.html : String.format('{0}',this.text);
36470 this.el.update(String.format(
36471 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36472 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36473 this.parentMenu.autoWidth();
36478 handleClick : function(e){
36479 if(!this.href){ // if no link defined, stop the event automatically
36482 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36486 activate : function(autoExpand){
36487 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36497 shouldDeactivate : function(e){
36498 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36499 if(this.menu && this.menu.isVisible()){
36500 return !this.menu.getEl().getRegion().contains(e.getPoint());
36508 deactivate : function(){
36509 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36514 expandMenu : function(autoActivate){
36515 if(!this.disabled && this.menu){
36516 clearTimeout(this.hideTimer);
36517 delete this.hideTimer;
36518 if(!this.menu.isVisible() && !this.showTimer){
36519 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36520 }else if (this.menu.isVisible() && autoActivate){
36521 this.menu.tryActivate(0, 1);
36527 deferExpand : function(autoActivate){
36528 delete this.showTimer;
36529 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36531 this.menu.tryActivate(0, 1);
36536 hideMenu : function(){
36537 clearTimeout(this.showTimer);
36538 delete this.showTimer;
36539 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36540 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36545 deferHide : function(){
36546 delete this.hideTimer;
36551 * Ext JS Library 1.1.1
36552 * Copyright(c) 2006-2007, Ext JS, LLC.
36554 * Originally Released Under LGPL - original licence link has changed is not relivant.
36557 * <script type="text/javascript">
36561 * @class Roo.menu.CheckItem
36562 * @extends Roo.menu.Item
36563 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36565 * Creates a new CheckItem
36566 * @param {Object} config Configuration options
36568 Roo.menu.CheckItem = function(config){
36569 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36572 * @event beforecheckchange
36573 * Fires before the checked value is set, providing an opportunity to cancel if needed
36574 * @param {Roo.menu.CheckItem} this
36575 * @param {Boolean} checked The new checked value that will be set
36577 "beforecheckchange" : true,
36579 * @event checkchange
36580 * Fires after the checked value has been set
36581 * @param {Roo.menu.CheckItem} this
36582 * @param {Boolean} checked The checked value that was set
36584 "checkchange" : true
36586 if(this.checkHandler){
36587 this.on('checkchange', this.checkHandler, this.scope);
36590 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36592 * @cfg {String} group
36593 * All check items with the same group name will automatically be grouped into a single-select
36594 * radio button group (defaults to '')
36597 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36599 itemCls : "x-menu-item x-menu-check-item",
36601 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36603 groupClass : "x-menu-group-item",
36606 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36607 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36608 * initialized with checked = true will be rendered as checked.
36613 ctype: "Roo.menu.CheckItem",
36616 onRender : function(c){
36617 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36619 this.el.addClass(this.groupClass);
36621 Roo.menu.MenuMgr.registerCheckable(this);
36623 this.checked = false;
36624 this.setChecked(true, true);
36629 destroy : function(){
36631 Roo.menu.MenuMgr.unregisterCheckable(this);
36633 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36637 * Set the checked state of this item
36638 * @param {Boolean} checked The new checked value
36639 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36641 setChecked : function(state, suppressEvent){
36642 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36643 if(this.container){
36644 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36646 this.checked = state;
36647 if(suppressEvent !== true){
36648 this.fireEvent("checkchange", this, state);
36654 handleClick : function(e){
36655 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36656 this.setChecked(!this.checked);
36658 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36662 * Ext JS Library 1.1.1
36663 * Copyright(c) 2006-2007, Ext JS, LLC.
36665 * Originally Released Under LGPL - original licence link has changed is not relivant.
36668 * <script type="text/javascript">
36672 * @class Roo.menu.DateItem
36673 * @extends Roo.menu.Adapter
36674 * A menu item that wraps the {@link Roo.DatPicker} component.
36676 * Creates a new DateItem
36677 * @param {Object} config Configuration options
36679 Roo.menu.DateItem = function(config){
36680 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36681 /** The Roo.DatePicker object @type Roo.DatePicker */
36682 this.picker = this.component;
36683 this.addEvents({select: true});
36685 this.picker.on("render", function(picker){
36686 picker.getEl().swallowEvent("click");
36687 picker.container.addClass("x-menu-date-item");
36690 this.picker.on("select", this.onSelect, this);
36693 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36695 onSelect : function(picker, date){
36696 this.fireEvent("select", this, date, picker);
36697 Roo.menu.DateItem.superclass.handleClick.call(this);
36701 * Ext JS Library 1.1.1
36702 * Copyright(c) 2006-2007, Ext JS, LLC.
36704 * Originally Released Under LGPL - original licence link has changed is not relivant.
36707 * <script type="text/javascript">
36711 * @class Roo.menu.ColorItem
36712 * @extends Roo.menu.Adapter
36713 * A menu item that wraps the {@link Roo.ColorPalette} component.
36715 * Creates a new ColorItem
36716 * @param {Object} config Configuration options
36718 Roo.menu.ColorItem = function(config){
36719 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36720 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36721 this.palette = this.component;
36722 this.relayEvents(this.palette, ["select"]);
36723 if(this.selectHandler){
36724 this.on('select', this.selectHandler, this.scope);
36727 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36729 * Ext JS Library 1.1.1
36730 * Copyright(c) 2006-2007, Ext JS, LLC.
36732 * Originally Released Under LGPL - original licence link has changed is not relivant.
36735 * <script type="text/javascript">
36740 * @class Roo.menu.DateMenu
36741 * @extends Roo.menu.Menu
36742 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36744 * Creates a new DateMenu
36745 * @param {Object} config Configuration options
36747 Roo.menu.DateMenu = function(config){
36748 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36750 var di = new Roo.menu.DateItem(config);
36753 * The {@link Roo.DatePicker} instance for this DateMenu
36756 this.picker = di.picker;
36759 * @param {DatePicker} picker
36760 * @param {Date} date
36762 this.relayEvents(di, ["select"]);
36763 this.on('beforeshow', function(){
36765 this.picker.hideMonthPicker(false);
36769 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
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">
36784 * @class Roo.menu.ColorMenu
36785 * @extends Roo.menu.Menu
36786 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36788 * Creates a new ColorMenu
36789 * @param {Object} config Configuration options
36791 Roo.menu.ColorMenu = function(config){
36792 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36794 var ci = new Roo.menu.ColorItem(config);
36797 * The {@link Roo.ColorPalette} instance for this ColorMenu
36798 * @type ColorPalette
36800 this.palette = ci.palette;
36803 * @param {ColorPalette} palette
36804 * @param {String} color
36806 this.relayEvents(ci, ["select"]);
36808 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36810 * Ext JS Library 1.1.1
36811 * Copyright(c) 2006-2007, Ext JS, LLC.
36813 * Originally Released Under LGPL - original licence link has changed is not relivant.
36816 * <script type="text/javascript">
36820 * @class Roo.form.Field
36821 * @extends Roo.BoxComponent
36822 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36824 * Creates a new Field
36825 * @param {Object} config Configuration options
36827 Roo.form.Field = function(config){
36828 Roo.form.Field.superclass.constructor.call(this, config);
36831 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36833 * @cfg {String} fieldLabel Label to use when rendering a form.
36836 * @cfg {String} qtip Mouse over tip
36840 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36842 invalidClass : "x-form-invalid",
36844 * @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")
36846 invalidText : "The value in this field is invalid",
36848 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36850 focusClass : "x-form-focus",
36852 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36853 automatic validation (defaults to "keyup").
36855 validationEvent : "keyup",
36857 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36859 validateOnBlur : true,
36861 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36863 validationDelay : 250,
36865 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36866 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36868 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36870 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36872 fieldClass : "x-form-field",
36874 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36877 ----------- ----------------------------------------------------------------------
36878 qtip Display a quick tip when the user hovers over the field
36879 title Display a default browser title attribute popup
36880 under Add a block div beneath the field containing the error text
36881 side Add an error icon to the right of the field with a popup on hover
36882 [element id] Add the error text directly to the innerHTML of the specified element
36885 msgTarget : 'qtip',
36887 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36892 * @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.
36897 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36902 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36904 inputType : undefined,
36907 * @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).
36909 tabIndex : undefined,
36912 isFormField : true,
36917 * @property {Roo.Element} fieldEl
36918 * Element Containing the rendered Field (with label etc.)
36921 * @cfg {Mixed} value A value to initialize this field with.
36926 * @cfg {String} name The field's HTML name attribute.
36929 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36933 initComponent : function(){
36934 Roo.form.Field.superclass.initComponent.call(this);
36938 * Fires when this field receives input focus.
36939 * @param {Roo.form.Field} this
36944 * Fires when this field loses input focus.
36945 * @param {Roo.form.Field} this
36949 * @event specialkey
36950 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36951 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36952 * @param {Roo.form.Field} this
36953 * @param {Roo.EventObject} e The event object
36958 * Fires just before the field blurs if the field value has changed.
36959 * @param {Roo.form.Field} this
36960 * @param {Mixed} newValue The new value
36961 * @param {Mixed} oldValue The original value
36966 * Fires after the field has been marked as invalid.
36967 * @param {Roo.form.Field} this
36968 * @param {String} msg The validation message
36973 * Fires after the field has been validated with no errors.
36974 * @param {Roo.form.Field} this
36979 * Fires after the key up
36980 * @param {Roo.form.Field} this
36981 * @param {Roo.EventObject} e The event Object
36988 * Returns the name attribute of the field if available
36989 * @return {String} name The field name
36991 getName: function(){
36992 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
36996 onRender : function(ct, position){
36997 Roo.form.Field.superclass.onRender.call(this, ct, position);
36999 var cfg = this.getAutoCreate();
37001 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37003 if (!cfg.name.length) {
37006 if(this.inputType){
37007 cfg.type = this.inputType;
37009 this.el = ct.createChild(cfg, position);
37011 var type = this.el.dom.type;
37013 if(type == 'password'){
37016 this.el.addClass('x-form-'+type);
37019 this.el.dom.readOnly = true;
37021 if(this.tabIndex !== undefined){
37022 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37025 this.el.addClass([this.fieldClass, this.cls]);
37030 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37031 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37032 * @return {Roo.form.Field} this
37034 applyTo : function(target){
37035 this.allowDomMove = false;
37036 this.el = Roo.get(target);
37037 this.render(this.el.dom.parentNode);
37042 initValue : function(){
37043 if(this.value !== undefined){
37044 this.setValue(this.value);
37045 }else if(this.el.dom.value.length > 0){
37046 this.setValue(this.el.dom.value);
37051 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37053 isDirty : function() {
37054 if(this.disabled) {
37057 return String(this.getValue()) !== String(this.originalValue);
37061 afterRender : function(){
37062 Roo.form.Field.superclass.afterRender.call(this);
37067 fireKey : function(e){
37068 //Roo.log('field ' + e.getKey());
37069 if(e.isNavKeyPress()){
37070 this.fireEvent("specialkey", this, e);
37075 * Resets the current field value to the originally loaded value and clears any validation messages
37077 reset : function(){
37078 this.setValue(this.resetValue);
37079 this.clearInvalid();
37083 initEvents : function(){
37084 // safari killled keypress - so keydown is now used..
37085 this.el.on("keydown" , this.fireKey, this);
37086 this.el.on("focus", this.onFocus, this);
37087 this.el.on("blur", this.onBlur, this);
37088 this.el.relayEvent('keyup', this);
37090 // reference to original value for reset
37091 this.originalValue = this.getValue();
37092 this.resetValue = this.getValue();
37096 onFocus : function(){
37097 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37098 this.el.addClass(this.focusClass);
37100 if(!this.hasFocus){
37101 this.hasFocus = true;
37102 this.startValue = this.getValue();
37103 this.fireEvent("focus", this);
37107 beforeBlur : Roo.emptyFn,
37110 onBlur : function(){
37112 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37113 this.el.removeClass(this.focusClass);
37115 this.hasFocus = false;
37116 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37119 var v = this.getValue();
37120 if(String(v) !== String(this.startValue)){
37121 this.fireEvent('change', this, v, this.startValue);
37123 this.fireEvent("blur", this);
37127 * Returns whether or not the field value is currently valid
37128 * @param {Boolean} preventMark True to disable marking the field invalid
37129 * @return {Boolean} True if the value is valid, else false
37131 isValid : function(preventMark){
37135 var restore = this.preventMark;
37136 this.preventMark = preventMark === true;
37137 var v = this.validateValue(this.processValue(this.getRawValue()));
37138 this.preventMark = restore;
37143 * Validates the field value
37144 * @return {Boolean} True if the value is valid, else false
37146 validate : function(){
37147 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37148 this.clearInvalid();
37154 processValue : function(value){
37159 // Subclasses should provide the validation implementation by overriding this
37160 validateValue : function(value){
37165 * Mark this field as invalid
37166 * @param {String} msg The validation message
37168 markInvalid : function(msg){
37169 if(!this.rendered || this.preventMark){ // not rendered
37173 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37175 obj.el.addClass(this.invalidClass);
37176 msg = msg || this.invalidText;
37177 switch(this.msgTarget){
37179 obj.el.dom.qtip = msg;
37180 obj.el.dom.qclass = 'x-form-invalid-tip';
37181 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37182 Roo.QuickTips.enable();
37186 this.el.dom.title = msg;
37190 var elp = this.el.findParent('.x-form-element', 5, true);
37191 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37192 this.errorEl.setWidth(elp.getWidth(true)-20);
37194 this.errorEl.update(msg);
37195 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37198 if(!this.errorIcon){
37199 var elp = this.el.findParent('.x-form-element', 5, true);
37200 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37202 this.alignErrorIcon();
37203 this.errorIcon.dom.qtip = msg;
37204 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37205 this.errorIcon.show();
37206 this.on('resize', this.alignErrorIcon, this);
37209 var t = Roo.getDom(this.msgTarget);
37211 t.style.display = this.msgDisplay;
37214 this.fireEvent('invalid', this, msg);
37218 alignErrorIcon : function(){
37219 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37223 * Clear any invalid styles/messages for this field
37225 clearInvalid : function(){
37226 if(!this.rendered || this.preventMark){ // not rendered
37229 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37231 obj.el.removeClass(this.invalidClass);
37232 switch(this.msgTarget){
37234 obj.el.dom.qtip = '';
37237 this.el.dom.title = '';
37241 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37245 if(this.errorIcon){
37246 this.errorIcon.dom.qtip = '';
37247 this.errorIcon.hide();
37248 this.un('resize', this.alignErrorIcon, this);
37252 var t = Roo.getDom(this.msgTarget);
37254 t.style.display = 'none';
37257 this.fireEvent('valid', this);
37261 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37262 * @return {Mixed} value The field value
37264 getRawValue : function(){
37265 var v = this.el.getValue();
37271 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37272 * @return {Mixed} value The field value
37274 getValue : function(){
37275 var v = this.el.getValue();
37281 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37282 * @param {Mixed} value The value to set
37284 setRawValue : function(v){
37285 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37289 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37290 * @param {Mixed} value The value to set
37292 setValue : function(v){
37295 this.el.dom.value = (v === null || v === undefined ? '' : v);
37300 adjustSize : function(w, h){
37301 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37302 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37306 adjustWidth : function(tag, w){
37307 tag = tag.toLowerCase();
37308 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37309 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37310 if(tag == 'input'){
37313 if(tag == 'textarea'){
37316 }else if(Roo.isOpera){
37317 if(tag == 'input'){
37320 if(tag == 'textarea'){
37330 // anything other than normal should be considered experimental
37331 Roo.form.Field.msgFx = {
37333 show: function(msgEl, f){
37334 msgEl.setDisplayed('block');
37337 hide : function(msgEl, f){
37338 msgEl.setDisplayed(false).update('');
37343 show: function(msgEl, f){
37344 msgEl.slideIn('t', {stopFx:true});
37347 hide : function(msgEl, f){
37348 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37353 show: function(msgEl, f){
37354 msgEl.fixDisplay();
37355 msgEl.alignTo(f.el, 'tl-tr');
37356 msgEl.slideIn('l', {stopFx:true});
37359 hide : function(msgEl, f){
37360 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37365 * Ext JS Library 1.1.1
37366 * Copyright(c) 2006-2007, Ext JS, LLC.
37368 * Originally Released Under LGPL - original licence link has changed is not relivant.
37371 * <script type="text/javascript">
37376 * @class Roo.form.TextField
37377 * @extends Roo.form.Field
37378 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37379 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37381 * Creates a new TextField
37382 * @param {Object} config Configuration options
37384 Roo.form.TextField = function(config){
37385 Roo.form.TextField.superclass.constructor.call(this, config);
37389 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37390 * according to the default logic, but this event provides a hook for the developer to apply additional
37391 * logic at runtime to resize the field if needed.
37392 * @param {Roo.form.Field} this This text field
37393 * @param {Number} width The new field width
37399 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37401 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37405 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37409 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37413 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37417 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37421 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37423 disableKeyFilter : false,
37425 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37429 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37433 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37435 maxLength : Number.MAX_VALUE,
37437 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37439 minLengthText : "The minimum length for this field is {0}",
37441 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37443 maxLengthText : "The maximum length for this field is {0}",
37445 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37447 selectOnFocus : false,
37449 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37451 blankText : "This field is required",
37453 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37454 * If available, this function will be called only after the basic validators all return true, and will be passed the
37455 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37459 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37460 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37461 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37465 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37469 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37475 initEvents : function()
37477 if (this.emptyText) {
37478 this.el.attr('placeholder', this.emptyText);
37481 Roo.form.TextField.superclass.initEvents.call(this);
37482 if(this.validationEvent == 'keyup'){
37483 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37484 this.el.on('keyup', this.filterValidation, this);
37486 else if(this.validationEvent !== false){
37487 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37490 if(this.selectOnFocus){
37491 this.on("focus", this.preFocus, this);
37494 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37495 this.el.on("keypress", this.filterKeys, this);
37498 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37499 this.el.on("click", this.autoSize, this);
37501 if(this.el.is('input[type=password]') && Roo.isSafari){
37502 this.el.on('keydown', this.SafariOnKeyDown, this);
37506 processValue : function(value){
37507 if(this.stripCharsRe){
37508 var newValue = value.replace(this.stripCharsRe, '');
37509 if(newValue !== value){
37510 this.setRawValue(newValue);
37517 filterValidation : function(e){
37518 if(!e.isNavKeyPress()){
37519 this.validationTask.delay(this.validationDelay);
37524 onKeyUp : function(e){
37525 if(!e.isNavKeyPress()){
37531 * Resets the current field value to the originally-loaded value and clears any validation messages.
37534 reset : function(){
37535 Roo.form.TextField.superclass.reset.call(this);
37541 preFocus : function(){
37543 if(this.selectOnFocus){
37544 this.el.dom.select();
37550 filterKeys : function(e){
37551 var k = e.getKey();
37552 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37555 var c = e.getCharCode(), cc = String.fromCharCode(c);
37556 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37559 if(!this.maskRe.test(cc)){
37564 setValue : function(v){
37566 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37572 * Validates a value according to the field's validation rules and marks the field as invalid
37573 * if the validation fails
37574 * @param {Mixed} value The value to validate
37575 * @return {Boolean} True if the value is valid, else false
37577 validateValue : function(value){
37578 if(value.length < 1) { // if it's blank
37579 if(this.allowBlank){
37580 this.clearInvalid();
37583 this.markInvalid(this.blankText);
37587 if(value.length < this.minLength){
37588 this.markInvalid(String.format(this.minLengthText, this.minLength));
37591 if(value.length > this.maxLength){
37592 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37596 var vt = Roo.form.VTypes;
37597 if(!vt[this.vtype](value, this)){
37598 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37602 if(typeof this.validator == "function"){
37603 var msg = this.validator(value);
37605 this.markInvalid(msg);
37609 if(this.regex && !this.regex.test(value)){
37610 this.markInvalid(this.regexText);
37617 * Selects text in this field
37618 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37619 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37621 selectText : function(start, end){
37622 var v = this.getRawValue();
37624 start = start === undefined ? 0 : start;
37625 end = end === undefined ? v.length : end;
37626 var d = this.el.dom;
37627 if(d.setSelectionRange){
37628 d.setSelectionRange(start, end);
37629 }else if(d.createTextRange){
37630 var range = d.createTextRange();
37631 range.moveStart("character", start);
37632 range.moveEnd("character", v.length-end);
37639 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37640 * This only takes effect if grow = true, and fires the autosize event.
37642 autoSize : function(){
37643 if(!this.grow || !this.rendered){
37647 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37650 var v = el.dom.value;
37651 var d = document.createElement('div');
37652 d.appendChild(document.createTextNode(v));
37656 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37657 this.el.setWidth(w);
37658 this.fireEvent("autosize", this, w);
37662 SafariOnKeyDown : function(event)
37664 // this is a workaround for a password hang bug on chrome/ webkit.
37666 var isSelectAll = false;
37668 if(this.el.dom.selectionEnd > 0){
37669 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37671 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37672 event.preventDefault();
37677 if(isSelectAll){ // backspace and delete key
37679 event.preventDefault();
37680 // this is very hacky as keydown always get's upper case.
37682 var cc = String.fromCharCode(event.getCharCode());
37683 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37691 * Ext JS Library 1.1.1
37692 * Copyright(c) 2006-2007, Ext JS, LLC.
37694 * Originally Released Under LGPL - original licence link has changed is not relivant.
37697 * <script type="text/javascript">
37701 * @class Roo.form.Hidden
37702 * @extends Roo.form.TextField
37703 * Simple Hidden element used on forms
37705 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37708 * Creates a new Hidden form element.
37709 * @param {Object} config Configuration options
37714 // easy hidden field...
37715 Roo.form.Hidden = function(config){
37716 Roo.form.Hidden.superclass.constructor.call(this, config);
37719 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37721 inputType: 'hidden',
37724 labelSeparator: '',
37726 itemCls : 'x-form-item-display-none'
37734 * Ext JS Library 1.1.1
37735 * Copyright(c) 2006-2007, Ext JS, LLC.
37737 * Originally Released Under LGPL - original licence link has changed is not relivant.
37740 * <script type="text/javascript">
37744 * @class Roo.form.TriggerField
37745 * @extends Roo.form.TextField
37746 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37747 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37748 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37749 * for which you can provide a custom implementation. For example:
37751 var trigger = new Roo.form.TriggerField();
37752 trigger.onTriggerClick = myTriggerFn;
37753 trigger.applyTo('my-field');
37756 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37757 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37758 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37759 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37761 * Create a new TriggerField.
37762 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37763 * to the base TextField)
37765 Roo.form.TriggerField = function(config){
37766 this.mimicing = false;
37767 Roo.form.TriggerField.superclass.constructor.call(this, config);
37770 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37772 * @cfg {String} triggerClass A CSS class to apply to the trigger
37775 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37776 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37778 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37780 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37784 /** @cfg {Boolean} grow @hide */
37785 /** @cfg {Number} growMin @hide */
37786 /** @cfg {Number} growMax @hide */
37792 autoSize: Roo.emptyFn,
37796 deferHeight : true,
37799 actionMode : 'wrap',
37801 onResize : function(w, h){
37802 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37803 if(typeof w == 'number'){
37804 var x = w - this.trigger.getWidth();
37805 this.el.setWidth(this.adjustWidth('input', x));
37806 this.trigger.setStyle('left', x+'px');
37811 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37814 getResizeEl : function(){
37819 getPositionEl : function(){
37824 alignErrorIcon : function(){
37825 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37829 onRender : function(ct, position){
37830 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37831 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37832 this.trigger = this.wrap.createChild(this.triggerConfig ||
37833 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37834 if(this.hideTrigger){
37835 this.trigger.setDisplayed(false);
37837 this.initTrigger();
37839 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37844 initTrigger : function(){
37845 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37846 this.trigger.addClassOnOver('x-form-trigger-over');
37847 this.trigger.addClassOnClick('x-form-trigger-click');
37851 onDestroy : function(){
37853 this.trigger.removeAllListeners();
37854 this.trigger.remove();
37857 this.wrap.remove();
37859 Roo.form.TriggerField.superclass.onDestroy.call(this);
37863 onFocus : function(){
37864 Roo.form.TriggerField.superclass.onFocus.call(this);
37865 if(!this.mimicing){
37866 this.wrap.addClass('x-trigger-wrap-focus');
37867 this.mimicing = true;
37868 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37869 if(this.monitorTab){
37870 this.el.on("keydown", this.checkTab, this);
37876 checkTab : function(e){
37877 if(e.getKey() == e.TAB){
37878 this.triggerBlur();
37883 onBlur : function(){
37888 mimicBlur : function(e, t){
37889 if(!this.wrap.contains(t) && this.validateBlur()){
37890 this.triggerBlur();
37895 triggerBlur : function(){
37896 this.mimicing = false;
37897 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37898 if(this.monitorTab){
37899 this.el.un("keydown", this.checkTab, this);
37901 this.wrap.removeClass('x-trigger-wrap-focus');
37902 Roo.form.TriggerField.superclass.onBlur.call(this);
37906 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37907 validateBlur : function(e, t){
37912 onDisable : function(){
37913 Roo.form.TriggerField.superclass.onDisable.call(this);
37915 this.wrap.addClass('x-item-disabled');
37920 onEnable : function(){
37921 Roo.form.TriggerField.superclass.onEnable.call(this);
37923 this.wrap.removeClass('x-item-disabled');
37928 onShow : function(){
37929 var ae = this.getActionEl();
37932 ae.dom.style.display = '';
37933 ae.dom.style.visibility = 'visible';
37939 onHide : function(){
37940 var ae = this.getActionEl();
37941 ae.dom.style.display = 'none';
37945 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37946 * by an implementing function.
37948 * @param {EventObject} e
37950 onTriggerClick : Roo.emptyFn
37953 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37954 // to be extended by an implementing class. For an example of implementing this class, see the custom
37955 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37956 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37957 initComponent : function(){
37958 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37960 this.triggerConfig = {
37961 tag:'span', cls:'x-form-twin-triggers', cn:[
37962 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37963 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
37967 getTrigger : function(index){
37968 return this.triggers[index];
37971 initTrigger : function(){
37972 var ts = this.trigger.select('.x-form-trigger', true);
37973 this.wrap.setStyle('overflow', 'hidden');
37974 var triggerField = this;
37975 ts.each(function(t, all, index){
37976 t.hide = function(){
37977 var w = triggerField.wrap.getWidth();
37978 this.dom.style.display = 'none';
37979 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37981 t.show = function(){
37982 var w = triggerField.wrap.getWidth();
37983 this.dom.style.display = '';
37984 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
37986 var triggerIndex = 'Trigger'+(index+1);
37988 if(this['hide'+triggerIndex]){
37989 t.dom.style.display = 'none';
37991 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
37992 t.addClassOnOver('x-form-trigger-over');
37993 t.addClassOnClick('x-form-trigger-click');
37995 this.triggers = ts.elements;
37998 onTrigger1Click : Roo.emptyFn,
37999 onTrigger2Click : Roo.emptyFn
38002 * Ext JS Library 1.1.1
38003 * Copyright(c) 2006-2007, Ext JS, LLC.
38005 * Originally Released Under LGPL - original licence link has changed is not relivant.
38008 * <script type="text/javascript">
38012 * @class Roo.form.TextArea
38013 * @extends Roo.form.TextField
38014 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38015 * support for auto-sizing.
38017 * Creates a new TextArea
38018 * @param {Object} config Configuration options
38020 Roo.form.TextArea = function(config){
38021 Roo.form.TextArea.superclass.constructor.call(this, config);
38022 // these are provided exchanges for backwards compat
38023 // minHeight/maxHeight were replaced by growMin/growMax to be
38024 // compatible with TextField growing config values
38025 if(this.minHeight !== undefined){
38026 this.growMin = this.minHeight;
38028 if(this.maxHeight !== undefined){
38029 this.growMax = this.maxHeight;
38033 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38035 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38039 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38043 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38044 * in the field (equivalent to setting overflow: hidden, defaults to false)
38046 preventScrollbars: false,
38048 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38049 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38053 onRender : function(ct, position){
38055 this.defaultAutoCreate = {
38057 style:"width:300px;height:60px;",
38058 autocomplete: "off"
38061 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38063 this.textSizeEl = Roo.DomHelper.append(document.body, {
38064 tag: "pre", cls: "x-form-grow-sizer"
38066 if(this.preventScrollbars){
38067 this.el.setStyle("overflow", "hidden");
38069 this.el.setHeight(this.growMin);
38073 onDestroy : function(){
38074 if(this.textSizeEl){
38075 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38077 Roo.form.TextArea.superclass.onDestroy.call(this);
38081 onKeyUp : function(e){
38082 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38088 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38089 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38091 autoSize : function(){
38092 if(!this.grow || !this.textSizeEl){
38096 var v = el.dom.value;
38097 var ts = this.textSizeEl;
38100 ts.appendChild(document.createTextNode(v));
38103 Roo.fly(ts).setWidth(this.el.getWidth());
38105 v = "  ";
38108 v = v.replace(/\n/g, '<p> </p>');
38110 v += " \n ";
38113 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38114 if(h != this.lastHeight){
38115 this.lastHeight = h;
38116 this.el.setHeight(h);
38117 this.fireEvent("autosize", this, h);
38122 * Ext JS Library 1.1.1
38123 * Copyright(c) 2006-2007, Ext JS, LLC.
38125 * Originally Released Under LGPL - original licence link has changed is not relivant.
38128 * <script type="text/javascript">
38133 * @class Roo.form.NumberField
38134 * @extends Roo.form.TextField
38135 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38137 * Creates a new NumberField
38138 * @param {Object} config Configuration options
38140 Roo.form.NumberField = function(config){
38141 Roo.form.NumberField.superclass.constructor.call(this, config);
38144 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38146 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38148 fieldClass: "x-form-field x-form-num-field",
38150 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38152 allowDecimals : true,
38154 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38156 decimalSeparator : ".",
38158 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38160 decimalPrecision : 2,
38162 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38164 allowNegative : true,
38166 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38168 minValue : Number.NEGATIVE_INFINITY,
38170 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38172 maxValue : Number.MAX_VALUE,
38174 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38176 minText : "The minimum value for this field is {0}",
38178 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38180 maxText : "The maximum value for this field is {0}",
38182 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38183 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38185 nanText : "{0} is not a valid number",
38188 initEvents : function(){
38189 Roo.form.NumberField.superclass.initEvents.call(this);
38190 var allowed = "0123456789";
38191 if(this.allowDecimals){
38192 allowed += this.decimalSeparator;
38194 if(this.allowNegative){
38197 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38198 var keyPress = function(e){
38199 var k = e.getKey();
38200 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38203 var c = e.getCharCode();
38204 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38208 this.el.on("keypress", keyPress, this);
38212 validateValue : function(value){
38213 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38216 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38219 var num = this.parseValue(value);
38221 this.markInvalid(String.format(this.nanText, value));
38224 if(num < this.minValue){
38225 this.markInvalid(String.format(this.minText, this.minValue));
38228 if(num > this.maxValue){
38229 this.markInvalid(String.format(this.maxText, this.maxValue));
38235 getValue : function(){
38236 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38240 parseValue : function(value){
38241 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38242 return isNaN(value) ? '' : value;
38246 fixPrecision : function(value){
38247 var nan = isNaN(value);
38248 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38249 return nan ? '' : value;
38251 return parseFloat(value).toFixed(this.decimalPrecision);
38254 setValue : function(v){
38255 v = this.fixPrecision(v);
38256 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38260 decimalPrecisionFcn : function(v){
38261 return Math.floor(v);
38264 beforeBlur : function(){
38265 var v = this.parseValue(this.getRawValue());
38272 * Ext JS Library 1.1.1
38273 * Copyright(c) 2006-2007, Ext JS, LLC.
38275 * Originally Released Under LGPL - original licence link has changed is not relivant.
38278 * <script type="text/javascript">
38282 * @class Roo.form.DateField
38283 * @extends Roo.form.TriggerField
38284 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38286 * Create a new DateField
38287 * @param {Object} config
38289 Roo.form.DateField = function(config){
38290 Roo.form.DateField.superclass.constructor.call(this, config);
38296 * Fires when a date is selected
38297 * @param {Roo.form.DateField} combo This combo box
38298 * @param {Date} date The date selected
38305 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38306 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38307 this.ddMatch = null;
38308 if(this.disabledDates){
38309 var dd = this.disabledDates;
38311 for(var i = 0; i < dd.length; i++){
38313 if(i != dd.length-1) re += "|";
38315 this.ddMatch = new RegExp(re + ")");
38319 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38321 * @cfg {String} format
38322 * The default date format string which can be overriden for localization support. The format must be
38323 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38327 * @cfg {String} altFormats
38328 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38329 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38331 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38333 * @cfg {Array} disabledDays
38334 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38336 disabledDays : null,
38338 * @cfg {String} disabledDaysText
38339 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38341 disabledDaysText : "Disabled",
38343 * @cfg {Array} disabledDates
38344 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38345 * expression so they are very powerful. Some examples:
38347 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38348 * <li>["03/08", "09/16"] would disable those days for every year</li>
38349 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38350 * <li>["03/../2006"] would disable every day in March 2006</li>
38351 * <li>["^03"] would disable every day in every March</li>
38353 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38354 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38356 disabledDates : null,
38358 * @cfg {String} disabledDatesText
38359 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38361 disabledDatesText : "Disabled",
38363 * @cfg {Date/String} minValue
38364 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38365 * valid format (defaults to null).
38369 * @cfg {Date/String} maxValue
38370 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38371 * valid format (defaults to null).
38375 * @cfg {String} minText
38376 * The error text to display when the date in the cell is before minValue (defaults to
38377 * 'The date in this field must be after {minValue}').
38379 minText : "The date in this field must be equal to or after {0}",
38381 * @cfg {String} maxText
38382 * The error text to display when the date in the cell is after maxValue (defaults to
38383 * 'The date in this field must be before {maxValue}').
38385 maxText : "The date in this field must be equal to or before {0}",
38387 * @cfg {String} invalidText
38388 * The error text to display when the date in the field is invalid (defaults to
38389 * '{value} is not a valid date - it must be in the format {format}').
38391 invalidText : "{0} is not a valid date - it must be in the format {1}",
38393 * @cfg {String} triggerClass
38394 * An additional CSS class used to style the trigger button. The trigger will always get the
38395 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38396 * which displays a calendar icon).
38398 triggerClass : 'x-form-date-trigger',
38402 * @cfg {Boolean} useIso
38403 * if enabled, then the date field will use a hidden field to store the
38404 * real value as iso formated date. default (false)
38408 * @cfg {String/Object} autoCreate
38409 * A DomHelper element spec, or true for a default element spec (defaults to
38410 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38413 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38416 hiddenField: false,
38418 onRender : function(ct, position)
38420 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38422 //this.el.dom.removeAttribute('name');
38423 Roo.log("Changing name?");
38424 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38425 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38427 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38428 // prevent input submission
38429 this.hiddenName = this.name;
38436 validateValue : function(value)
38438 value = this.formatDate(value);
38439 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38440 Roo.log('super failed');
38443 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38446 var svalue = value;
38447 value = this.parseDate(value);
38449 Roo.log('parse date failed' + svalue);
38450 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38453 var time = value.getTime();
38454 if(this.minValue && time < this.minValue.getTime()){
38455 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38458 if(this.maxValue && time > this.maxValue.getTime()){
38459 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38462 if(this.disabledDays){
38463 var day = value.getDay();
38464 for(var i = 0; i < this.disabledDays.length; i++) {
38465 if(day === this.disabledDays[i]){
38466 this.markInvalid(this.disabledDaysText);
38471 var fvalue = this.formatDate(value);
38472 if(this.ddMatch && this.ddMatch.test(fvalue)){
38473 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38480 // Provides logic to override the default TriggerField.validateBlur which just returns true
38481 validateBlur : function(){
38482 return !this.menu || !this.menu.isVisible();
38485 getName: function()
38487 // returns hidden if it's set..
38488 if (!this.rendered) {return ''};
38489 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38494 * Returns the current date value of the date field.
38495 * @return {Date} The date value
38497 getValue : function(){
38499 return this.hiddenField ?
38500 this.hiddenField.value :
38501 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38505 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38506 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38507 * (the default format used is "m/d/y").
38510 //All of these calls set the same date value (May 4, 2006)
38512 //Pass a date object:
38513 var dt = new Date('5/4/06');
38514 dateField.setValue(dt);
38516 //Pass a date string (default format):
38517 dateField.setValue('5/4/06');
38519 //Pass a date string (custom format):
38520 dateField.format = 'Y-m-d';
38521 dateField.setValue('2006-5-4');
38523 * @param {String/Date} date The date or valid date string
38525 setValue : function(date){
38526 if (this.hiddenField) {
38527 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38529 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38530 // make sure the value field is always stored as a date..
38531 this.value = this.parseDate(date);
38537 parseDate : function(value){
38538 if(!value || value instanceof Date){
38541 var v = Date.parseDate(value, this.format);
38542 if (!v && this.useIso) {
38543 v = Date.parseDate(value, 'Y-m-d');
38545 if(!v && this.altFormats){
38546 if(!this.altFormatsArray){
38547 this.altFormatsArray = this.altFormats.split("|");
38549 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38550 v = Date.parseDate(value, this.altFormatsArray[i]);
38557 formatDate : function(date, fmt){
38558 return (!date || !(date instanceof Date)) ?
38559 date : date.dateFormat(fmt || this.format);
38564 select: function(m, d){
38567 this.fireEvent('select', this, d);
38569 show : function(){ // retain focus styling
38573 this.focus.defer(10, this);
38574 var ml = this.menuListeners;
38575 this.menu.un("select", ml.select, this);
38576 this.menu.un("show", ml.show, this);
38577 this.menu.un("hide", ml.hide, this);
38582 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38583 onTriggerClick : function(){
38587 if(this.menu == null){
38588 this.menu = new Roo.menu.DateMenu();
38590 Roo.apply(this.menu.picker, {
38591 showClear: this.allowBlank,
38592 minDate : this.minValue,
38593 maxDate : this.maxValue,
38594 disabledDatesRE : this.ddMatch,
38595 disabledDatesText : this.disabledDatesText,
38596 disabledDays : this.disabledDays,
38597 disabledDaysText : this.disabledDaysText,
38598 format : this.useIso ? 'Y-m-d' : this.format,
38599 minText : String.format(this.minText, this.formatDate(this.minValue)),
38600 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38602 this.menu.on(Roo.apply({}, this.menuListeners, {
38605 this.menu.picker.setValue(this.getValue() || new Date());
38606 this.menu.show(this.el, "tl-bl?");
38609 beforeBlur : function(){
38610 var v = this.parseDate(this.getRawValue());
38620 isDirty : function() {
38621 if(this.disabled) {
38625 if(typeof(this.startValue) === 'undefined'){
38629 return String(this.getValue()) !== String(this.startValue);
38634 * Ext JS Library 1.1.1
38635 * Copyright(c) 2006-2007, Ext JS, LLC.
38637 * Originally Released Under LGPL - original licence link has changed is not relivant.
38640 * <script type="text/javascript">
38644 * @class Roo.form.MonthField
38645 * @extends Roo.form.TriggerField
38646 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38648 * Create a new MonthField
38649 * @param {Object} config
38651 Roo.form.MonthField = function(config){
38653 Roo.form.MonthField.superclass.constructor.call(this, config);
38659 * Fires when a date is selected
38660 * @param {Roo.form.MonthFieeld} combo This combo box
38661 * @param {Date} date The date selected
38668 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38669 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38670 this.ddMatch = null;
38671 if(this.disabledDates){
38672 var dd = this.disabledDates;
38674 for(var i = 0; i < dd.length; i++){
38676 if(i != dd.length-1) re += "|";
38678 this.ddMatch = new RegExp(re + ")");
38682 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38684 * @cfg {String} format
38685 * The default date format string which can be overriden for localization support. The format must be
38686 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38690 * @cfg {String} altFormats
38691 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38692 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38694 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38696 * @cfg {Array} disabledDays
38697 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38699 disabledDays : [0,1,2,3,4,5,6],
38701 * @cfg {String} disabledDaysText
38702 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38704 disabledDaysText : "Disabled",
38706 * @cfg {Array} disabledDates
38707 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38708 * expression so they are very powerful. Some examples:
38710 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38711 * <li>["03/08", "09/16"] would disable those days for every year</li>
38712 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38713 * <li>["03/../2006"] would disable every day in March 2006</li>
38714 * <li>["^03"] would disable every day in every March</li>
38716 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38717 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38719 disabledDates : null,
38721 * @cfg {String} disabledDatesText
38722 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38724 disabledDatesText : "Disabled",
38726 * @cfg {Date/String} minValue
38727 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38728 * valid format (defaults to null).
38732 * @cfg {Date/String} maxValue
38733 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38734 * valid format (defaults to null).
38738 * @cfg {String} minText
38739 * The error text to display when the date in the cell is before minValue (defaults to
38740 * 'The date in this field must be after {minValue}').
38742 minText : "The date in this field must be equal to or after {0}",
38744 * @cfg {String} maxTextf
38745 * The error text to display when the date in the cell is after maxValue (defaults to
38746 * 'The date in this field must be before {maxValue}').
38748 maxText : "The date in this field must be equal to or before {0}",
38750 * @cfg {String} invalidText
38751 * The error text to display when the date in the field is invalid (defaults to
38752 * '{value} is not a valid date - it must be in the format {format}').
38754 invalidText : "{0} is not a valid date - it must be in the format {1}",
38756 * @cfg {String} triggerClass
38757 * An additional CSS class used to style the trigger button. The trigger will always get the
38758 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38759 * which displays a calendar icon).
38761 triggerClass : 'x-form-date-trigger',
38765 * @cfg {Boolean} useIso
38766 * if enabled, then the date field will use a hidden field to store the
38767 * real value as iso formated date. default (true)
38771 * @cfg {String/Object} autoCreate
38772 * A DomHelper element spec, or true for a default element spec (defaults to
38773 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38776 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38779 hiddenField: false,
38781 hideMonthPicker : false,
38783 onRender : function(ct, position)
38785 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38787 this.el.dom.removeAttribute('name');
38788 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38790 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38791 // prevent input submission
38792 this.hiddenName = this.name;
38799 validateValue : function(value)
38801 value = this.formatDate(value);
38802 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38805 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38808 var svalue = value;
38809 value = this.parseDate(value);
38811 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38814 var time = value.getTime();
38815 if(this.minValue && time < this.minValue.getTime()){
38816 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38819 if(this.maxValue && time > this.maxValue.getTime()){
38820 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38823 /*if(this.disabledDays){
38824 var day = value.getDay();
38825 for(var i = 0; i < this.disabledDays.length; i++) {
38826 if(day === this.disabledDays[i]){
38827 this.markInvalid(this.disabledDaysText);
38833 var fvalue = this.formatDate(value);
38834 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38835 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38843 // Provides logic to override the default TriggerField.validateBlur which just returns true
38844 validateBlur : function(){
38845 return !this.menu || !this.menu.isVisible();
38849 * Returns the current date value of the date field.
38850 * @return {Date} The date value
38852 getValue : function(){
38856 return this.hiddenField ?
38857 this.hiddenField.value :
38858 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38862 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38863 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38864 * (the default format used is "m/d/y").
38867 //All of these calls set the same date value (May 4, 2006)
38869 //Pass a date object:
38870 var dt = new Date('5/4/06');
38871 monthField.setValue(dt);
38873 //Pass a date string (default format):
38874 monthField.setValue('5/4/06');
38876 //Pass a date string (custom format):
38877 monthField.format = 'Y-m-d';
38878 monthField.setValue('2006-5-4');
38880 * @param {String/Date} date The date or valid date string
38882 setValue : function(date){
38883 Roo.log('month setValue' + date);
38884 // can only be first of month..
38886 var val = this.parseDate(date);
38888 if (this.hiddenField) {
38889 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38891 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38892 this.value = this.parseDate(date);
38896 parseDate : function(value){
38897 if(!value || value instanceof Date){
38898 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38901 var v = Date.parseDate(value, this.format);
38902 if (!v && this.useIso) {
38903 v = Date.parseDate(value, 'Y-m-d');
38907 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38911 if(!v && this.altFormats){
38912 if(!this.altFormatsArray){
38913 this.altFormatsArray = this.altFormats.split("|");
38915 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38916 v = Date.parseDate(value, this.altFormatsArray[i]);
38923 formatDate : function(date, fmt){
38924 return (!date || !(date instanceof Date)) ?
38925 date : date.dateFormat(fmt || this.format);
38930 select: function(m, d){
38932 this.fireEvent('select', this, d);
38934 show : function(){ // retain focus styling
38938 this.focus.defer(10, this);
38939 var ml = this.menuListeners;
38940 this.menu.un("select", ml.select, this);
38941 this.menu.un("show", ml.show, this);
38942 this.menu.un("hide", ml.hide, this);
38946 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38947 onTriggerClick : function(){
38951 if(this.menu == null){
38952 this.menu = new Roo.menu.DateMenu();
38956 Roo.apply(this.menu.picker, {
38958 showClear: this.allowBlank,
38959 minDate : this.minValue,
38960 maxDate : this.maxValue,
38961 disabledDatesRE : this.ddMatch,
38962 disabledDatesText : this.disabledDatesText,
38964 format : this.useIso ? 'Y-m-d' : this.format,
38965 minText : String.format(this.minText, this.formatDate(this.minValue)),
38966 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38969 this.menu.on(Roo.apply({}, this.menuListeners, {
38977 // hide month picker get's called when we called by 'before hide';
38979 var ignorehide = true;
38980 p.hideMonthPicker = function(disableAnim){
38984 if(this.monthPicker){
38985 Roo.log("hideMonthPicker called");
38986 if(disableAnim === true){
38987 this.monthPicker.hide();
38989 this.monthPicker.slideOut('t', {duration:.2});
38990 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
38991 p.fireEvent("select", this, this.value);
38997 Roo.log('picker set value');
38998 Roo.log(this.getValue());
38999 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39000 m.show(this.el, 'tl-bl?');
39001 ignorehide = false;
39002 // this will trigger hideMonthPicker..
39005 // hidden the day picker
39006 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39012 p.showMonthPicker.defer(100, p);
39018 beforeBlur : function(){
39019 var v = this.parseDate(this.getRawValue());
39025 /** @cfg {Boolean} grow @hide */
39026 /** @cfg {Number} growMin @hide */
39027 /** @cfg {Number} growMax @hide */
39034 * Ext JS Library 1.1.1
39035 * Copyright(c) 2006-2007, Ext JS, LLC.
39037 * Originally Released Under LGPL - original licence link has changed is not relivant.
39040 * <script type="text/javascript">
39045 * @class Roo.form.ComboBox
39046 * @extends Roo.form.TriggerField
39047 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39049 * Create a new ComboBox.
39050 * @param {Object} config Configuration options
39052 Roo.form.ComboBox = function(config){
39053 Roo.form.ComboBox.superclass.constructor.call(this, config);
39057 * Fires when the dropdown list is expanded
39058 * @param {Roo.form.ComboBox} combo This combo box
39063 * Fires when the dropdown list is collapsed
39064 * @param {Roo.form.ComboBox} combo This combo box
39068 * @event beforeselect
39069 * Fires before a list item is selected. Return false to cancel the selection.
39070 * @param {Roo.form.ComboBox} combo This combo box
39071 * @param {Roo.data.Record} record The data record returned from the underlying store
39072 * @param {Number} index The index of the selected item in the dropdown list
39074 'beforeselect' : true,
39077 * Fires when a list item is selected
39078 * @param {Roo.form.ComboBox} combo This combo box
39079 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39080 * @param {Number} index The index of the selected item in the dropdown list
39084 * @event beforequery
39085 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39086 * The event object passed has these properties:
39087 * @param {Roo.form.ComboBox} combo This combo box
39088 * @param {String} query The query
39089 * @param {Boolean} forceAll true to force "all" query
39090 * @param {Boolean} cancel true to cancel the query
39091 * @param {Object} e The query event object
39093 'beforequery': true,
39096 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39097 * @param {Roo.form.ComboBox} combo This combo box
39102 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39103 * @param {Roo.form.ComboBox} combo This combo box
39104 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39110 if(this.transform){
39111 this.allowDomMove = false;
39112 var s = Roo.getDom(this.transform);
39113 if(!this.hiddenName){
39114 this.hiddenName = s.name;
39117 this.mode = 'local';
39118 var d = [], opts = s.options;
39119 for(var i = 0, len = opts.length;i < len; i++){
39121 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39123 this.value = value;
39125 d.push([value, o.text]);
39127 this.store = new Roo.data.SimpleStore({
39129 fields: ['value', 'text'],
39132 this.valueField = 'value';
39133 this.displayField = 'text';
39135 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39136 if(!this.lazyRender){
39137 this.target = true;
39138 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39139 s.parentNode.removeChild(s); // remove it
39140 this.render(this.el.parentNode);
39142 s.parentNode.removeChild(s); // remove it
39147 this.store = Roo.factory(this.store, Roo.data);
39150 this.selectedIndex = -1;
39151 if(this.mode == 'local'){
39152 if(config.queryDelay === undefined){
39153 this.queryDelay = 10;
39155 if(config.minChars === undefined){
39161 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39163 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39166 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39167 * rendering into an Roo.Editor, defaults to false)
39170 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39171 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39174 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39177 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39178 * the dropdown list (defaults to undefined, with no header element)
39182 * @cfg {String/Roo.Template} tpl The template to use to render the output
39186 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39188 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39190 listWidth: undefined,
39192 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39193 * mode = 'remote' or 'text' if mode = 'local')
39195 displayField: undefined,
39197 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39198 * mode = 'remote' or 'value' if mode = 'local').
39199 * Note: use of a valueField requires the user make a selection
39200 * in order for a value to be mapped.
39202 valueField: undefined,
39206 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39207 * field's data value (defaults to the underlying DOM element's name)
39209 hiddenName: undefined,
39211 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39215 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39217 selectedClass: 'x-combo-selected',
39219 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39220 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39221 * which displays a downward arrow icon).
39223 triggerClass : 'x-form-arrow-trigger',
39225 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39229 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39230 * anchor positions (defaults to 'tl-bl')
39232 listAlign: 'tl-bl?',
39234 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39238 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39239 * query specified by the allQuery config option (defaults to 'query')
39241 triggerAction: 'query',
39243 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39244 * (defaults to 4, does not apply if editable = false)
39248 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39249 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39253 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39254 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39258 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39259 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39263 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39264 * when editable = true (defaults to false)
39266 selectOnFocus:false,
39268 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39270 queryParam: 'query',
39272 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39273 * when mode = 'remote' (defaults to 'Loading...')
39275 loadingText: 'Loading...',
39277 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39281 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39285 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39286 * traditional select (defaults to true)
39290 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39294 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39298 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39299 * listWidth has a higher value)
39303 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39304 * allow the user to set arbitrary text into the field (defaults to false)
39306 forceSelection:false,
39308 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39309 * if typeAhead = true (defaults to 250)
39311 typeAheadDelay : 250,
39313 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39314 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39316 valueNotFoundText : undefined,
39318 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39320 blockFocus : false,
39323 * @cfg {Boolean} disableClear Disable showing of clear button.
39325 disableClear : false,
39327 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39329 alwaysQuery : false,
39335 // element that contains real text value.. (when hidden is used..)
39338 onRender : function(ct, position){
39339 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39340 if(this.hiddenName){
39341 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39343 this.hiddenField.value =
39344 this.hiddenValue !== undefined ? this.hiddenValue :
39345 this.value !== undefined ? this.value : '';
39347 // prevent input submission
39348 this.el.dom.removeAttribute('name');
39353 this.el.dom.setAttribute('autocomplete', 'off');
39356 var cls = 'x-combo-list';
39358 this.list = new Roo.Layer({
39359 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39362 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39363 this.list.setWidth(lw);
39364 this.list.swallowEvent('mousewheel');
39365 this.assetHeight = 0;
39368 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39369 this.assetHeight += this.header.getHeight();
39372 this.innerList = this.list.createChild({cls:cls+'-inner'});
39373 this.innerList.on('mouseover', this.onViewOver, this);
39374 this.innerList.on('mousemove', this.onViewMove, this);
39375 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39377 if(this.allowBlank && !this.pageSize && !this.disableClear){
39378 this.footer = this.list.createChild({cls:cls+'-ft'});
39379 this.pageTb = new Roo.Toolbar(this.footer);
39383 this.footer = this.list.createChild({cls:cls+'-ft'});
39384 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39385 {pageSize: this.pageSize});
39389 if (this.pageTb && this.allowBlank && !this.disableClear) {
39391 this.pageTb.add(new Roo.Toolbar.Fill(), {
39392 cls: 'x-btn-icon x-btn-clear',
39394 handler: function()
39397 _this.clearValue();
39398 _this.onSelect(false, -1);
39403 this.assetHeight += this.footer.getHeight();
39408 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39411 this.view = new Roo.View(this.innerList, this.tpl, {
39412 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39415 this.view.on('click', this.onViewClick, this);
39417 this.store.on('beforeload', this.onBeforeLoad, this);
39418 this.store.on('load', this.onLoad, this);
39419 this.store.on('loadexception', this.onLoadException, this);
39421 if(this.resizable){
39422 this.resizer = new Roo.Resizable(this.list, {
39423 pinned:true, handles:'se'
39425 this.resizer.on('resize', function(r, w, h){
39426 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39427 this.listWidth = w;
39428 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39429 this.restrictHeight();
39431 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39433 if(!this.editable){
39434 this.editable = true;
39435 this.setEditable(false);
39439 if (typeof(this.events.add.listeners) != 'undefined') {
39441 this.addicon = this.wrap.createChild(
39442 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39444 this.addicon.on('click', function(e) {
39445 this.fireEvent('add', this);
39448 if (typeof(this.events.edit.listeners) != 'undefined') {
39450 this.editicon = this.wrap.createChild(
39451 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39452 if (this.addicon) {
39453 this.editicon.setStyle('margin-left', '40px');
39455 this.editicon.on('click', function(e) {
39457 // we fire even if inothing is selected..
39458 this.fireEvent('edit', this, this.lastData );
39468 initEvents : function(){
39469 Roo.form.ComboBox.superclass.initEvents.call(this);
39471 this.keyNav = new Roo.KeyNav(this.el, {
39472 "up" : function(e){
39473 this.inKeyMode = true;
39477 "down" : function(e){
39478 if(!this.isExpanded()){
39479 this.onTriggerClick();
39481 this.inKeyMode = true;
39486 "enter" : function(e){
39487 this.onViewClick();
39491 "esc" : function(e){
39495 "tab" : function(e){
39496 this.onViewClick(false);
39497 this.fireEvent("specialkey", this, e);
39503 doRelay : function(foo, bar, hname){
39504 if(hname == 'down' || this.scope.isExpanded()){
39505 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39512 this.queryDelay = Math.max(this.queryDelay || 10,
39513 this.mode == 'local' ? 10 : 250);
39514 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39515 if(this.typeAhead){
39516 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39518 if(this.editable !== false){
39519 this.el.on("keyup", this.onKeyUp, this);
39521 if(this.forceSelection){
39522 this.on('blur', this.doForce, this);
39526 onDestroy : function(){
39528 this.view.setStore(null);
39529 this.view.el.removeAllListeners();
39530 this.view.el.remove();
39531 this.view.purgeListeners();
39534 this.list.destroy();
39537 this.store.un('beforeload', this.onBeforeLoad, this);
39538 this.store.un('load', this.onLoad, this);
39539 this.store.un('loadexception', this.onLoadException, this);
39541 Roo.form.ComboBox.superclass.onDestroy.call(this);
39545 fireKey : function(e){
39546 if(e.isNavKeyPress() && !this.list.isVisible()){
39547 this.fireEvent("specialkey", this, e);
39552 onResize: function(w, h){
39553 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39555 if(typeof w != 'number'){
39556 // we do not handle it!?!?
39559 var tw = this.trigger.getWidth();
39560 tw += this.addicon ? this.addicon.getWidth() : 0;
39561 tw += this.editicon ? this.editicon.getWidth() : 0;
39563 this.el.setWidth( this.adjustWidth('input', x));
39565 this.trigger.setStyle('left', x+'px');
39567 if(this.list && this.listWidth === undefined){
39568 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39569 this.list.setWidth(lw);
39570 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39578 * Allow or prevent the user from directly editing the field text. If false is passed,
39579 * the user will only be able to select from the items defined in the dropdown list. This method
39580 * is the runtime equivalent of setting the 'editable' config option at config time.
39581 * @param {Boolean} value True to allow the user to directly edit the field text
39583 setEditable : function(value){
39584 if(value == this.editable){
39587 this.editable = value;
39589 this.el.dom.setAttribute('readOnly', true);
39590 this.el.on('mousedown', this.onTriggerClick, this);
39591 this.el.addClass('x-combo-noedit');
39593 this.el.dom.setAttribute('readOnly', false);
39594 this.el.un('mousedown', this.onTriggerClick, this);
39595 this.el.removeClass('x-combo-noedit');
39600 onBeforeLoad : function(){
39601 if(!this.hasFocus){
39604 this.innerList.update(this.loadingText ?
39605 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39606 this.restrictHeight();
39607 this.selectedIndex = -1;
39611 onLoad : function(){
39612 if(!this.hasFocus){
39615 if(this.store.getCount() > 0){
39617 this.restrictHeight();
39618 if(this.lastQuery == this.allQuery){
39620 this.el.dom.select();
39622 if(!this.selectByValue(this.value, true)){
39623 this.select(0, true);
39627 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39628 this.taTask.delay(this.typeAheadDelay);
39632 this.onEmptyResults();
39637 onLoadException : function()
39640 Roo.log(this.store.reader.jsonData);
39641 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39642 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39648 onTypeAhead : function(){
39649 if(this.store.getCount() > 0){
39650 var r = this.store.getAt(0);
39651 var newValue = r.data[this.displayField];
39652 var len = newValue.length;
39653 var selStart = this.getRawValue().length;
39654 if(selStart != len){
39655 this.setRawValue(newValue);
39656 this.selectText(selStart, newValue.length);
39662 onSelect : function(record, index){
39663 if(this.fireEvent('beforeselect', this, record, index) !== false){
39664 this.setFromData(index > -1 ? record.data : false);
39666 this.fireEvent('select', this, record, index);
39671 * Returns the currently selected field value or empty string if no value is set.
39672 * @return {String} value The selected value
39674 getValue : function(){
39675 if(this.valueField){
39676 return typeof this.value != 'undefined' ? this.value : '';
39678 return Roo.form.ComboBox.superclass.getValue.call(this);
39683 * Clears any text/value currently set in the field
39685 clearValue : function(){
39686 if(this.hiddenField){
39687 this.hiddenField.value = '';
39690 this.setRawValue('');
39691 this.lastSelectionText = '';
39696 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39697 * will be displayed in the field. If the value does not match the data value of an existing item,
39698 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39699 * Otherwise the field will be blank (although the value will still be set).
39700 * @param {String} value The value to match
39702 setValue : function(v){
39704 if(this.valueField){
39705 var r = this.findRecord(this.valueField, v);
39707 text = r.data[this.displayField];
39708 }else if(this.valueNotFoundText !== undefined){
39709 text = this.valueNotFoundText;
39712 this.lastSelectionText = text;
39713 if(this.hiddenField){
39714 this.hiddenField.value = v;
39716 Roo.form.ComboBox.superclass.setValue.call(this, text);
39720 * @property {Object} the last set data for the element
39725 * Sets the value of the field based on a object which is related to the record format for the store.
39726 * @param {Object} value the value to set as. or false on reset?
39728 setFromData : function(o){
39729 var dv = ''; // display value
39730 var vv = ''; // value value..
39732 if (this.displayField) {
39733 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39735 // this is an error condition!!!
39736 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39739 if(this.valueField){
39740 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39742 if(this.hiddenField){
39743 this.hiddenField.value = vv;
39745 this.lastSelectionText = dv;
39746 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39750 // no hidden field.. - we store the value in 'value', but still display
39751 // display field!!!!
39752 this.lastSelectionText = dv;
39753 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39759 reset : function(){
39760 // overridden so that last data is reset..
39761 this.setValue(this.resetValue);
39762 this.clearInvalid();
39763 this.lastData = false;
39765 this.view.clearSelections();
39769 findRecord : function(prop, value){
39771 if(this.store.getCount() > 0){
39772 this.store.each(function(r){
39773 if(r.data[prop] == value){
39783 getName: function()
39785 // returns hidden if it's set..
39786 if (!this.rendered) {return ''};
39787 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39791 onViewMove : function(e, t){
39792 this.inKeyMode = false;
39796 onViewOver : function(e, t){
39797 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39800 var item = this.view.findItemFromChild(t);
39802 var index = this.view.indexOf(item);
39803 this.select(index, false);
39808 onViewClick : function(doFocus)
39810 var index = this.view.getSelectedIndexes()[0];
39811 var r = this.store.getAt(index);
39813 this.onSelect(r, index);
39815 if(doFocus !== false && !this.blockFocus){
39821 restrictHeight : function(){
39822 this.innerList.dom.style.height = '';
39823 var inner = this.innerList.dom;
39824 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39825 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39826 this.list.beginUpdate();
39827 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39828 this.list.alignTo(this.el, this.listAlign);
39829 this.list.endUpdate();
39833 onEmptyResults : function(){
39838 * Returns true if the dropdown list is expanded, else false.
39840 isExpanded : function(){
39841 return this.list.isVisible();
39845 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39846 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39847 * @param {String} value The data value of the item to select
39848 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39849 * selected item if it is not currently in view (defaults to true)
39850 * @return {Boolean} True if the value matched an item in the list, else false
39852 selectByValue : function(v, scrollIntoView){
39853 if(v !== undefined && v !== null){
39854 var r = this.findRecord(this.valueField || this.displayField, v);
39856 this.select(this.store.indexOf(r), scrollIntoView);
39864 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39865 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39866 * @param {Number} index The zero-based index of the list item to select
39867 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39868 * selected item if it is not currently in view (defaults to true)
39870 select : function(index, scrollIntoView){
39871 this.selectedIndex = index;
39872 this.view.select(index);
39873 if(scrollIntoView !== false){
39874 var el = this.view.getNode(index);
39876 this.innerList.scrollChildIntoView(el, false);
39882 selectNext : function(){
39883 var ct = this.store.getCount();
39885 if(this.selectedIndex == -1){
39887 }else if(this.selectedIndex < ct-1){
39888 this.select(this.selectedIndex+1);
39894 selectPrev : function(){
39895 var ct = this.store.getCount();
39897 if(this.selectedIndex == -1){
39899 }else if(this.selectedIndex != 0){
39900 this.select(this.selectedIndex-1);
39906 onKeyUp : function(e){
39907 if(this.editable !== false && !e.isSpecialKey()){
39908 this.lastKey = e.getKey();
39909 this.dqTask.delay(this.queryDelay);
39914 validateBlur : function(){
39915 return !this.list || !this.list.isVisible();
39919 initQuery : function(){
39920 this.doQuery(this.getRawValue());
39924 doForce : function(){
39925 if(this.el.dom.value.length > 0){
39926 this.el.dom.value =
39927 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39933 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39934 * query allowing the query action to be canceled if needed.
39935 * @param {String} query The SQL query to execute
39936 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39937 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39938 * saved in the current store (defaults to false)
39940 doQuery : function(q, forceAll){
39941 if(q === undefined || q === null){
39946 forceAll: forceAll,
39950 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39954 forceAll = qe.forceAll;
39955 if(forceAll === true || (q.length >= this.minChars)){
39956 if(this.lastQuery != q || this.alwaysQuery){
39957 this.lastQuery = q;
39958 if(this.mode == 'local'){
39959 this.selectedIndex = -1;
39961 this.store.clearFilter();
39963 this.store.filter(this.displayField, q);
39967 this.store.baseParams[this.queryParam] = q;
39969 params: this.getParams(q)
39974 this.selectedIndex = -1;
39981 getParams : function(q){
39983 //p[this.queryParam] = q;
39986 p.limit = this.pageSize;
39992 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
39994 collapse : function(){
39995 if(!this.isExpanded()){
39999 Roo.get(document).un('mousedown', this.collapseIf, this);
40000 Roo.get(document).un('mousewheel', this.collapseIf, this);
40001 if (!this.editable) {
40002 Roo.get(document).un('keydown', this.listKeyPress, this);
40004 this.fireEvent('collapse', this);
40008 collapseIf : function(e){
40009 if(!e.within(this.wrap) && !e.within(this.list)){
40015 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40017 expand : function(){
40018 if(this.isExpanded() || !this.hasFocus){
40021 this.list.alignTo(this.el, this.listAlign);
40023 Roo.get(document).on('mousedown', this.collapseIf, this);
40024 Roo.get(document).on('mousewheel', this.collapseIf, this);
40025 if (!this.editable) {
40026 Roo.get(document).on('keydown', this.listKeyPress, this);
40029 this.fireEvent('expand', this);
40033 // Implements the default empty TriggerField.onTriggerClick function
40034 onTriggerClick : function(){
40038 if(this.isExpanded()){
40040 if (!this.blockFocus) {
40045 this.hasFocus = true;
40046 if(this.triggerAction == 'all') {
40047 this.doQuery(this.allQuery, true);
40049 this.doQuery(this.getRawValue());
40051 if (!this.blockFocus) {
40056 listKeyPress : function(e)
40058 //Roo.log('listkeypress');
40059 // scroll to first matching element based on key pres..
40060 if (e.isSpecialKey()) {
40063 var k = String.fromCharCode(e.getKey()).toUpperCase();
40066 var csel = this.view.getSelectedNodes();
40067 var cselitem = false;
40069 var ix = this.view.indexOf(csel[0]);
40070 cselitem = this.store.getAt(ix);
40071 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40077 this.store.each(function(v) {
40079 // start at existing selection.
40080 if (cselitem.id == v.id) {
40086 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40087 match = this.store.indexOf(v);
40092 if (match === false) {
40093 return true; // no more action?
40096 this.view.select(match);
40097 var sn = Roo.get(this.view.getSelectedNodes()[0])
40098 sn.scrollIntoView(sn.dom.parentNode, false);
40102 * @cfg {Boolean} grow
40106 * @cfg {Number} growMin
40110 * @cfg {Number} growMax
40118 * Copyright(c) 2010-2012, Roo J Solutions Limited
40125 * @class Roo.form.ComboBoxArray
40126 * @extends Roo.form.TextField
40127 * A facebook style adder... for lists of email / people / countries etc...
40128 * pick multiple items from a combo box, and shows each one.
40130 * Fred [x] Brian [x] [Pick another |v]
40133 * For this to work: it needs various extra information
40134 * - normal combo problay has
40136 * + displayField, valueField
40138 * For our purpose...
40141 * If we change from 'extends' to wrapping...
40148 * Create a new ComboBoxArray.
40149 * @param {Object} config Configuration options
40153 Roo.form.ComboBoxArray = function(config)
40156 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40158 this.items = new Roo.util.MixedCollection(false);
40160 // construct the child combo...
40170 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40173 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40178 // behavies liek a hiddne field
40179 inputType: 'hidden',
40181 * @cfg {Number} width The width of the box that displays the selected element
40188 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40192 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40194 hiddenName : false,
40197 // private the array of items that are displayed..
40199 // private - the hidden field el.
40201 // private - the filed el..
40204 //validateValue : function() { return true; }, // all values are ok!
40205 //onAddClick: function() { },
40207 onRender : function(ct, position)
40210 // create the standard hidden element
40211 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40214 // give fake names to child combo;
40215 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40216 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40218 this.combo = Roo.factory(this.combo, Roo.form);
40219 this.combo.onRender(ct, position);
40220 if (typeof(this.combo.width) != 'undefined') {
40221 this.combo.onResize(this.combo.width,0);
40224 this.combo.initEvents();
40226 // assigned so form know we need to do this..
40227 this.store = this.combo.store;
40228 this.valueField = this.combo.valueField;
40229 this.displayField = this.combo.displayField ;
40232 this.combo.wrap.addClass('x-cbarray-grp');
40234 var cbwrap = this.combo.wrap.createChild(
40235 {tag: 'div', cls: 'x-cbarray-cb'},
40240 this.hiddenEl = this.combo.wrap.createChild({
40241 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40243 this.el = this.combo.wrap.createChild({
40244 tag: 'input', type:'hidden' , name: this.name, value : ''
40246 // this.el.dom.removeAttribute("name");
40249 this.outerWrap = this.combo.wrap;
40250 this.wrap = cbwrap;
40252 this.outerWrap.setWidth(this.width);
40253 this.outerWrap.dom.removeChild(this.el.dom);
40255 this.wrap.dom.appendChild(this.el.dom);
40256 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40257 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40259 this.combo.trigger.setStyle('position','relative');
40260 this.combo.trigger.setStyle('left', '0px');
40261 this.combo.trigger.setStyle('top', '2px');
40263 this.combo.el.setStyle('vertical-align', 'text-bottom');
40265 //this.trigger.setStyle('vertical-align', 'top');
40267 // this should use the code from combo really... on('add' ....)
40271 this.adder = this.outerWrap.createChild(
40272 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40274 this.adder.on('click', function(e) {
40275 _t.fireEvent('adderclick', this, e);
40279 //this.adder.on('click', this.onAddClick, _t);
40282 this.combo.on('select', function(cb, rec, ix) {
40283 this.addItem(rec.data);
40286 cb.el.dom.value = '';
40287 //cb.lastData = rec.data;
40296 getName: function()
40298 // returns hidden if it's set..
40299 if (!this.rendered) {return ''};
40300 return this.hiddenName ? this.hiddenName : this.name;
40305 onResize: function(w, h){
40308 // not sure if this is needed..
40309 //this.combo.onResize(w,h);
40311 if(typeof w != 'number'){
40312 // we do not handle it!?!?
40315 var tw = this.combo.trigger.getWidth();
40316 tw += this.addicon ? this.addicon.getWidth() : 0;
40317 tw += this.editicon ? this.editicon.getWidth() : 0;
40319 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40321 this.combo.trigger.setStyle('left', '0px');
40323 if(this.list && this.listWidth === undefined){
40324 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40325 this.list.setWidth(lw);
40326 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40333 addItem: function(rec)
40335 var valueField = this.combo.valueField;
40336 var displayField = this.combo.displayField;
40337 if (this.items.indexOfKey(rec[valueField]) > -1) {
40338 //console.log("GOT " + rec.data.id);
40342 var x = new Roo.form.ComboBoxArray.Item({
40343 //id : rec[this.idField],
40345 displayField : displayField ,
40346 tipField : displayField ,
40350 this.items.add(rec[valueField],x);
40351 // add it before the element..
40352 this.updateHiddenEl();
40353 x.render(this.outerWrap, this.wrap.dom);
40354 // add the image handler..
40357 updateHiddenEl : function()
40360 if (!this.hiddenEl) {
40364 var idField = this.combo.valueField;
40366 this.items.each(function(f) {
40367 ar.push(f.data[idField]);
40370 this.hiddenEl.dom.value = ar.join(',');
40376 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40377 this.items.each(function(f) {
40380 this.el.dom.value = '';
40381 if (this.hiddenEl) {
40382 this.hiddenEl.dom.value = '';
40386 getValue: function()
40388 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40390 setValue: function(v) // not a valid action - must use addItems..
40397 if (this.store.isLocal && (typeof(v) == 'string')) {
40398 // then we can use the store to find the values..
40399 // comma seperated at present.. this needs to allow JSON based encoding..
40400 this.hiddenEl.value = v;
40402 Roo.each(v.split(','), function(k) {
40403 Roo.log("CHECK " + this.valueField + ',' + k);
40404 var li = this.store.query(this.valueField, k);
40409 add[this.valueField] = k;
40410 add[this.displayField] = li.item(0).data[this.displayField];
40416 if (typeof(v) == 'object') {
40417 // then let's assume it's an array of objects..
40418 Roo.each(v, function(l) {
40426 setFromData: function(v)
40428 // this recieves an object, if setValues is called.
40430 this.el.dom.value = v[this.displayField];
40431 this.hiddenEl.dom.value = v[this.valueField];
40432 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40435 var kv = v[this.valueField];
40436 var dv = v[this.displayField];
40437 kv = typeof(kv) != 'string' ? '' : kv;
40438 dv = typeof(dv) != 'string' ? '' : dv;
40441 var keys = kv.split(',');
40442 var display = dv.split(',');
40443 for (var i = 0 ; i < keys.length; i++) {
40446 add[this.valueField] = keys[i];
40447 add[this.displayField] = display[i];
40455 * Validates the combox array value
40456 * @return {Boolean} True if the value is valid, else false
40458 validate : function(){
40459 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40460 this.clearInvalid();
40466 validateValue : function(value){
40467 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40475 isDirty : function() {
40476 if(this.disabled) {
40481 var d = Roo.decode(String(this.originalValue));
40483 return String(this.getValue()) !== String(this.originalValue);
40486 var originalValue = [];
40488 for (var i = 0; i < d.length; i++){
40489 originalValue.push(d[i][this.valueField]);
40492 return String(this.getValue()) !== String(originalValue.join(','));
40501 * @class Roo.form.ComboBoxArray.Item
40502 * @extends Roo.BoxComponent
40503 * A selected item in the list
40504 * Fred [x] Brian [x] [Pick another |v]
40507 * Create a new item.
40508 * @param {Object} config Configuration options
40511 Roo.form.ComboBoxArray.Item = function(config) {
40512 config.id = Roo.id();
40513 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40516 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40519 displayField : false,
40523 defaultAutoCreate : {
40525 cls: 'x-cbarray-item',
40532 src : Roo.BLANK_IMAGE_URL ,
40540 onRender : function(ct, position)
40542 Roo.form.Field.superclass.onRender.call(this, ct, position);
40545 var cfg = this.getAutoCreate();
40546 this.el = ct.createChild(cfg, position);
40549 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40551 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40552 this.cb.renderer(this.data) :
40553 String.format('{0}',this.data[this.displayField]);
40556 this.el.child('div').dom.setAttribute('qtip',
40557 String.format('{0}',this.data[this.tipField])
40560 this.el.child('img').on('click', this.remove, this);
40564 remove : function()
40567 this.cb.items.remove(this);
40568 this.el.child('img').un('click', this.remove, this);
40570 this.cb.updateHiddenEl();
40574 * Ext JS Library 1.1.1
40575 * Copyright(c) 2006-2007, Ext JS, LLC.
40577 * Originally Released Under LGPL - original licence link has changed is not relivant.
40580 * <script type="text/javascript">
40583 * @class Roo.form.Checkbox
40584 * @extends Roo.form.Field
40585 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40587 * Creates a new Checkbox
40588 * @param {Object} config Configuration options
40590 Roo.form.Checkbox = function(config){
40591 Roo.form.Checkbox.superclass.constructor.call(this, config);
40595 * Fires when the checkbox is checked or unchecked.
40596 * @param {Roo.form.Checkbox} this This checkbox
40597 * @param {Boolean} checked The new checked value
40603 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40605 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40607 focusClass : undefined,
40609 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40611 fieldClass: "x-form-field",
40613 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40617 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40618 * {tag: "input", type: "checkbox", autocomplete: "off"})
40620 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40622 * @cfg {String} boxLabel The text that appears beside the checkbox
40626 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40630 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40632 valueOff: '0', // value when not checked..
40634 actionMode : 'viewEl',
40637 itemCls : 'x-menu-check-item x-form-item',
40638 groupClass : 'x-menu-group-item',
40639 inputType : 'hidden',
40642 inSetChecked: false, // check that we are not calling self...
40644 inputElement: false, // real input element?
40645 basedOn: false, // ????
40647 isFormField: true, // not sure where this is needed!!!!
40649 onResize : function(){
40650 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40651 if(!this.boxLabel){
40652 this.el.alignTo(this.wrap, 'c-c');
40656 initEvents : function(){
40657 Roo.form.Checkbox.superclass.initEvents.call(this);
40658 this.el.on("click", this.onClick, this);
40659 this.el.on("change", this.onClick, this);
40663 getResizeEl : function(){
40667 getPositionEl : function(){
40672 onRender : function(ct, position){
40673 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40675 if(this.inputValue !== undefined){
40676 this.el.dom.value = this.inputValue;
40679 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40680 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40681 var viewEl = this.wrap.createChild({
40682 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40683 this.viewEl = viewEl;
40684 this.wrap.on('click', this.onClick, this);
40686 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40687 this.el.on('propertychange', this.setFromHidden, this); //ie
40692 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40693 // viewEl.on('click', this.onClick, this);
40695 //if(this.checked){
40696 this.setChecked(this.checked);
40698 //this.checked = this.el.dom;
40704 initValue : Roo.emptyFn,
40707 * Returns the checked state of the checkbox.
40708 * @return {Boolean} True if checked, else false
40710 getValue : function(){
40712 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40714 return this.valueOff;
40719 onClick : function(){
40720 this.setChecked(!this.checked);
40722 //if(this.el.dom.checked != this.checked){
40723 // this.setValue(this.el.dom.checked);
40728 * Sets the checked state of the checkbox.
40729 * On is always based on a string comparison between inputValue and the param.
40730 * @param {Boolean/String} value - the value to set
40731 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40733 setValue : function(v,suppressEvent){
40736 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40737 //if(this.el && this.el.dom){
40738 // this.el.dom.checked = this.checked;
40739 // this.el.dom.defaultChecked = this.checked;
40741 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40742 //this.fireEvent("check", this, this.checked);
40745 setChecked : function(state,suppressEvent)
40747 if (this.inSetChecked) {
40748 this.checked = state;
40754 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40756 this.checked = state;
40757 if(suppressEvent !== true){
40758 this.fireEvent('check', this, state);
40760 this.inSetChecked = true;
40761 this.el.dom.value = state ? this.inputValue : this.valueOff;
40762 this.inSetChecked = false;
40765 // handle setting of hidden value by some other method!!?!?
40766 setFromHidden: function()
40771 //console.log("SET FROM HIDDEN");
40772 //alert('setFrom hidden');
40773 this.setValue(this.el.dom.value);
40776 onDestroy : function()
40779 Roo.get(this.viewEl).remove();
40782 Roo.form.Checkbox.superclass.onDestroy.call(this);
40787 * Ext JS Library 1.1.1
40788 * Copyright(c) 2006-2007, Ext JS, LLC.
40790 * Originally Released Under LGPL - original licence link has changed is not relivant.
40793 * <script type="text/javascript">
40797 * @class Roo.form.Radio
40798 * @extends Roo.form.Checkbox
40799 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40800 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40802 * Creates a new Radio
40803 * @param {Object} config Configuration options
40805 Roo.form.Radio = function(){
40806 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40808 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40809 inputType: 'radio',
40812 * If this radio is part of a group, it will return the selected value
40815 getGroupValue : function(){
40816 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40820 onRender : function(ct, position){
40821 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40823 if(this.inputValue !== undefined){
40824 this.el.dom.value = this.inputValue;
40827 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40828 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40829 //var viewEl = this.wrap.createChild({
40830 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40831 //this.viewEl = viewEl;
40832 //this.wrap.on('click', this.onClick, this);
40834 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40835 //this.el.on('propertychange', this.setFromHidden, this); //ie
40840 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40841 // viewEl.on('click', this.onClick, this);
40844 this.el.dom.checked = 'checked' ;
40850 });//<script type="text/javascript">
40853 * Based Ext JS Library 1.1.1
40854 * Copyright(c) 2006-2007, Ext JS, LLC.
40860 * @class Roo.HtmlEditorCore
40861 * @extends Roo.Component
40862 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
40864 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40867 Roo.HtmlEditorCore = function(config){
40870 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
40873 * @event initialize
40874 * Fires when the editor is fully initialized (including the iframe)
40875 * @param {Roo.HtmlEditorCore} this
40880 * Fires when the editor is first receives the focus. Any insertion must wait
40881 * until after this event.
40882 * @param {Roo.HtmlEditorCore} this
40886 * @event beforesync
40887 * Fires before the textarea is updated with content from the editor iframe. Return false
40888 * to cancel the sync.
40889 * @param {Roo.HtmlEditorCore} this
40890 * @param {String} html
40894 * @event beforepush
40895 * Fires before the iframe editor is updated with content from the textarea. Return false
40896 * to cancel the push.
40897 * @param {Roo.HtmlEditorCore} this
40898 * @param {String} html
40903 * Fires when the textarea is updated with content from the editor iframe.
40904 * @param {Roo.HtmlEditorCore} this
40905 * @param {String} html
40910 * Fires when the iframe editor is updated with content from the textarea.
40911 * @param {Roo.HtmlEditorCore} this
40912 * @param {String} html
40917 * @event editorevent
40918 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40919 * @param {Roo.HtmlEditorCore} this
40927 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
40931 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
40937 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40942 * @cfg {Number} height (in pixels)
40946 * @cfg {Number} width (in pixels)
40951 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
40954 stylesheets: false,
40959 // private properties
40960 validationEvent : false,
40962 initialized : false,
40964 sourceEditMode : false,
40965 onFocus : Roo.emptyFn,
40967 hideMode:'offsets',
40973 * Protected method that will not generally be called directly. It
40974 * is called when the editor initializes the iframe with HTML contents. Override this method if you
40975 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
40977 getDocMarkup : function(){
40980 Roo.log(this.stylesheets);
40982 // inherit styels from page...??
40983 if (this.stylesheets === false) {
40985 Roo.get(document.head).select('style').each(function(node) {
40986 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40989 Roo.get(document.head).select('link').each(function(node) {
40990 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
40993 } else if (!this.stylesheets.length) {
40995 st = '<style type="text/css">' +
40996 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
40999 Roo.each(this.stylesheets, function(s) {
41000 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41005 st += '<style type="text/css">' +
41006 'IMG { cursor: pointer } ' +
41010 return '<html><head>' + st +
41011 //<style type="text/css">' +
41012 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41014 ' </head><body class="roo-htmleditor-body"></body></html>';
41018 onRender : function(ct, position)
41021 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41022 this.el = this.owner.el;
41025 this.el.dom.style.border = '0 none';
41026 this.el.dom.setAttribute('tabIndex', -1);
41027 this.el.addClass('x-hidden');
41031 if(Roo.isIE){ // fix IE 1px bogus margin
41032 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41036 this.frameId = Roo.id();
41040 var iframe = this.owner.wrap.createChild({
41043 name: this.frameId,
41044 frameBorder : 'no',
41045 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41050 this.iframe = iframe.dom;
41052 this.assignDocWin();
41054 this.doc.designMode = 'on';
41057 this.doc.write(this.getDocMarkup());
41061 var task = { // must defer to wait for browser to be ready
41063 //console.log("run task?" + this.doc.readyState);
41064 this.assignDocWin();
41065 if(this.doc.body || this.doc.readyState == 'complete'){
41067 this.doc.designMode="on";
41071 Roo.TaskMgr.stop(task);
41072 this.initEditor.defer(10, this);
41079 Roo.TaskMgr.start(task);
41086 onResize : function(w, h)
41088 //Roo.log('resize: ' +w + ',' + h );
41089 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41093 if(typeof w == 'number'){
41095 this.iframe.style.width = w + 'px';
41097 if(typeof h == 'number'){
41099 this.iframe.style.height = h + 'px';
41101 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41108 * Toggles the editor between standard and source edit mode.
41109 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41111 toggleSourceEdit : function(sourceEditMode){
41113 this.sourceEditMode = sourceEditMode === true;
41115 if(this.sourceEditMode){
41117 this.iframe.className = 'x-hidden'; //FIXME - what's the BS styles for these
41121 this.iframe.className = '';
41124 //this.setSize(this.owner.wrap.getSize());
41125 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41132 * Protected method that will not generally be called directly. If you need/want
41133 * custom HTML cleanup, this is the method you should override.
41134 * @param {String} html The HTML to be cleaned
41135 * return {String} The cleaned HTML
41137 cleanHtml : function(html){
41138 html = String(html);
41139 if(html.length > 5){
41140 if(Roo.isSafari){ // strip safari nonsense
41141 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41144 if(html == ' '){
41151 * HTML Editor -> Textarea
41152 * Protected method that will not generally be called directly. Syncs the contents
41153 * of the editor iframe with the textarea.
41155 syncValue : function(){
41156 if(this.initialized){
41157 var bd = (this.doc.body || this.doc.documentElement);
41158 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41159 var html = bd.innerHTML;
41161 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41162 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41164 html = '<div style="'+m[0]+'">' + html + '</div>';
41167 html = this.cleanHtml(html);
41168 // fix up the special chars.. normaly like back quotes in word...
41169 // however we do not want to do this with chinese..
41170 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41171 var cc = b.charCodeAt();
41173 (cc >= 0x4E00 && cc < 0xA000 ) ||
41174 (cc >= 0x3400 && cc < 0x4E00 ) ||
41175 (cc >= 0xf900 && cc < 0xfb00 )
41181 if(this.owner.fireEvent('beforesync', this, html) !== false){
41182 this.el.dom.value = html;
41183 this.owner.fireEvent('sync', this, html);
41189 * Protected method that will not generally be called directly. Pushes the value of the textarea
41190 * into the iframe editor.
41192 pushValue : function(){
41193 if(this.initialized){
41194 var v = this.el.dom.value;
41200 if(this.owner.fireEvent('beforepush', this, v) !== false){
41201 var d = (this.doc.body || this.doc.documentElement);
41203 this.cleanUpPaste();
41204 this.el.dom.value = d.innerHTML;
41205 this.owner.fireEvent('push', this, v);
41211 deferFocus : function(){
41212 this.focus.defer(10, this);
41216 focus : function(){
41217 if(this.win && !this.sourceEditMode){
41224 assignDocWin: function()
41226 var iframe = this.iframe;
41229 this.doc = iframe.contentWindow.document;
41230 this.win = iframe.contentWindow;
41232 if (!Roo.get(this.frameId)) {
41235 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41236 this.win = Roo.get(this.frameId).dom.contentWindow;
41241 initEditor : function(){
41242 //console.log("INIT EDITOR");
41243 this.assignDocWin();
41247 this.doc.designMode="on";
41249 this.doc.write(this.getDocMarkup());
41252 var dbody = (this.doc.body || this.doc.documentElement);
41253 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41254 // this copies styles from the containing element into thsi one..
41255 // not sure why we need all of this..
41256 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41257 ss['background-attachment'] = 'fixed'; // w3c
41258 dbody.bgProperties = 'fixed'; // ie
41259 Roo.DomHelper.applyStyles(dbody, ss);
41260 Roo.EventManager.on(this.doc, {
41261 //'mousedown': this.onEditorEvent,
41262 'mouseup': this.onEditorEvent,
41263 'dblclick': this.onEditorEvent,
41264 'click': this.onEditorEvent,
41265 'keyup': this.onEditorEvent,
41270 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41272 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41273 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41275 this.initialized = true;
41277 this.owner.fireEvent('initialize', this);
41282 onDestroy : function(){
41288 //for (var i =0; i < this.toolbars.length;i++) {
41289 // // fixme - ask toolbars for heights?
41290 // this.toolbars[i].onDestroy();
41293 //this.wrap.dom.innerHTML = '';
41294 //this.wrap.remove();
41299 onFirstFocus : function(){
41301 this.assignDocWin();
41304 this.activated = true;
41307 if(Roo.isGecko){ // prevent silly gecko errors
41309 var s = this.win.getSelection();
41310 if(!s.focusNode || s.focusNode.nodeType != 3){
41311 var r = s.getRangeAt(0);
41312 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41317 this.execCmd('useCSS', true);
41318 this.execCmd('styleWithCSS', false);
41321 this.owner.fireEvent('activate', this);
41325 adjustFont: function(btn){
41326 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41327 //if(Roo.isSafari){ // safari
41330 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41331 if(Roo.isSafari){ // safari
41332 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41333 v = (v < 10) ? 10 : v;
41334 v = (v > 48) ? 48 : v;
41335 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41340 v = Math.max(1, v+adjust);
41342 this.execCmd('FontSize', v );
41345 onEditorEvent : function(e){
41346 this.owner.fireEvent('editorevent', this, e);
41347 // this.updateToolbar();
41348 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41351 insertTag : function(tg)
41353 // could be a bit smarter... -> wrap the current selected tRoo..
41354 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41356 range = this.createRange(this.getSelection());
41357 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41358 wrappingNode.appendChild(range.extractContents());
41359 range.insertNode(wrappingNode);
41366 this.execCmd("formatblock", tg);
41370 insertText : function(txt)
41374 var range = this.createRange();
41375 range.deleteContents();
41376 //alert(Sender.getAttribute('label'));
41378 range.insertNode(this.doc.createTextNode(txt));
41384 * Executes a Midas editor command on the editor document and performs necessary focus and
41385 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41386 * @param {String} cmd The Midas command
41387 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41389 relayCmd : function(cmd, value){
41391 this.execCmd(cmd, value);
41392 this.owner.fireEvent('editorevent', this);
41393 //this.updateToolbar();
41394 this.owner.deferFocus();
41398 * Executes a Midas editor command directly on the editor document.
41399 * For visual commands, you should use {@link #relayCmd} instead.
41400 * <b>This should only be called after the editor is initialized.</b>
41401 * @param {String} cmd The Midas command
41402 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41404 execCmd : function(cmd, value){
41405 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41412 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41414 * @param {String} text | dom node..
41416 insertAtCursor : function(text)
41421 if(!this.activated){
41427 var r = this.doc.selection.createRange();
41438 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41442 // from jquery ui (MIT licenced)
41444 var win = this.win;
41446 if (win.getSelection && win.getSelection().getRangeAt) {
41447 range = win.getSelection().getRangeAt(0);
41448 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41449 range.insertNode(node);
41450 } else if (win.document.selection && win.document.selection.createRange) {
41451 // no firefox support
41452 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41453 win.document.selection.createRange().pasteHTML(txt);
41455 // no firefox support
41456 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41457 this.execCmd('InsertHTML', txt);
41466 mozKeyPress : function(e){
41468 var c = e.getCharCode(), cmd;
41471 c = String.fromCharCode(c).toLowerCase();
41485 this.cleanUpPaste.defer(100, this);
41493 e.preventDefault();
41501 fixKeys : function(){ // load time branching for fastest keydown performance
41503 return function(e){
41504 var k = e.getKey(), r;
41507 r = this.doc.selection.createRange();
41510 r.pasteHTML('    ');
41517 r = this.doc.selection.createRange();
41519 var target = r.parentElement();
41520 if(!target || target.tagName.toLowerCase() != 'li'){
41522 r.pasteHTML('<br />');
41528 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41529 this.cleanUpPaste.defer(100, this);
41535 }else if(Roo.isOpera){
41536 return function(e){
41537 var k = e.getKey();
41541 this.execCmd('InsertHTML','    ');
41544 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41545 this.cleanUpPaste.defer(100, this);
41550 }else if(Roo.isSafari){
41551 return function(e){
41552 var k = e.getKey();
41556 this.execCmd('InsertText','\t');
41560 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41561 this.cleanUpPaste.defer(100, this);
41569 getAllAncestors: function()
41571 var p = this.getSelectedNode();
41574 a.push(p); // push blank onto stack..
41575 p = this.getParentElement();
41579 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41583 a.push(this.doc.body);
41587 lastSelNode : false,
41590 getSelection : function()
41592 this.assignDocWin();
41593 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41596 getSelectedNode: function()
41598 // this may only work on Gecko!!!
41600 // should we cache this!!!!
41605 var range = this.createRange(this.getSelection()).cloneRange();
41608 var parent = range.parentElement();
41610 var testRange = range.duplicate();
41611 testRange.moveToElementText(parent);
41612 if (testRange.inRange(range)) {
41615 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41618 parent = parent.parentElement;
41623 // is ancestor a text element.
41624 var ac = range.commonAncestorContainer;
41625 if (ac.nodeType == 3) {
41626 ac = ac.parentNode;
41629 var ar = ac.childNodes;
41632 var other_nodes = [];
41633 var has_other_nodes = false;
41634 for (var i=0;i<ar.length;i++) {
41635 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41638 // fullly contained node.
41640 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41645 // probably selected..
41646 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41647 other_nodes.push(ar[i]);
41651 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41656 has_other_nodes = true;
41658 if (!nodes.length && other_nodes.length) {
41659 nodes= other_nodes;
41661 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41667 createRange: function(sel)
41669 // this has strange effects when using with
41670 // top toolbar - not sure if it's a great idea.
41671 //this.editor.contentWindow.focus();
41672 if (typeof sel != "undefined") {
41674 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41676 return this.doc.createRange();
41679 return this.doc.createRange();
41682 getParentElement: function()
41685 this.assignDocWin();
41686 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41688 var range = this.createRange(sel);
41691 var p = range.commonAncestorContainer;
41692 while (p.nodeType == 3) { // text node
41703 * Range intersection.. the hard stuff...
41707 * [ -- selected range --- ]
41711 * if end is before start or hits it. fail.
41712 * if start is after end or hits it fail.
41714 * if either hits (but other is outside. - then it's not
41720 // @see http://www.thismuchiknow.co.uk/?p=64.
41721 rangeIntersectsNode : function(range, node)
41723 var nodeRange = node.ownerDocument.createRange();
41725 nodeRange.selectNode(node);
41727 nodeRange.selectNodeContents(node);
41730 var rangeStartRange = range.cloneRange();
41731 rangeStartRange.collapse(true);
41733 var rangeEndRange = range.cloneRange();
41734 rangeEndRange.collapse(false);
41736 var nodeStartRange = nodeRange.cloneRange();
41737 nodeStartRange.collapse(true);
41739 var nodeEndRange = nodeRange.cloneRange();
41740 nodeEndRange.collapse(false);
41742 return rangeStartRange.compareBoundaryPoints(
41743 Range.START_TO_START, nodeEndRange) == -1 &&
41744 rangeEndRange.compareBoundaryPoints(
41745 Range.START_TO_START, nodeStartRange) == 1;
41749 rangeCompareNode : function(range, node)
41751 var nodeRange = node.ownerDocument.createRange();
41753 nodeRange.selectNode(node);
41755 nodeRange.selectNodeContents(node);
41759 range.collapse(true);
41761 nodeRange.collapse(true);
41763 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41764 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41766 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41768 var nodeIsBefore = ss == 1;
41769 var nodeIsAfter = ee == -1;
41771 if (nodeIsBefore && nodeIsAfter)
41773 if (!nodeIsBefore && nodeIsAfter)
41774 return 1; //right trailed.
41776 if (nodeIsBefore && !nodeIsAfter)
41777 return 2; // left trailed.
41782 // private? - in a new class?
41783 cleanUpPaste : function()
41785 // cleans up the whole document..
41786 Roo.log('cleanuppaste');
41787 this.cleanUpChildren(this.doc.body);
41788 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41789 if (clean != this.doc.body.innerHTML) {
41790 this.doc.body.innerHTML = clean;
41795 cleanWordChars : function(input) {// change the chars to hex code
41796 var he = Roo.HtmlEditorCore;
41798 var output = input;
41799 Roo.each(he.swapCodes, function(sw) {
41800 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41802 output = output.replace(swapper, sw[1]);
41809 cleanUpChildren : function (n)
41811 if (!n.childNodes.length) {
41814 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41815 this.cleanUpChild(n.childNodes[i]);
41822 cleanUpChild : function (node)
41825 //console.log(node);
41826 if (node.nodeName == "#text") {
41827 // clean up silly Windows -- stuff?
41830 if (node.nodeName == "#comment") {
41831 node.parentNode.removeChild(node);
41832 // clean up silly Windows -- stuff?
41836 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1) {
41838 node.parentNode.removeChild(node);
41843 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41845 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41846 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41848 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41849 // remove_keep_children = true;
41852 if (remove_keep_children) {
41853 this.cleanUpChildren(node);
41854 // inserts everything just before this node...
41855 while (node.childNodes.length) {
41856 var cn = node.childNodes[0];
41857 node.removeChild(cn);
41858 node.parentNode.insertBefore(cn, node);
41860 node.parentNode.removeChild(node);
41864 if (!node.attributes || !node.attributes.length) {
41865 this.cleanUpChildren(node);
41869 function cleanAttr(n,v)
41872 if (v.match(/^\./) || v.match(/^\//)) {
41875 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41878 if (v.match(/^#/)) {
41881 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41882 node.removeAttribute(n);
41886 function cleanStyle(n,v)
41888 if (v.match(/expression/)) { //XSS?? should we even bother..
41889 node.removeAttribute(n);
41892 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
41893 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
41896 var parts = v.split(/;/);
41899 Roo.each(parts, function(p) {
41900 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41904 var l = p.split(':').shift().replace(/\s+/g,'');
41905 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41908 if ( cblack.indexOf(l) > -1) {
41909 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41910 //node.removeAttribute(n);
41914 // only allow 'c whitelisted system attributes'
41915 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41916 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41917 //node.removeAttribute(n);
41927 if (clean.length) {
41928 node.setAttribute(n, clean.join(';'));
41930 node.removeAttribute(n);
41936 for (var i = node.attributes.length-1; i > -1 ; i--) {
41937 var a = node.attributes[i];
41940 if (a.name.toLowerCase().substr(0,2)=='on') {
41941 node.removeAttribute(a.name);
41944 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
41945 node.removeAttribute(a.name);
41948 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
41949 cleanAttr(a.name,a.value); // fixme..
41952 if (a.name == 'style') {
41953 cleanStyle(a.name,a.value);
41956 /// clean up MS crap..
41957 // tecnically this should be a list of valid class'es..
41960 if (a.name == 'class') {
41961 if (a.value.match(/^Mso/)) {
41962 node.className = '';
41965 if (a.value.match(/body/)) {
41966 node.className = '';
41977 this.cleanUpChildren(node);
41983 // hide stuff that is not compatible
41997 * @event specialkey
42001 * @cfg {String} fieldClass @hide
42004 * @cfg {String} focusClass @hide
42007 * @cfg {String} autoCreate @hide
42010 * @cfg {String} inputType @hide
42013 * @cfg {String} invalidClass @hide
42016 * @cfg {String} invalidText @hide
42019 * @cfg {String} msgFx @hide
42022 * @cfg {String} validateOnBlur @hide
42026 Roo.HtmlEditorCore.white = [
42027 'area', 'br', 'img', 'input', 'hr', 'wbr',
42029 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42030 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42031 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42032 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42033 'table', 'ul', 'xmp',
42035 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42038 'dir', 'menu', 'ol', 'ul', 'dl',
42044 Roo.HtmlEditorCore.black = [
42045 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42047 'base', 'basefont', 'bgsound', 'blink', 'body',
42048 'frame', 'frameset', 'head', 'html', 'ilayer',
42049 'iframe', 'layer', 'link', 'meta', 'object',
42050 'script', 'style' ,'title', 'xml' // clean later..
42052 Roo.HtmlEditorCore.clean = [
42053 'script', 'style', 'title', 'xml'
42055 Roo.HtmlEditorCore.remove = [
42060 Roo.HtmlEditorCore.ablack = [
42064 Roo.HtmlEditorCore.aclean = [
42065 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42069 Roo.HtmlEditorCore.pwhite= [
42070 'http', 'https', 'mailto'
42073 // white listed style attributes.
42074 Roo.HtmlEditorCore.cwhite= [
42075 // 'text-align', /// default is to allow most things..
42081 // black listed style attributes.
42082 Roo.HtmlEditorCore.cblack= [
42083 // 'font-size' -- this can be set by the project
42087 Roo.HtmlEditorCore.swapCodes =[
42098 //<script type="text/javascript">
42101 * Ext JS Library 1.1.1
42102 * Copyright(c) 2006-2007, Ext JS, LLC.
42108 Roo.form.HtmlEditor = function(config){
42112 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42114 if (!this.toolbars) {
42115 this.toolbars = [];
42117 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42123 * @class Roo.form.HtmlEditor
42124 * @extends Roo.form.Field
42125 * Provides a lightweight HTML Editor component.
42127 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42129 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42130 * supported by this editor.</b><br/><br/>
42131 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42132 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42134 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42136 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42141 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42146 * @cfg {Number} height (in pixels)
42150 * @cfg {Number} width (in pixels)
42155 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42158 stylesheets: false,
42163 // private properties
42164 validationEvent : false,
42166 initialized : false,
42169 onFocus : Roo.emptyFn,
42171 hideMode:'offsets',
42173 defaultAutoCreate : { // modified by initCompnoent..
42175 style:"width:500px;height:300px;",
42176 autocomplete: "off"
42180 initComponent : function(){
42183 * @event initialize
42184 * Fires when the editor is fully initialized (including the iframe)
42185 * @param {HtmlEditor} this
42190 * Fires when the editor is first receives the focus. Any insertion must wait
42191 * until after this event.
42192 * @param {HtmlEditor} this
42196 * @event beforesync
42197 * Fires before the textarea is updated with content from the editor iframe. Return false
42198 * to cancel the sync.
42199 * @param {HtmlEditor} this
42200 * @param {String} html
42204 * @event beforepush
42205 * Fires before the iframe editor is updated with content from the textarea. Return false
42206 * to cancel the push.
42207 * @param {HtmlEditor} this
42208 * @param {String} html
42213 * Fires when the textarea is updated with content from the editor iframe.
42214 * @param {HtmlEditor} this
42215 * @param {String} html
42220 * Fires when the iframe editor is updated with content from the textarea.
42221 * @param {HtmlEditor} this
42222 * @param {String} html
42226 * @event editmodechange
42227 * Fires when the editor switches edit modes
42228 * @param {HtmlEditor} this
42229 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42231 editmodechange: true,
42233 * @event editorevent
42234 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42235 * @param {HtmlEditor} this
42239 * @event firstfocus
42240 * Fires when on first focus - needed by toolbars..
42241 * @param {HtmlEditor} this
42246 * Auto save the htmlEditor value as a file into Events
42247 * @param {HtmlEditor} this
42251 * @event savedpreview
42252 * preview the saved version of htmlEditor
42253 * @param {HtmlEditor} this
42257 this.defaultAutoCreate = {
42259 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42260 autocomplete: "off"
42265 * Protected method that will not generally be called directly. It
42266 * is called when the editor creates its toolbar. Override this method if you need to
42267 * add custom toolbar buttons.
42268 * @param {HtmlEditor} editor
42270 createToolbar : function(editor){
42271 Roo.log("create toolbars");
42272 if (!editor.toolbars || !editor.toolbars.length) {
42273 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42276 for (var i =0 ; i < editor.toolbars.length;i++) {
42277 editor.toolbars[i] = Roo.factory(
42278 typeof(editor.toolbars[i]) == 'string' ?
42279 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42280 Roo.form.HtmlEditor);
42281 editor.toolbars[i].init(editor);
42289 onRender : function(ct, position)
42292 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42294 this.wrap = this.el.wrap({
42295 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42298 this.editorcore.onRender(ct, position);
42300 if (this.resizable) {
42301 this.resizeEl = new Roo.Resizable(this.wrap, {
42305 minHeight : this.height,
42306 height: this.height,
42307 handles : this.resizable,
42310 resize : function(r, w, h) {
42311 _t.onResize(w,h); // -something
42317 this.createToolbar(this);
42321 this.setSize(this.wrap.getSize());
42323 if (this.resizeEl) {
42324 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42325 // should trigger onReize..
42328 // if(this.autosave && this.w){
42329 // this.autoSaveFn = setInterval(this.autosave, 1000);
42334 onResize : function(w, h)
42336 //Roo.log('resize: ' +w + ',' + h );
42337 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42342 if(typeof w == 'number'){
42343 var aw = w - this.wrap.getFrameWidth('lr');
42344 this.el.setWidth(this.adjustWidth('textarea', aw));
42347 if(typeof h == 'number'){
42349 for (var i =0; i < this.toolbars.length;i++) {
42350 // fixme - ask toolbars for heights?
42351 tbh += this.toolbars[i].tb.el.getHeight();
42352 if (this.toolbars[i].footer) {
42353 tbh += this.toolbars[i].footer.el.getHeight();
42360 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42361 ah -= 5; // knock a few pixes off for look..
42362 this.el.setHeight(this.adjustWidth('textarea', ah));
42366 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42367 this.editorcore.onResize(ew,eh);
42372 * Toggles the editor between standard and source edit mode.
42373 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42375 toggleSourceEdit : function(sourceEditMode)
42377 this.editorcore.toggleSourceEdit(sourceEditMode);
42379 if(this.editorcore.sourceEditMode){
42380 Roo.log('editor - showing textarea');
42383 // Roo.log(this.syncValue());
42384 this.editorcore.syncValue();
42385 this.el.removeClass('x-hidden');
42386 this.el.dom.removeAttribute('tabIndex');
42389 Roo.log('editor - hiding textarea');
42391 // Roo.log(this.pushValue());
42392 this.editorcore.pushValue();
42394 this.el.addClass('x-hidden');
42395 this.el.dom.setAttribute('tabIndex', -1);
42396 //this.deferFocus();
42399 this.setSize(this.wrap.getSize());
42400 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42403 // private (for BoxComponent)
42404 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42406 // private (for BoxComponent)
42407 getResizeEl : function(){
42411 // private (for BoxComponent)
42412 getPositionEl : function(){
42417 initEvents : function(){
42418 this.originalValue = this.getValue();
42422 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42425 markInvalid : Roo.emptyFn,
42427 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42430 clearInvalid : Roo.emptyFn,
42432 setValue : function(v){
42433 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42434 this.editorcore.pushValue();
42439 deferFocus : function(){
42440 this.focus.defer(10, this);
42444 focus : function(){
42445 this.editorcore.focus();
42451 onDestroy : function(){
42457 for (var i =0; i < this.toolbars.length;i++) {
42458 // fixme - ask toolbars for heights?
42459 this.toolbars[i].onDestroy();
42462 this.wrap.dom.innerHTML = '';
42463 this.wrap.remove();
42468 onFirstFocus : function(){
42469 //Roo.log("onFirstFocus");
42470 this.editorcore.onFirstFocus();
42471 for (var i =0; i < this.toolbars.length;i++) {
42472 this.toolbars[i].onFirstFocus();
42478 syncValue : function()
42480 this.editorcore.syncValue();
42484 // hide stuff that is not compatible
42498 * @event specialkey
42502 * @cfg {String} fieldClass @hide
42505 * @cfg {String} focusClass @hide
42508 * @cfg {String} autoCreate @hide
42511 * @cfg {String} inputType @hide
42514 * @cfg {String} invalidClass @hide
42517 * @cfg {String} invalidText @hide
42520 * @cfg {String} msgFx @hide
42523 * @cfg {String} validateOnBlur @hide
42527 // <script type="text/javascript">
42530 * Ext JS Library 1.1.1
42531 * Copyright(c) 2006-2007, Ext JS, LLC.
42537 * @class Roo.form.HtmlEditorToolbar1
42542 new Roo.form.HtmlEditor({
42545 new Roo.form.HtmlEditorToolbar1({
42546 disable : { fonts: 1 , format: 1, ..., ... , ...],
42552 * @cfg {Object} disable List of elements to disable..
42553 * @cfg {Array} btns List of additional buttons.
42557 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42560 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42563 Roo.apply(this, config);
42565 // default disabled, based on 'good practice'..
42566 this.disable = this.disable || {};
42567 Roo.applyIf(this.disable, {
42570 specialElements : true
42574 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42575 // dont call parent... till later.
42578 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42585 editorcore : false,
42587 * @cfg {Object} disable List of toolbar elements to disable
42594 * @cfg {String} createLinkText The default text for the create link prompt
42596 createLinkText : 'Please enter the URL for the link:',
42598 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42600 defaultLinkValue : 'http:/'+'/',
42604 * @cfg {Array} fontFamilies An array of available font families
42622 // "á" , ?? a acute?
42627 "°" // , // degrees
42629 // "é" , // e ecute
42630 // "ú" , // u ecute?
42633 specialElements : [
42635 text: "Insert Table",
42638 ihtml : '<table><tr><td>Cell</td></tr></table>'
42642 text: "Insert Image",
42645 ihtml : '<img src="about:blank"/>'
42654 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42655 "input:submit", "input:button", "select", "textarea", "label" ],
42658 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42660 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42668 * @cfg {String} defaultFont default font to use.
42670 defaultFont: 'tahoma',
42672 fontSelect : false,
42675 formatCombo : false,
42677 init : function(editor)
42679 this.editor = editor;
42680 this.editorcore = editor.editorcore ? editor.editorcore : editor;
42681 var editorcore = this.editorcore;
42685 var fid = editorcore.frameId;
42687 function btn(id, toggle, handler){
42688 var xid = fid + '-'+ id ;
42692 cls : 'x-btn-icon x-edit-'+id,
42693 enableToggle:toggle !== false,
42694 scope: _t, // was editor...
42695 handler:handler||_t.relayBtnCmd,
42696 clickEvent:'mousedown',
42697 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42704 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42706 // stop form submits
42707 tb.el.on('click', function(e){
42708 e.preventDefault(); // what does this do?
42711 if(!this.disable.font) { // && !Roo.isSafari){
42712 /* why no safari for fonts
42713 editor.fontSelect = tb.el.createChild({
42716 cls:'x-font-select',
42717 html: this.createFontOptions()
42720 editor.fontSelect.on('change', function(){
42721 var font = editor.fontSelect.dom.value;
42722 editor.relayCmd('fontname', font);
42723 editor.deferFocus();
42727 editor.fontSelect.dom,
42733 if(!this.disable.formats){
42734 this.formatCombo = new Roo.form.ComboBox({
42735 store: new Roo.data.SimpleStore({
42738 data : this.formats // from states.js
42742 //autoCreate : {tag: "div", size: "20"},
42743 displayField:'tag',
42747 triggerAction: 'all',
42748 emptyText:'Add tag',
42749 selectOnFocus:true,
42752 'select': function(c, r, i) {
42753 editorcore.insertTag(r.get('tag'));
42759 tb.addField(this.formatCombo);
42763 if(!this.disable.format){
42770 if(!this.disable.fontSize){
42775 btn('increasefontsize', false, editorcore.adjustFont),
42776 btn('decreasefontsize', false, editorcore.adjustFont)
42781 if(!this.disable.colors){
42784 id:editorcore.frameId +'-forecolor',
42785 cls:'x-btn-icon x-edit-forecolor',
42786 clickEvent:'mousedown',
42787 tooltip: this.buttonTips['forecolor'] || undefined,
42789 menu : new Roo.menu.ColorMenu({
42790 allowReselect: true,
42791 focus: Roo.emptyFn,
42794 selectHandler: function(cp, color){
42795 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
42796 editor.deferFocus();
42799 clickEvent:'mousedown'
42802 id:editorcore.frameId +'backcolor',
42803 cls:'x-btn-icon x-edit-backcolor',
42804 clickEvent:'mousedown',
42805 tooltip: this.buttonTips['backcolor'] || undefined,
42807 menu : new Roo.menu.ColorMenu({
42808 focus: Roo.emptyFn,
42811 allowReselect: true,
42812 selectHandler: function(cp, color){
42814 editorcore.execCmd('useCSS', false);
42815 editorcore.execCmd('hilitecolor', color);
42816 editorcore.execCmd('useCSS', true);
42817 editor.deferFocus();
42819 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
42820 Roo.isSafari || Roo.isIE ? '#'+color : color);
42821 editor.deferFocus();
42825 clickEvent:'mousedown'
42830 // now add all the items...
42833 if(!this.disable.alignments){
42836 btn('justifyleft'),
42837 btn('justifycenter'),
42838 btn('justifyright')
42842 //if(!Roo.isSafari){
42843 if(!this.disable.links){
42846 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
42850 if(!this.disable.lists){
42853 btn('insertorderedlist'),
42854 btn('insertunorderedlist')
42857 if(!this.disable.sourceEdit){
42860 btn('sourceedit', true, function(btn){
42862 this.toggleSourceEdit(btn.pressed);
42869 // special menu.. - needs to be tidied up..
42870 if (!this.disable.special) {
42873 cls: 'x-edit-none',
42879 for (var i =0; i < this.specialChars.length; i++) {
42880 smenu.menu.items.push({
42882 html: this.specialChars[i],
42883 handler: function(a,b) {
42884 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
42885 //editor.insertAtCursor(a.html);
42899 if (!this.disable.cleanStyles) {
42901 cls: 'x-btn-icon x-btn-clear',
42907 for (var i =0; i < this.cleanStyles.length; i++) {
42908 cmenu.menu.items.push({
42909 actiontype : this.cleanStyles[i],
42910 html: 'Remove ' + this.cleanStyles[i],
42911 handler: function(a,b) {
42914 var c = Roo.get(editorcore.doc.body);
42915 c.select('[style]').each(function(s) {
42916 s.dom.style.removeProperty(a.actiontype);
42927 if (!this.disable.specialElements) {
42930 cls: 'x-edit-none',
42935 for (var i =0; i < this.specialElements.length; i++) {
42936 semenu.menu.items.push(
42938 handler: function(a,b) {
42939 editor.insertAtCursor(this.ihtml);
42941 }, this.specialElements[i])
42953 for(var i =0; i< this.btns.length;i++) {
42954 var b = Roo.factory(this.btns[i],Roo.form);
42955 b.cls = 'x-edit-none';
42956 b.scope = editorcore;
42964 // disable everything...
42966 this.tb.items.each(function(item){
42967 if(item.id != editorcore.frameId+ '-sourceedit'){
42971 this.rendered = true;
42973 // the all the btns;
42974 editor.on('editorevent', this.updateToolbar, this);
42975 // other toolbars need to implement this..
42976 //editor.on('editmodechange', this.updateToolbar, this);
42980 relayBtnCmd : function(btn) {
42981 this.editorcore.relayCmd(btn.cmd);
42983 // private used internally
42984 createLink : function(){
42985 Roo.log("create link?");
42986 var url = prompt(this.createLinkText, this.defaultLinkValue);
42987 if(url && url != 'http:/'+'/'){
42988 this.editorcore.relayCmd('createlink', url);
42994 * Protected method that will not generally be called directly. It triggers
42995 * a toolbar update by reading the markup state of the current selection in the editor.
42997 updateToolbar: function(){
42999 if(!this.editorcore.activated){
43000 this.editor.onFirstFocus();
43004 var btns = this.tb.items.map,
43005 doc = this.editorcore.doc,
43006 frameId = this.editorcore.frameId;
43008 if(!this.disable.font && !Roo.isSafari){
43010 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43011 if(name != this.fontSelect.dom.value){
43012 this.fontSelect.dom.value = name;
43016 if(!this.disable.format){
43017 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43018 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43019 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43021 if(!this.disable.alignments){
43022 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43023 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43024 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43026 if(!Roo.isSafari && !this.disable.lists){
43027 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43028 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43031 var ans = this.editorcore.getAllAncestors();
43032 if (this.formatCombo) {
43035 var store = this.formatCombo.store;
43036 this.formatCombo.setValue("");
43037 for (var i =0; i < ans.length;i++) {
43038 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43040 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43048 // hides menus... - so this cant be on a menu...
43049 Roo.menu.MenuMgr.hideAll();
43051 //this.editorsyncValue();
43055 createFontOptions : function(){
43056 var buf = [], fs = this.fontFamilies, ff, lc;
43060 for(var i = 0, len = fs.length; i< len; i++){
43062 lc = ff.toLowerCase();
43064 '<option value="',lc,'" style="font-family:',ff,';"',
43065 (this.defaultFont == lc ? ' selected="true">' : '>'),
43070 return buf.join('');
43073 toggleSourceEdit : function(sourceEditMode){
43075 Roo.log("toolbar toogle");
43076 if(sourceEditMode === undefined){
43077 sourceEditMode = !this.sourceEditMode;
43079 this.sourceEditMode = sourceEditMode === true;
43080 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43081 // just toggle the button?
43082 if(btn.pressed !== this.sourceEditMode){
43083 btn.toggle(this.sourceEditMode);
43087 if(sourceEditMode){
43088 Roo.log("disabling buttons");
43089 this.tb.items.each(function(item){
43090 if(item.cmd != 'sourceedit'){
43096 Roo.log("enabling buttons");
43097 if(this.editorcore.initialized){
43098 this.tb.items.each(function(item){
43104 Roo.log("calling toggole on editor");
43105 // tell the editor that it's been pressed..
43106 this.editor.toggleSourceEdit(sourceEditMode);
43110 * Object collection of toolbar tooltips for the buttons in the editor. The key
43111 * is the command id associated with that button and the value is a valid QuickTips object.
43116 title: 'Bold (Ctrl+B)',
43117 text: 'Make the selected text bold.',
43118 cls: 'x-html-editor-tip'
43121 title: 'Italic (Ctrl+I)',
43122 text: 'Make the selected text italic.',
43123 cls: 'x-html-editor-tip'
43131 title: 'Bold (Ctrl+B)',
43132 text: 'Make the selected text bold.',
43133 cls: 'x-html-editor-tip'
43136 title: 'Italic (Ctrl+I)',
43137 text: 'Make the selected text italic.',
43138 cls: 'x-html-editor-tip'
43141 title: 'Underline (Ctrl+U)',
43142 text: 'Underline the selected text.',
43143 cls: 'x-html-editor-tip'
43145 increasefontsize : {
43146 title: 'Grow Text',
43147 text: 'Increase the font size.',
43148 cls: 'x-html-editor-tip'
43150 decreasefontsize : {
43151 title: 'Shrink Text',
43152 text: 'Decrease the font size.',
43153 cls: 'x-html-editor-tip'
43156 title: 'Text Highlight Color',
43157 text: 'Change the background color of the selected text.',
43158 cls: 'x-html-editor-tip'
43161 title: 'Font Color',
43162 text: 'Change the color of the selected text.',
43163 cls: 'x-html-editor-tip'
43166 title: 'Align Text Left',
43167 text: 'Align text to the left.',
43168 cls: 'x-html-editor-tip'
43171 title: 'Center Text',
43172 text: 'Center text in the editor.',
43173 cls: 'x-html-editor-tip'
43176 title: 'Align Text Right',
43177 text: 'Align text to the right.',
43178 cls: 'x-html-editor-tip'
43180 insertunorderedlist : {
43181 title: 'Bullet List',
43182 text: 'Start a bulleted list.',
43183 cls: 'x-html-editor-tip'
43185 insertorderedlist : {
43186 title: 'Numbered List',
43187 text: 'Start a numbered list.',
43188 cls: 'x-html-editor-tip'
43191 title: 'Hyperlink',
43192 text: 'Make the selected text a hyperlink.',
43193 cls: 'x-html-editor-tip'
43196 title: 'Source Edit',
43197 text: 'Switch to source editing mode.',
43198 cls: 'x-html-editor-tip'
43202 onDestroy : function(){
43205 this.tb.items.each(function(item){
43207 item.menu.removeAll();
43209 item.menu.el.destroy();
43217 onFirstFocus: function() {
43218 this.tb.items.each(function(item){
43227 // <script type="text/javascript">
43230 * Ext JS Library 1.1.1
43231 * Copyright(c) 2006-2007, Ext JS, LLC.
43238 * @class Roo.form.HtmlEditor.ToolbarContext
43243 new Roo.form.HtmlEditor({
43246 { xtype: 'ToolbarStandard', styles : {} }
43247 { xtype: 'ToolbarContext', disable : {} }
43253 * @config : {Object} disable List of elements to disable.. (not done yet.)
43254 * @config : {Object} styles Map of styles available.
43258 Roo.form.HtmlEditor.ToolbarContext = function(config)
43261 Roo.apply(this, config);
43262 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43263 // dont call parent... till later.
43264 this.styles = this.styles || {};
43269 Roo.form.HtmlEditor.ToolbarContext.types = {
43281 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43347 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43352 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43362 style : 'fontFamily',
43363 displayField: 'display',
43364 optname : 'font-family',
43413 // should we really allow this??
43414 // should this just be
43425 style : 'fontFamily',
43426 displayField: 'display',
43427 optname : 'font-family',
43434 style : 'fontFamily',
43435 displayField: 'display',
43436 optname : 'font-family',
43443 style : 'fontFamily',
43444 displayField: 'display',
43445 optname : 'font-family',
43456 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43457 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43459 Roo.form.HtmlEditor.ToolbarContext.options = {
43461 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43462 [ 'Courier New', 'Courier New'],
43463 [ 'Tahoma', 'Tahoma'],
43464 [ 'Times New Roman,serif', 'Times'],
43465 [ 'Verdana','Verdana' ]
43469 // fixme - these need to be configurable..
43472 Roo.form.HtmlEditor.ToolbarContext.types
43475 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43482 editorcore : false,
43484 * @cfg {Object} disable List of toolbar elements to disable
43489 * @cfg {Object} styles List of styles
43490 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43492 * These must be defined in the page, so they get rendered correctly..
43503 init : function(editor)
43505 this.editor = editor;
43506 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43507 var editorcore = this.editorcore;
43509 var fid = editorcore.frameId;
43511 function btn(id, toggle, handler){
43512 var xid = fid + '-'+ id ;
43516 cls : 'x-btn-icon x-edit-'+id,
43517 enableToggle:toggle !== false,
43518 scope: editorcore, // was editor...
43519 handler:handler||editorcore.relayBtnCmd,
43520 clickEvent:'mousedown',
43521 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43525 // create a new element.
43526 var wdiv = editor.wrap.createChild({
43528 }, editor.wrap.dom.firstChild.nextSibling, true);
43530 // can we do this more than once??
43532 // stop form submits
43535 // disable everything...
43536 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43537 this.toolbars = {};
43539 for (var i in ty) {
43541 this.toolbars[i] = this.buildToolbar(ty[i],i);
43543 this.tb = this.toolbars.BODY;
43545 this.buildFooter();
43546 this.footer.show();
43547 editor.on('hide', function( ) { this.footer.hide() }, this);
43548 editor.on('show', function( ) { this.footer.show() }, this);
43551 this.rendered = true;
43553 // the all the btns;
43554 editor.on('editorevent', this.updateToolbar, this);
43555 // other toolbars need to implement this..
43556 //editor.on('editmodechange', this.updateToolbar, this);
43562 * Protected method that will not generally be called directly. It triggers
43563 * a toolbar update by reading the markup state of the current selection in the editor.
43565 updateToolbar: function(editor,ev,sel){
43568 // capture mouse up - this is handy for selecting images..
43569 // perhaps should go somewhere else...
43570 if(!this.editorcore.activated){
43571 this.editor.onFirstFocus();
43575 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43576 // selectNode - might want to handle IE?
43578 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43579 ev.target && ev.target.tagName == 'IMG') {
43580 // they have click on an image...
43581 // let's see if we can change the selection...
43584 var nodeRange = sel.ownerDocument.createRange();
43586 nodeRange.selectNode(sel);
43588 nodeRange.selectNodeContents(sel);
43590 //nodeRange.collapse(true);
43591 var s = this.editorcore.win.getSelection();
43592 s.removeAllRanges();
43593 s.addRange(nodeRange);
43597 var updateFooter = sel ? false : true;
43600 var ans = this.editorcore.getAllAncestors();
43603 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43606 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43607 sel = sel ? sel : this.editorcore.doc.body;
43608 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
43611 // pick a menu that exists..
43612 var tn = sel.tagName.toUpperCase();
43613 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43615 tn = sel.tagName.toUpperCase();
43617 var lastSel = this.tb.selectedNode
43619 this.tb.selectedNode = sel;
43621 // if current menu does not match..
43622 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43625 ///console.log("show: " + tn);
43626 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43629 this.tb.items.first().el.innerHTML = tn + ': ';
43632 // update attributes
43633 if (this.tb.fields) {
43634 this.tb.fields.each(function(e) {
43636 e.setValue(sel.style[e.stylename]);
43639 e.setValue(sel.getAttribute(e.attrname));
43643 var hasStyles = false;
43644 for(var i in this.styles) {
43651 var st = this.tb.fields.item(0);
43653 st.store.removeAll();
43656 var cn = sel.className.split(/\s+/);
43659 if (this.styles['*']) {
43661 Roo.each(this.styles['*'], function(v) {
43662 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43665 if (this.styles[tn]) {
43666 Roo.each(this.styles[tn], function(v) {
43667 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43671 st.store.loadData(avs);
43675 // flag our selected Node.
43676 this.tb.selectedNode = sel;
43679 Roo.menu.MenuMgr.hideAll();
43683 if (!updateFooter) {
43684 //this.footDisp.dom.innerHTML = '';
43687 // update the footer
43691 this.footerEls = ans.reverse();
43692 Roo.each(this.footerEls, function(a,i) {
43693 if (!a) { return; }
43694 html += html.length ? ' > ' : '';
43696 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43701 var sz = this.footDisp.up('td').getSize();
43702 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43703 this.footDisp.dom.style.marginLeft = '5px';
43705 this.footDisp.dom.style.overflow = 'hidden';
43707 this.footDisp.dom.innerHTML = html;
43709 //this.editorsyncValue();
43716 onDestroy : function(){
43719 this.tb.items.each(function(item){
43721 item.menu.removeAll();
43723 item.menu.el.destroy();
43731 onFirstFocus: function() {
43732 // need to do this for all the toolbars..
43733 this.tb.items.each(function(item){
43737 buildToolbar: function(tlist, nm)
43739 var editor = this.editor;
43740 var editorcore = this.editorcore;
43741 // create a new element.
43742 var wdiv = editor.wrap.createChild({
43744 }, editor.wrap.dom.firstChild.nextSibling, true);
43747 var tb = new Roo.Toolbar(wdiv);
43750 tb.add(nm+ ": ");
43753 for(var i in this.styles) {
43758 if (styles && styles.length) {
43760 // this needs a multi-select checkbox...
43761 tb.addField( new Roo.form.ComboBox({
43762 store: new Roo.data.SimpleStore({
43764 fields: ['val', 'selected'],
43767 name : '-roo-edit-className',
43768 attrname : 'className',
43769 displayField: 'val',
43773 triggerAction: 'all',
43774 emptyText:'Select Style',
43775 selectOnFocus:true,
43778 'select': function(c, r, i) {
43779 // initial support only for on class per el..
43780 tb.selectedNode.className = r ? r.get('val') : '';
43781 editorcore.syncValue();
43788 var tbc = Roo.form.HtmlEditor.ToolbarContext;
43789 var tbops = tbc.options;
43791 for (var i in tlist) {
43793 var item = tlist[i];
43794 tb.add(item.title + ": ");
43797 //optname == used so you can configure the options available..
43798 var opts = item.opts ? item.opts : false;
43799 if (item.optname) {
43800 opts = tbops[item.optname];
43805 // opts == pulldown..
43806 tb.addField( new Roo.form.ComboBox({
43807 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
43809 fields: ['val', 'display'],
43812 name : '-roo-edit-' + i,
43814 stylename : item.style ? item.style : false,
43815 displayField: item.displayField ? item.displayField : 'val',
43816 valueField : 'val',
43818 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
43820 triggerAction: 'all',
43821 emptyText:'Select',
43822 selectOnFocus:true,
43823 width: item.width ? item.width : 130,
43825 'select': function(c, r, i) {
43827 tb.selectedNode.style[c.stylename] = r.get('val');
43830 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
43839 tb.addField( new Roo.form.TextField({
43842 //allowBlank:false,
43847 tb.addField( new Roo.form.TextField({
43848 name: '-roo-edit-' + i,
43855 'change' : function(f, nv, ov) {
43856 tb.selectedNode.setAttribute(f.attrname, nv);
43865 text: 'Remove Tag',
43868 click : function ()
43871 // undo does not work.
43873 var sn = tb.selectedNode;
43875 var pn = sn.parentNode;
43877 var stn = sn.childNodes[0];
43878 var en = sn.childNodes[sn.childNodes.length - 1 ];
43879 while (sn.childNodes.length) {
43880 var node = sn.childNodes[0];
43881 sn.removeChild(node);
43883 pn.insertBefore(node, sn);
43886 pn.removeChild(sn);
43887 var range = editorcore.createRange();
43889 range.setStart(stn,0);
43890 range.setEnd(en,0); //????
43891 //range.selectNode(sel);
43894 var selection = editorcore.getSelection();
43895 selection.removeAllRanges();
43896 selection.addRange(range);
43900 //_this.updateToolbar(null, null, pn);
43901 _this.updateToolbar(null, null, null);
43902 _this.footDisp.dom.innerHTML = '';
43912 tb.el.on('click', function(e){
43913 e.preventDefault(); // what does this do?
43915 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
43918 // dont need to disable them... as they will get hidden
43923 buildFooter : function()
43926 var fel = this.editor.wrap.createChild();
43927 this.footer = new Roo.Toolbar(fel);
43928 // toolbar has scrolly on left / right?
43929 var footDisp= new Roo.Toolbar.Fill();
43935 handler : function() {
43936 _t.footDisp.scrollTo('left',0,true)
43940 this.footer.add( footDisp );
43945 handler : function() {
43947 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
43951 var fel = Roo.get(footDisp.el);
43952 fel.addClass('x-editor-context');
43953 this.footDispWrap = fel;
43954 this.footDispWrap.overflow = 'hidden';
43956 this.footDisp = fel.createChild();
43957 this.footDispWrap.on('click', this.onContextClick, this)
43961 onContextClick : function (ev,dom)
43963 ev.preventDefault();
43964 var cn = dom.className;
43966 if (!cn.match(/x-ed-loc-/)) {
43969 var n = cn.split('-').pop();
43970 var ans = this.footerEls;
43974 var range = this.editorcore.createRange();
43976 range.selectNodeContents(sel);
43977 //range.selectNode(sel);
43980 var selection = this.editorcore.getSelection();
43981 selection.removeAllRanges();
43982 selection.addRange(range);
43986 this.updateToolbar(null, null, sel);
44003 * Ext JS Library 1.1.1
44004 * Copyright(c) 2006-2007, Ext JS, LLC.
44006 * Originally Released Under LGPL - original licence link has changed is not relivant.
44009 * <script type="text/javascript">
44013 * @class Roo.form.BasicForm
44014 * @extends Roo.util.Observable
44015 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44017 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44018 * @param {Object} config Configuration options
44020 Roo.form.BasicForm = function(el, config){
44021 this.allItems = [];
44022 this.childForms = [];
44023 Roo.apply(this, config);
44025 * The Roo.form.Field items in this form.
44026 * @type MixedCollection
44030 this.items = new Roo.util.MixedCollection(false, function(o){
44031 return o.id || (o.id = Roo.id());
44035 * @event beforeaction
44036 * Fires before any action is performed. Return false to cancel the action.
44037 * @param {Form} this
44038 * @param {Action} action The action to be performed
44040 beforeaction: true,
44042 * @event actionfailed
44043 * Fires when an action fails.
44044 * @param {Form} this
44045 * @param {Action} action The action that failed
44047 actionfailed : true,
44049 * @event actioncomplete
44050 * Fires when an action is completed.
44051 * @param {Form} this
44052 * @param {Action} action The action that completed
44054 actioncomplete : true
44059 Roo.form.BasicForm.superclass.constructor.call(this);
44062 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44064 * @cfg {String} method
44065 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44068 * @cfg {DataReader} reader
44069 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44070 * This is optional as there is built-in support for processing JSON.
44073 * @cfg {DataReader} errorReader
44074 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44075 * This is completely optional as there is built-in support for processing JSON.
44078 * @cfg {String} url
44079 * The URL to use for form actions if one isn't supplied in the action options.
44082 * @cfg {Boolean} fileUpload
44083 * Set to true if this form is a file upload.
44087 * @cfg {Object} baseParams
44088 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44093 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44098 activeAction : null,
44101 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44102 * or setValues() data instead of when the form was first created.
44104 trackResetOnLoad : false,
44108 * childForms - used for multi-tab forms
44111 childForms : false,
44114 * allItems - full list of fields.
44120 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44121 * element by passing it or its id or mask the form itself by passing in true.
44124 waitMsgTarget : false,
44127 initEl : function(el){
44128 this.el = Roo.get(el);
44129 this.id = this.el.id || Roo.id();
44130 this.el.on('submit', this.onSubmit, this);
44131 this.el.addClass('x-form');
44135 onSubmit : function(e){
44140 * Returns true if client-side validation on the form is successful.
44143 isValid : function(){
44145 this.items.each(function(f){
44154 * Returns true if any fields in this form have changed since their original load.
44157 isDirty : function(){
44159 this.items.each(function(f){
44169 * Performs a predefined action (submit or load) or custom actions you define on this form.
44170 * @param {String} actionName The name of the action type
44171 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44172 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44173 * accept other config options):
44175 Property Type Description
44176 ---------------- --------------- ----------------------------------------------------------------------------------
44177 url String The url for the action (defaults to the form's url)
44178 method String The form method to use (defaults to the form's method, or POST if not defined)
44179 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44180 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44181 validate the form on the client (defaults to false)
44183 * @return {BasicForm} this
44185 doAction : function(action, options){
44186 if(typeof action == 'string'){
44187 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44189 if(this.fireEvent('beforeaction', this, action) !== false){
44190 this.beforeAction(action);
44191 action.run.defer(100, action);
44197 * Shortcut to do a submit action.
44198 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44199 * @return {BasicForm} this
44201 submit : function(options){
44202 this.doAction('submit', options);
44207 * Shortcut to do a load action.
44208 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44209 * @return {BasicForm} this
44211 load : function(options){
44212 this.doAction('load', options);
44217 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44218 * @param {Record} record The record to edit
44219 * @return {BasicForm} this
44221 updateRecord : function(record){
44222 record.beginEdit();
44223 var fs = record.fields;
44224 fs.each(function(f){
44225 var field = this.findField(f.name);
44227 record.set(f.name, field.getValue());
44235 * Loads an Roo.data.Record into this form.
44236 * @param {Record} record The record to load
44237 * @return {BasicForm} this
44239 loadRecord : function(record){
44240 this.setValues(record.data);
44245 beforeAction : function(action){
44246 var o = action.options;
44249 if(this.waitMsgTarget === true){
44250 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44251 }else if(this.waitMsgTarget){
44252 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44253 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44255 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44261 afterAction : function(action, success){
44262 this.activeAction = null;
44263 var o = action.options;
44265 if(this.waitMsgTarget === true){
44267 }else if(this.waitMsgTarget){
44268 this.waitMsgTarget.unmask();
44270 Roo.MessageBox.updateProgress(1);
44271 Roo.MessageBox.hide();
44278 Roo.callback(o.success, o.scope, [this, action]);
44279 this.fireEvent('actioncomplete', this, action);
44283 // failure condition..
44284 // we have a scenario where updates need confirming.
44285 // eg. if a locking scenario exists..
44286 // we look for { errors : { needs_confirm : true }} in the response.
44288 (typeof(action.result) != 'undefined') &&
44289 (typeof(action.result.errors) != 'undefined') &&
44290 (typeof(action.result.errors.needs_confirm) != 'undefined')
44293 Roo.MessageBox.confirm(
44294 "Change requires confirmation",
44295 action.result.errorMsg,
44300 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44310 Roo.callback(o.failure, o.scope, [this, action]);
44311 // show an error message if no failed handler is set..
44312 if (!this.hasListener('actionfailed')) {
44313 Roo.MessageBox.alert("Error",
44314 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44315 action.result.errorMsg :
44316 "Saving Failed, please check your entries or try again"
44320 this.fireEvent('actionfailed', this, action);
44326 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44327 * @param {String} id The value to search for
44330 findField : function(id){
44331 var field = this.items.get(id);
44333 this.items.each(function(f){
44334 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44340 return field || null;
44344 * Add a secondary form to this one,
44345 * Used to provide tabbed forms. One form is primary, with hidden values
44346 * which mirror the elements from the other forms.
44348 * @param {Roo.form.Form} form to add.
44351 addForm : function(form)
44354 if (this.childForms.indexOf(form) > -1) {
44358 this.childForms.push(form);
44360 Roo.each(form.allItems, function (fe) {
44362 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44363 if (this.findField(n)) { // already added..
44366 var add = new Roo.form.Hidden({
44369 add.render(this.el);
44376 * Mark fields in this form invalid in bulk.
44377 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44378 * @return {BasicForm} this
44380 markInvalid : function(errors){
44381 if(errors instanceof Array){
44382 for(var i = 0, len = errors.length; i < len; i++){
44383 var fieldError = errors[i];
44384 var f = this.findField(fieldError.id);
44386 f.markInvalid(fieldError.msg);
44392 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44393 field.markInvalid(errors[id]);
44397 Roo.each(this.childForms || [], function (f) {
44398 f.markInvalid(errors);
44405 * Set values for fields in this form in bulk.
44406 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44407 * @return {BasicForm} this
44409 setValues : function(values){
44410 if(values instanceof Array){ // array of objects
44411 for(var i = 0, len = values.length; i < len; i++){
44413 var f = this.findField(v.id);
44415 f.setValue(v.value);
44416 if(this.trackResetOnLoad){
44417 f.originalValue = f.getValue();
44421 }else{ // object hash
44424 if(typeof values[id] != 'function' && (field = this.findField(id))){
44426 if (field.setFromData &&
44427 field.valueField &&
44428 field.displayField &&
44429 // combos' with local stores can
44430 // be queried via setValue()
44431 // to set their value..
44432 (field.store && !field.store.isLocal)
44436 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44437 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44438 field.setFromData(sd);
44441 field.setValue(values[id]);
44445 if(this.trackResetOnLoad){
44446 field.originalValue = field.getValue();
44452 Roo.each(this.childForms || [], function (f) {
44453 f.setValues(values);
44460 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44461 * they are returned as an array.
44462 * @param {Boolean} asString
44465 getValues : function(asString){
44466 if (this.childForms) {
44467 // copy values from the child forms
44468 Roo.each(this.childForms, function (f) {
44469 this.setValues(f.getValues());
44475 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44476 if(asString === true){
44479 return Roo.urlDecode(fs);
44483 * Returns the fields in this form as an object with key/value pairs.
44484 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44487 getFieldValues : function(with_hidden)
44489 if (this.childForms) {
44490 // copy values from the child forms
44491 // should this call getFieldValues - probably not as we do not currently copy
44492 // hidden fields when we generate..
44493 Roo.each(this.childForms, function (f) {
44494 this.setValues(f.getValues());
44499 this.items.each(function(f){
44500 if (!f.getName()) {
44503 var v = f.getValue();
44504 if (f.inputType =='radio') {
44505 if (typeof(ret[f.getName()]) == 'undefined') {
44506 ret[f.getName()] = ''; // empty..
44509 if (!f.el.dom.checked) {
44513 v = f.el.dom.value;
44517 // not sure if this supported any more..
44518 if ((typeof(v) == 'object') && f.getRawValue) {
44519 v = f.getRawValue() ; // dates..
44521 // combo boxes where name != hiddenName...
44522 if (f.name != f.getName()) {
44523 ret[f.name] = f.getRawValue();
44525 ret[f.getName()] = v;
44532 * Clears all invalid messages in this form.
44533 * @return {BasicForm} this
44535 clearInvalid : function(){
44536 this.items.each(function(f){
44540 Roo.each(this.childForms || [], function (f) {
44549 * Resets this form.
44550 * @return {BasicForm} this
44552 reset : function(){
44553 this.items.each(function(f){
44557 Roo.each(this.childForms || [], function (f) {
44566 * Add Roo.form components to this form.
44567 * @param {Field} field1
44568 * @param {Field} field2 (optional)
44569 * @param {Field} etc (optional)
44570 * @return {BasicForm} this
44573 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44579 * Removes a field from the items collection (does NOT remove its markup).
44580 * @param {Field} field
44581 * @return {BasicForm} this
44583 remove : function(field){
44584 this.items.remove(field);
44589 * Looks at the fields in this form, checks them for an id attribute,
44590 * and calls applyTo on the existing dom element with that id.
44591 * @return {BasicForm} this
44593 render : function(){
44594 this.items.each(function(f){
44595 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44603 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44604 * @param {Object} values
44605 * @return {BasicForm} this
44607 applyToFields : function(o){
44608 this.items.each(function(f){
44615 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44616 * @param {Object} values
44617 * @return {BasicForm} this
44619 applyIfToFields : function(o){
44620 this.items.each(function(f){
44628 Roo.BasicForm = Roo.form.BasicForm;/*
44630 * Ext JS Library 1.1.1
44631 * Copyright(c) 2006-2007, Ext JS, LLC.
44633 * Originally Released Under LGPL - original licence link has changed is not relivant.
44636 * <script type="text/javascript">
44640 * @class Roo.form.Form
44641 * @extends Roo.form.BasicForm
44642 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44644 * @param {Object} config Configuration options
44646 Roo.form.Form = function(config){
44648 if (config.items) {
44649 xitems = config.items;
44650 delete config.items;
44654 Roo.form.Form.superclass.constructor.call(this, null, config);
44655 this.url = this.url || this.action;
44657 this.root = new Roo.form.Layout(Roo.applyIf({
44661 this.active = this.root;
44663 * Array of all the buttons that have been added to this form via {@link addButton}
44667 this.allItems = [];
44670 * @event clientvalidation
44671 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44672 * @param {Form} this
44673 * @param {Boolean} valid true if the form has passed client-side validation
44675 clientvalidation: true,
44678 * Fires when the form is rendered
44679 * @param {Roo.form.Form} form
44684 if (this.progressUrl) {
44685 // push a hidden field onto the list of fields..
44689 name : 'UPLOAD_IDENTIFIER'
44694 Roo.each(xitems, this.addxtype, this);
44700 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44702 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44705 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44708 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44710 buttonAlign:'center',
44713 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
44718 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
44719 * This property cascades to child containers if not set.
44724 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
44725 * fires a looping event with that state. This is required to bind buttons to the valid
44726 * state using the config value formBind:true on the button.
44728 monitorValid : false,
44731 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
44736 * @cfg {String} progressUrl - Url to return progress data
44739 progressUrl : false,
44742 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
44743 * fields are added and the column is closed. If no fields are passed the column remains open
44744 * until end() is called.
44745 * @param {Object} config The config to pass to the column
44746 * @param {Field} field1 (optional)
44747 * @param {Field} field2 (optional)
44748 * @param {Field} etc (optional)
44749 * @return Column The column container object
44751 column : function(c){
44752 var col = new Roo.form.Column(c);
44754 if(arguments.length > 1){ // duplicate code required because of Opera
44755 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44762 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
44763 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
44764 * until end() is called.
44765 * @param {Object} config The config to pass to the fieldset
44766 * @param {Field} field1 (optional)
44767 * @param {Field} field2 (optional)
44768 * @param {Field} etc (optional)
44769 * @return FieldSet The fieldset container object
44771 fieldset : function(c){
44772 var fs = new Roo.form.FieldSet(c);
44774 if(arguments.length > 1){ // duplicate code required because of Opera
44775 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44782 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
44783 * fields are added and the container is closed. If no fields are passed the container remains open
44784 * until end() is called.
44785 * @param {Object} config The config to pass to the Layout
44786 * @param {Field} field1 (optional)
44787 * @param {Field} field2 (optional)
44788 * @param {Field} etc (optional)
44789 * @return Layout The container object
44791 container : function(c){
44792 var l = new Roo.form.Layout(c);
44794 if(arguments.length > 1){ // duplicate code required because of Opera
44795 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
44802 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
44803 * @param {Object} container A Roo.form.Layout or subclass of Layout
44804 * @return {Form} this
44806 start : function(c){
44807 // cascade label info
44808 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
44809 this.active.stack.push(c);
44810 c.ownerCt = this.active;
44816 * Closes the current open container
44817 * @return {Form} this
44820 if(this.active == this.root){
44823 this.active = this.active.ownerCt;
44828 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
44829 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
44830 * as the label of the field.
44831 * @param {Field} field1
44832 * @param {Field} field2 (optional)
44833 * @param {Field} etc. (optional)
44834 * @return {Form} this
44837 this.active.stack.push.apply(this.active.stack, arguments);
44838 this.allItems.push.apply(this.allItems,arguments);
44840 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
44841 if(a[i].isFormField){
44846 Roo.form.Form.superclass.add.apply(this, r);
44856 * Find any element that has been added to a form, using it's ID or name
44857 * This can include framesets, columns etc. along with regular fields..
44858 * @param {String} id - id or name to find.
44860 * @return {Element} e - or false if nothing found.
44862 findbyId : function(id)
44868 Roo.each(this.allItems, function(f){
44869 if (f.id == id || f.name == id ){
44880 * Render this form into the passed container. This should only be called once!
44881 * @param {String/HTMLElement/Element} container The element this component should be rendered into
44882 * @return {Form} this
44884 render : function(ct)
44890 var o = this.autoCreate || {
44892 method : this.method || 'POST',
44893 id : this.id || Roo.id()
44895 this.initEl(ct.createChild(o));
44897 this.root.render(this.el);
44901 this.items.each(function(f){
44902 f.render('x-form-el-'+f.id);
44905 if(this.buttons.length > 0){
44906 // tables are required to maintain order and for correct IE layout
44907 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
44908 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
44909 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
44911 var tr = tb.getElementsByTagName('tr')[0];
44912 for(var i = 0, len = this.buttons.length; i < len; i++) {
44913 var b = this.buttons[i];
44914 var td = document.createElement('td');
44915 td.className = 'x-form-btn-td';
44916 b.render(tr.appendChild(td));
44919 if(this.monitorValid){ // initialize after render
44920 this.startMonitoring();
44922 this.fireEvent('rendered', this);
44927 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
44928 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
44929 * object or a valid Roo.DomHelper element config
44930 * @param {Function} handler The function called when the button is clicked
44931 * @param {Object} scope (optional) The scope of the handler function
44932 * @return {Roo.Button}
44934 addButton : function(config, handler, scope){
44938 minWidth: this.minButtonWidth,
44941 if(typeof config == "string"){
44944 Roo.apply(bc, config);
44946 var btn = new Roo.Button(null, bc);
44947 this.buttons.push(btn);
44952 * Adds a series of form elements (using the xtype property as the factory method.
44953 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
44954 * @param {Object} config
44957 addxtype : function()
44959 var ar = Array.prototype.slice.call(arguments, 0);
44961 for(var i = 0; i < ar.length; i++) {
44963 continue; // skip -- if this happends something invalid got sent, we
44964 // should ignore it, as basically that interface element will not show up
44965 // and that should be pretty obvious!!
44968 if (Roo.form[ar[i].xtype]) {
44970 var fe = Roo.factory(ar[i], Roo.form);
44976 fe.store.form = this;
44981 this.allItems.push(fe);
44982 if (fe.items && fe.addxtype) {
44983 fe.addxtype.apply(fe, fe.items);
44993 // console.log('adding ' + ar[i].xtype);
44995 if (ar[i].xtype == 'Button') {
44996 //console.log('adding button');
44997 //console.log(ar[i]);
44998 this.addButton(ar[i]);
44999 this.allItems.push(fe);
45003 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45004 alert('end is not supported on xtype any more, use items');
45006 // //console.log('adding end');
45014 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45015 * option "monitorValid"
45017 startMonitoring : function(){
45020 Roo.TaskMgr.start({
45021 run : this.bindHandler,
45022 interval : this.monitorPoll || 200,
45029 * Stops monitoring of the valid state of this form
45031 stopMonitoring : function(){
45032 this.bound = false;
45036 bindHandler : function(){
45038 return false; // stops binding
45041 this.items.each(function(f){
45042 if(!f.isValid(true)){
45047 for(var i = 0, len = this.buttons.length; i < len; i++){
45048 var btn = this.buttons[i];
45049 if(btn.formBind === true && btn.disabled === valid){
45050 btn.setDisabled(!valid);
45053 this.fireEvent('clientvalidation', this, valid);
45067 Roo.Form = Roo.form.Form;
45070 * Ext JS Library 1.1.1
45071 * Copyright(c) 2006-2007, Ext JS, LLC.
45073 * Originally Released Under LGPL - original licence link has changed is not relivant.
45076 * <script type="text/javascript">
45079 // as we use this in bootstrap.
45080 Roo.namespace('Roo.form');
45082 * @class Roo.form.Action
45083 * Internal Class used to handle form actions
45085 * @param {Roo.form.BasicForm} el The form element or its id
45086 * @param {Object} config Configuration options
45091 // define the action interface
45092 Roo.form.Action = function(form, options){
45094 this.options = options || {};
45097 * Client Validation Failed
45100 Roo.form.Action.CLIENT_INVALID = 'client';
45102 * Server Validation Failed
45105 Roo.form.Action.SERVER_INVALID = 'server';
45107 * Connect to Server Failed
45110 Roo.form.Action.CONNECT_FAILURE = 'connect';
45112 * Reading Data from Server Failed
45115 Roo.form.Action.LOAD_FAILURE = 'load';
45117 Roo.form.Action.prototype = {
45119 failureType : undefined,
45120 response : undefined,
45121 result : undefined,
45123 // interface method
45124 run : function(options){
45128 // interface method
45129 success : function(response){
45133 // interface method
45134 handleResponse : function(response){
45138 // default connection failure
45139 failure : function(response){
45141 this.response = response;
45142 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45143 this.form.afterAction(this, false);
45146 processResponse : function(response){
45147 this.response = response;
45148 if(!response.responseText){
45151 this.result = this.handleResponse(response);
45152 return this.result;
45155 // utility functions used internally
45156 getUrl : function(appendParams){
45157 var url = this.options.url || this.form.url || this.form.el.dom.action;
45159 var p = this.getParams();
45161 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45167 getMethod : function(){
45168 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45171 getParams : function(){
45172 var bp = this.form.baseParams;
45173 var p = this.options.params;
45175 if(typeof p == "object"){
45176 p = Roo.urlEncode(Roo.applyIf(p, bp));
45177 }else if(typeof p == 'string' && bp){
45178 p += '&' + Roo.urlEncode(bp);
45181 p = Roo.urlEncode(bp);
45186 createCallback : function(){
45188 success: this.success,
45189 failure: this.failure,
45191 timeout: (this.form.timeout*1000),
45192 upload: this.form.fileUpload ? this.success : undefined
45197 Roo.form.Action.Submit = function(form, options){
45198 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45201 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45204 haveProgress : false,
45205 uploadComplete : false,
45207 // uploadProgress indicator.
45208 uploadProgress : function()
45210 if (!this.form.progressUrl) {
45214 if (!this.haveProgress) {
45215 Roo.MessageBox.progress("Uploading", "Uploading");
45217 if (this.uploadComplete) {
45218 Roo.MessageBox.hide();
45222 this.haveProgress = true;
45224 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45226 var c = new Roo.data.Connection();
45228 url : this.form.progressUrl,
45233 success : function(req){
45234 //console.log(data);
45238 rdata = Roo.decode(req.responseText)
45240 Roo.log("Invalid data from server..");
45244 if (!rdata || !rdata.success) {
45246 Roo.MessageBox.alert(Roo.encode(rdata));
45249 var data = rdata.data;
45251 if (this.uploadComplete) {
45252 Roo.MessageBox.hide();
45257 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45258 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45261 this.uploadProgress.defer(2000,this);
45264 failure: function(data) {
45265 Roo.log('progress url failed ');
45276 // run get Values on the form, so it syncs any secondary forms.
45277 this.form.getValues();
45279 var o = this.options;
45280 var method = this.getMethod();
45281 var isPost = method == 'POST';
45282 if(o.clientValidation === false || this.form.isValid()){
45284 if (this.form.progressUrl) {
45285 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45286 (new Date() * 1) + '' + Math.random());
45291 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45292 form:this.form.el.dom,
45293 url:this.getUrl(!isPost),
45295 params:isPost ? this.getParams() : null,
45296 isUpload: this.form.fileUpload
45299 this.uploadProgress();
45301 }else if (o.clientValidation !== false){ // client validation failed
45302 this.failureType = Roo.form.Action.CLIENT_INVALID;
45303 this.form.afterAction(this, false);
45307 success : function(response)
45309 this.uploadComplete= true;
45310 if (this.haveProgress) {
45311 Roo.MessageBox.hide();
45315 var result = this.processResponse(response);
45316 if(result === true || result.success){
45317 this.form.afterAction(this, true);
45321 this.form.markInvalid(result.errors);
45322 this.failureType = Roo.form.Action.SERVER_INVALID;
45324 this.form.afterAction(this, false);
45326 failure : function(response)
45328 this.uploadComplete= true;
45329 if (this.haveProgress) {
45330 Roo.MessageBox.hide();
45333 this.response = response;
45334 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45335 this.form.afterAction(this, false);
45338 handleResponse : function(response){
45339 if(this.form.errorReader){
45340 var rs = this.form.errorReader.read(response);
45343 for(var i = 0, len = rs.records.length; i < len; i++) {
45344 var r = rs.records[i];
45345 errors[i] = r.data;
45348 if(errors.length < 1){
45352 success : rs.success,
45358 ret = Roo.decode(response.responseText);
45362 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45372 Roo.form.Action.Load = function(form, options){
45373 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45374 this.reader = this.form.reader;
45377 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45382 Roo.Ajax.request(Roo.apply(
45383 this.createCallback(), {
45384 method:this.getMethod(),
45385 url:this.getUrl(false),
45386 params:this.getParams()
45390 success : function(response){
45392 var result = this.processResponse(response);
45393 if(result === true || !result.success || !result.data){
45394 this.failureType = Roo.form.Action.LOAD_FAILURE;
45395 this.form.afterAction(this, false);
45398 this.form.clearInvalid();
45399 this.form.setValues(result.data);
45400 this.form.afterAction(this, true);
45403 handleResponse : function(response){
45404 if(this.form.reader){
45405 var rs = this.form.reader.read(response);
45406 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45408 success : rs.success,
45412 return Roo.decode(response.responseText);
45416 Roo.form.Action.ACTION_TYPES = {
45417 'load' : Roo.form.Action.Load,
45418 'submit' : Roo.form.Action.Submit
45421 * Ext JS Library 1.1.1
45422 * Copyright(c) 2006-2007, Ext JS, LLC.
45424 * Originally Released Under LGPL - original licence link has changed is not relivant.
45427 * <script type="text/javascript">
45431 * @class Roo.form.Layout
45432 * @extends Roo.Component
45433 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45435 * @param {Object} config Configuration options
45437 Roo.form.Layout = function(config){
45439 if (config.items) {
45440 xitems = config.items;
45441 delete config.items;
45443 Roo.form.Layout.superclass.constructor.call(this, config);
45445 Roo.each(xitems, this.addxtype, this);
45449 Roo.extend(Roo.form.Layout, Roo.Component, {
45451 * @cfg {String/Object} autoCreate
45452 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45455 * @cfg {String/Object/Function} style
45456 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45457 * a function which returns such a specification.
45460 * @cfg {String} labelAlign
45461 * Valid values are "left," "top" and "right" (defaults to "left")
45464 * @cfg {Number} labelWidth
45465 * Fixed width in pixels of all field labels (defaults to undefined)
45468 * @cfg {Boolean} clear
45469 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45473 * @cfg {String} labelSeparator
45474 * The separator to use after field labels (defaults to ':')
45476 labelSeparator : ':',
45478 * @cfg {Boolean} hideLabels
45479 * True to suppress the display of field labels in this layout (defaults to false)
45481 hideLabels : false,
45484 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45489 onRender : function(ct, position){
45490 if(this.el){ // from markup
45491 this.el = Roo.get(this.el);
45492 }else { // generate
45493 var cfg = this.getAutoCreate();
45494 this.el = ct.createChild(cfg, position);
45497 this.el.applyStyles(this.style);
45499 if(this.labelAlign){
45500 this.el.addClass('x-form-label-'+this.labelAlign);
45502 if(this.hideLabels){
45503 this.labelStyle = "display:none";
45504 this.elementStyle = "padding-left:0;";
45506 if(typeof this.labelWidth == 'number'){
45507 this.labelStyle = "width:"+this.labelWidth+"px;";
45508 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45510 if(this.labelAlign == 'top'){
45511 this.labelStyle = "width:auto;";
45512 this.elementStyle = "padding-left:0;";
45515 var stack = this.stack;
45516 var slen = stack.length;
45518 if(!this.fieldTpl){
45519 var t = new Roo.Template(
45520 '<div class="x-form-item {5}">',
45521 '<label for="{0}" style="{2}">{1}{4}</label>',
45522 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45524 '</div><div class="x-form-clear-left"></div>'
45526 t.disableFormats = true;
45528 Roo.form.Layout.prototype.fieldTpl = t;
45530 for(var i = 0; i < slen; i++) {
45531 if(stack[i].isFormField){
45532 this.renderField(stack[i]);
45534 this.renderComponent(stack[i]);
45539 this.el.createChild({cls:'x-form-clear'});
45544 renderField : function(f){
45545 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45548 f.labelStyle||this.labelStyle||'', //2
45549 this.elementStyle||'', //3
45550 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45551 f.itemCls||this.itemCls||'' //5
45552 ], true).getPrevSibling());
45556 renderComponent : function(c){
45557 c.render(c.isLayout ? this.el : this.el.createChild());
45560 * Adds a object form elements (using the xtype property as the factory method.)
45561 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45562 * @param {Object} config
45564 addxtype : function(o)
45566 // create the lement.
45567 o.form = this.form;
45568 var fe = Roo.factory(o, Roo.form);
45569 this.form.allItems.push(fe);
45570 this.stack.push(fe);
45572 if (fe.isFormField) {
45573 this.form.items.add(fe);
45581 * @class Roo.form.Column
45582 * @extends Roo.form.Layout
45583 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45585 * @param {Object} config Configuration options
45587 Roo.form.Column = function(config){
45588 Roo.form.Column.superclass.constructor.call(this, config);
45591 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45593 * @cfg {Number/String} width
45594 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45597 * @cfg {String/Object} autoCreate
45598 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45602 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45605 onRender : function(ct, position){
45606 Roo.form.Column.superclass.onRender.call(this, ct, position);
45608 this.el.setWidth(this.width);
45615 * @class Roo.form.Row
45616 * @extends Roo.form.Layout
45617 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45619 * @param {Object} config Configuration options
45623 Roo.form.Row = function(config){
45624 Roo.form.Row.superclass.constructor.call(this, config);
45627 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45629 * @cfg {Number/String} width
45630 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45633 * @cfg {Number/String} height
45634 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45636 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45640 onRender : function(ct, position){
45641 //console.log('row render');
45643 var t = new Roo.Template(
45644 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45645 '<label for="{0}" style="{2}">{1}{4}</label>',
45646 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45650 t.disableFormats = true;
45652 Roo.form.Layout.prototype.rowTpl = t;
45654 this.fieldTpl = this.rowTpl;
45656 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45657 var labelWidth = 100;
45659 if ((this.labelAlign != 'top')) {
45660 if (typeof this.labelWidth == 'number') {
45661 labelWidth = this.labelWidth
45663 this.padWidth = 20 + labelWidth;
45667 Roo.form.Column.superclass.onRender.call(this, ct, position);
45669 this.el.setWidth(this.width);
45672 this.el.setHeight(this.height);
45677 renderField : function(f){
45678 f.fieldEl = this.fieldTpl.append(this.el, [
45679 f.id, f.fieldLabel,
45680 f.labelStyle||this.labelStyle||'',
45681 this.elementStyle||'',
45682 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45683 f.itemCls||this.itemCls||'',
45684 f.width ? f.width + this.padWidth : 160 + this.padWidth
45691 * @class Roo.form.FieldSet
45692 * @extends Roo.form.Layout
45693 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45695 * @param {Object} config Configuration options
45697 Roo.form.FieldSet = function(config){
45698 Roo.form.FieldSet.superclass.constructor.call(this, config);
45701 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45703 * @cfg {String} legend
45704 * The text to display as the legend for the FieldSet (defaults to '')
45707 * @cfg {String/Object} autoCreate
45708 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45712 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
45715 onRender : function(ct, position){
45716 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
45718 this.setLegend(this.legend);
45723 setLegend : function(text){
45725 this.el.child('legend').update(text);
45730 * Ext JS Library 1.1.1
45731 * Copyright(c) 2006-2007, Ext JS, LLC.
45733 * Originally Released Under LGPL - original licence link has changed is not relivant.
45736 * <script type="text/javascript">
45739 * @class Roo.form.VTypes
45740 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
45743 Roo.form.VTypes = function(){
45744 // closure these in so they are only created once.
45745 var alpha = /^[a-zA-Z_]+$/;
45746 var alphanum = /^[a-zA-Z0-9_]+$/;
45747 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
45748 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
45750 // All these messages and functions are configurable
45753 * The function used to validate email addresses
45754 * @param {String} value The email address
45756 'email' : function(v){
45757 return email.test(v);
45760 * The error text to display when the email validation function returns false
45763 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
45765 * The keystroke filter mask to be applied on email input
45768 'emailMask' : /[a-z0-9_\.\-@]/i,
45771 * The function used to validate URLs
45772 * @param {String} value The URL
45774 'url' : function(v){
45775 return url.test(v);
45778 * The error text to display when the url validation function returns false
45781 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
45784 * The function used to validate alpha values
45785 * @param {String} value The value
45787 'alpha' : function(v){
45788 return alpha.test(v);
45791 * The error text to display when the alpha validation function returns false
45794 'alphaText' : 'This field should only contain letters and _',
45796 * The keystroke filter mask to be applied on alpha input
45799 'alphaMask' : /[a-z_]/i,
45802 * The function used to validate alphanumeric values
45803 * @param {String} value The value
45805 'alphanum' : function(v){
45806 return alphanum.test(v);
45809 * The error text to display when the alphanumeric validation function returns false
45812 'alphanumText' : 'This field should only contain letters, numbers and _',
45814 * The keystroke filter mask to be applied on alphanumeric input
45817 'alphanumMask' : /[a-z0-9_]/i
45819 }();//<script type="text/javascript">
45822 * @class Roo.form.FCKeditor
45823 * @extends Roo.form.TextArea
45824 * Wrapper around the FCKEditor http://www.fckeditor.net
45826 * Creates a new FCKeditor
45827 * @param {Object} config Configuration options
45829 Roo.form.FCKeditor = function(config){
45830 Roo.form.FCKeditor.superclass.constructor.call(this, config);
45833 * @event editorinit
45834 * Fired when the editor is initialized - you can add extra handlers here..
45835 * @param {FCKeditor} this
45836 * @param {Object} the FCK object.
45843 Roo.form.FCKeditor.editors = { };
45844 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
45846 //defaultAutoCreate : {
45847 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
45851 * @cfg {Object} fck options - see fck manual for details.
45856 * @cfg {Object} fck toolbar set (Basic or Default)
45858 toolbarSet : 'Basic',
45860 * @cfg {Object} fck BasePath
45862 basePath : '/fckeditor/',
45870 onRender : function(ct, position)
45873 this.defaultAutoCreate = {
45875 style:"width:300px;height:60px;",
45876 autocomplete: "off"
45879 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
45882 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
45883 if(this.preventScrollbars){
45884 this.el.setStyle("overflow", "hidden");
45886 this.el.setHeight(this.growMin);
45889 //console.log('onrender' + this.getId() );
45890 Roo.form.FCKeditor.editors[this.getId()] = this;
45893 this.replaceTextarea() ;
45897 getEditor : function() {
45898 return this.fckEditor;
45901 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
45902 * @param {Mixed} value The value to set
45906 setValue : function(value)
45908 //console.log('setValue: ' + value);
45910 if(typeof(value) == 'undefined') { // not sure why this is happending...
45913 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45915 //if(!this.el || !this.getEditor()) {
45916 // this.value = value;
45917 //this.setValue.defer(100,this,[value]);
45921 if(!this.getEditor()) {
45925 this.getEditor().SetData(value);
45932 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
45933 * @return {Mixed} value The field value
45935 getValue : function()
45938 if (this.frame && this.frame.dom.style.display == 'none') {
45939 return Roo.form.FCKeditor.superclass.getValue.call(this);
45942 if(!this.el || !this.getEditor()) {
45944 // this.getValue.defer(100,this);
45949 var value=this.getEditor().GetData();
45950 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
45951 return Roo.form.FCKeditor.superclass.getValue.call(this);
45957 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
45958 * @return {Mixed} value The field value
45960 getRawValue : function()
45962 if (this.frame && this.frame.dom.style.display == 'none') {
45963 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45966 if(!this.el || !this.getEditor()) {
45967 //this.getRawValue.defer(100,this);
45974 var value=this.getEditor().GetData();
45975 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
45976 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
45980 setSize : function(w,h) {
45984 //if (this.frame && this.frame.dom.style.display == 'none') {
45985 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45988 //if(!this.el || !this.getEditor()) {
45989 // this.setSize.defer(100,this, [w,h]);
45995 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
45997 this.frame.dom.setAttribute('width', w);
45998 this.frame.dom.setAttribute('height', h);
45999 this.frame.setSize(w,h);
46003 toggleSourceEdit : function(value) {
46007 this.el.dom.style.display = value ? '' : 'none';
46008 this.frame.dom.style.display = value ? 'none' : '';
46013 focus: function(tag)
46015 if (this.frame.dom.style.display == 'none') {
46016 return Roo.form.FCKeditor.superclass.focus.call(this);
46018 if(!this.el || !this.getEditor()) {
46019 this.focus.defer(100,this, [tag]);
46026 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46027 this.getEditor().Focus();
46029 if (!this.getEditor().Selection.GetSelection()) {
46030 this.focus.defer(100,this, [tag]);
46035 var r = this.getEditor().EditorDocument.createRange();
46036 r.setStart(tgs[0],0);
46037 r.setEnd(tgs[0],0);
46038 this.getEditor().Selection.GetSelection().removeAllRanges();
46039 this.getEditor().Selection.GetSelection().addRange(r);
46040 this.getEditor().Focus();
46047 replaceTextarea : function()
46049 if ( document.getElementById( this.getId() + '___Frame' ) )
46051 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46053 // We must check the elements firstly using the Id and then the name.
46054 var oTextarea = document.getElementById( this.getId() );
46056 var colElementsByName = document.getElementsByName( this.getId() ) ;
46058 oTextarea.style.display = 'none' ;
46060 if ( oTextarea.tabIndex ) {
46061 this.TabIndex = oTextarea.tabIndex ;
46064 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46065 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46066 this.frame = Roo.get(this.getId() + '___Frame')
46069 _getConfigHtml : function()
46073 for ( var o in this.fckconfig ) {
46074 sConfig += sConfig.length > 0 ? '&' : '';
46075 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46078 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46082 _getIFrameHtml : function()
46084 var sFile = 'fckeditor.html' ;
46085 /* no idea what this is about..
46088 if ( (/fcksource=true/i).test( window.top.location.search ) )
46089 sFile = 'fckeditor.original.html' ;
46094 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46095 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46098 var html = '<iframe id="' + this.getId() +
46099 '___Frame" src="' + sLink +
46100 '" width="' + this.width +
46101 '" height="' + this.height + '"' +
46102 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46103 ' frameborder="0" scrolling="no"></iframe>' ;
46108 _insertHtmlBefore : function( html, element )
46110 if ( element.insertAdjacentHTML ) {
46112 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46114 var oRange = document.createRange() ;
46115 oRange.setStartBefore( element ) ;
46116 var oFragment = oRange.createContextualFragment( html );
46117 element.parentNode.insertBefore( oFragment, element ) ;
46130 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46132 function FCKeditor_OnComplete(editorInstance){
46133 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46134 f.fckEditor = editorInstance;
46135 //console.log("loaded");
46136 f.fireEvent('editorinit', f, editorInstance);
46156 //<script type="text/javascript">
46158 * @class Roo.form.GridField
46159 * @extends Roo.form.Field
46160 * Embed a grid (or editable grid into a form)
46163 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46165 * xgrid.store = Roo.data.Store
46166 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46167 * xgrid.store.reader = Roo.data.JsonReader
46171 * Creates a new GridField
46172 * @param {Object} config Configuration options
46174 Roo.form.GridField = function(config){
46175 Roo.form.GridField.superclass.constructor.call(this, config);
46179 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46181 * @cfg {Number} width - used to restrict width of grid..
46185 * @cfg {Number} height - used to restrict height of grid..
46189 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46195 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46196 * {tag: "input", type: "checkbox", autocomplete: "off"})
46198 // defaultAutoCreate : { tag: 'div' },
46199 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46201 * @cfg {String} addTitle Text to include for adding a title.
46205 onResize : function(){
46206 Roo.form.Field.superclass.onResize.apply(this, arguments);
46209 initEvents : function(){
46210 // Roo.form.Checkbox.superclass.initEvents.call(this);
46211 // has no events...
46216 getResizeEl : function(){
46220 getPositionEl : function(){
46225 onRender : function(ct, position){
46227 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46228 var style = this.style;
46231 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46232 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46233 this.viewEl = this.wrap.createChild({ tag: 'div' });
46235 this.viewEl.applyStyles(style);
46238 this.viewEl.setWidth(this.width);
46241 this.viewEl.setHeight(this.height);
46243 //if(this.inputValue !== undefined){
46244 //this.setValue(this.value);
46247 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46250 this.grid.render();
46251 this.grid.getDataSource().on('remove', this.refreshValue, this);
46252 this.grid.getDataSource().on('update', this.refreshValue, this);
46253 this.grid.on('afteredit', this.refreshValue, this);
46259 * Sets the value of the item.
46260 * @param {String} either an object or a string..
46262 setValue : function(v){
46264 v = v || []; // empty set..
46265 // this does not seem smart - it really only affects memoryproxy grids..
46266 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46267 var ds = this.grid.getDataSource();
46268 // assumes a json reader..
46270 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46271 ds.loadData( data);
46273 // clear selection so it does not get stale.
46274 if (this.grid.sm) {
46275 this.grid.sm.clearSelections();
46278 Roo.form.GridField.superclass.setValue.call(this, v);
46279 this.refreshValue();
46280 // should load data in the grid really....
46284 refreshValue: function() {
46286 this.grid.getDataSource().each(function(r) {
46289 this.el.dom.value = Roo.encode(val);
46297 * Ext JS Library 1.1.1
46298 * Copyright(c) 2006-2007, Ext JS, LLC.
46300 * Originally Released Under LGPL - original licence link has changed is not relivant.
46303 * <script type="text/javascript">
46306 * @class Roo.form.DisplayField
46307 * @extends Roo.form.Field
46308 * A generic Field to display non-editable data.
46310 * Creates a new Display Field item.
46311 * @param {Object} config Configuration options
46313 Roo.form.DisplayField = function(config){
46314 Roo.form.DisplayField.superclass.constructor.call(this, config);
46318 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46319 inputType: 'hidden',
46325 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46327 focusClass : undefined,
46329 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46331 fieldClass: 'x-form-field',
46334 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46336 valueRenderer: undefined,
46340 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46341 * {tag: "input", type: "checkbox", autocomplete: "off"})
46344 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46346 onResize : function(){
46347 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46351 initEvents : function(){
46352 // Roo.form.Checkbox.superclass.initEvents.call(this);
46353 // has no events...
46358 getResizeEl : function(){
46362 getPositionEl : function(){
46367 onRender : function(ct, position){
46369 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46370 //if(this.inputValue !== undefined){
46371 this.wrap = this.el.wrap();
46373 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46375 if (this.bodyStyle) {
46376 this.viewEl.applyStyles(this.bodyStyle);
46378 //this.viewEl.setStyle('padding', '2px');
46380 this.setValue(this.value);
46385 initValue : Roo.emptyFn,
46390 onClick : function(){
46395 * Sets the checked state of the checkbox.
46396 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46398 setValue : function(v){
46400 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46401 // this might be called before we have a dom element..
46402 if (!this.viewEl) {
46405 this.viewEl.dom.innerHTML = html;
46406 Roo.form.DisplayField.superclass.setValue.call(this, v);
46416 * @class Roo.form.DayPicker
46417 * @extends Roo.form.Field
46418 * A Day picker show [M] [T] [W] ....
46420 * Creates a new Day Picker
46421 * @param {Object} config Configuration options
46423 Roo.form.DayPicker= function(config){
46424 Roo.form.DayPicker.superclass.constructor.call(this, config);
46428 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46430 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46432 focusClass : undefined,
46434 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46436 fieldClass: "x-form-field",
46439 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46440 * {tag: "input", type: "checkbox", autocomplete: "off"})
46442 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46445 actionMode : 'viewEl',
46449 inputType : 'hidden',
46452 inputElement: false, // real input element?
46453 basedOn: false, // ????
46455 isFormField: true, // not sure where this is needed!!!!
46457 onResize : function(){
46458 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46459 if(!this.boxLabel){
46460 this.el.alignTo(this.wrap, 'c-c');
46464 initEvents : function(){
46465 Roo.form.Checkbox.superclass.initEvents.call(this);
46466 this.el.on("click", this.onClick, this);
46467 this.el.on("change", this.onClick, this);
46471 getResizeEl : function(){
46475 getPositionEl : function(){
46481 onRender : function(ct, position){
46482 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46484 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46486 var r1 = '<table><tr>';
46487 var r2 = '<tr class="x-form-daypick-icons">';
46488 for (var i=0; i < 7; i++) {
46489 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46490 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46493 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46494 viewEl.select('img').on('click', this.onClick, this);
46495 this.viewEl = viewEl;
46498 // this will not work on Chrome!!!
46499 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46500 this.el.on('propertychange', this.setFromHidden, this); //ie
46508 initValue : Roo.emptyFn,
46511 * Returns the checked state of the checkbox.
46512 * @return {Boolean} True if checked, else false
46514 getValue : function(){
46515 return this.el.dom.value;
46520 onClick : function(e){
46521 //this.setChecked(!this.checked);
46522 Roo.get(e.target).toggleClass('x-menu-item-checked');
46523 this.refreshValue();
46524 //if(this.el.dom.checked != this.checked){
46525 // this.setValue(this.el.dom.checked);
46530 refreshValue : function()
46533 this.viewEl.select('img',true).each(function(e,i,n) {
46534 val += e.is(".x-menu-item-checked") ? String(n) : '';
46536 this.setValue(val, true);
46540 * Sets the checked state of the checkbox.
46541 * On is always based on a string comparison between inputValue and the param.
46542 * @param {Boolean/String} value - the value to set
46543 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46545 setValue : function(v,suppressEvent){
46546 if (!this.el.dom) {
46549 var old = this.el.dom.value ;
46550 this.el.dom.value = v;
46551 if (suppressEvent) {
46555 // update display..
46556 this.viewEl.select('img',true).each(function(e,i,n) {
46558 var on = e.is(".x-menu-item-checked");
46559 var newv = v.indexOf(String(n)) > -1;
46561 e.toggleClass('x-menu-item-checked');
46567 this.fireEvent('change', this, v, old);
46572 // handle setting of hidden value by some other method!!?!?
46573 setFromHidden: function()
46578 //console.log("SET FROM HIDDEN");
46579 //alert('setFrom hidden');
46580 this.setValue(this.el.dom.value);
46583 onDestroy : function()
46586 Roo.get(this.viewEl).remove();
46589 Roo.form.DayPicker.superclass.onDestroy.call(this);
46593 * RooJS Library 1.1.1
46594 * Copyright(c) 2008-2011 Alan Knowles
46601 * @class Roo.form.ComboCheck
46602 * @extends Roo.form.ComboBox
46603 * A combobox for multiple select items.
46605 * FIXME - could do with a reset button..
46608 * Create a new ComboCheck
46609 * @param {Object} config Configuration options
46611 Roo.form.ComboCheck = function(config){
46612 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46613 // should verify some data...
46615 // hiddenName = required..
46616 // displayField = required
46617 // valudField == required
46618 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46620 Roo.each(req, function(e) {
46621 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46622 throw "Roo.form.ComboCheck : missing value for: " + e;
46629 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46634 selectedClass: 'x-menu-item-checked',
46637 onRender : function(ct, position){
46643 var cls = 'x-combo-list';
46646 this.tpl = new Roo.Template({
46647 html : '<div class="'+cls+'-item x-menu-check-item">' +
46648 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46649 '<span>{' + this.displayField + '}</span>' +
46656 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46657 this.view.singleSelect = false;
46658 this.view.multiSelect = true;
46659 this.view.toggleSelect = true;
46660 this.pageTb.add(new Roo.Toolbar.Fill(), {
46663 handler: function()
46670 onViewOver : function(e, t){
46676 onViewClick : function(doFocus,index){
46680 select: function () {
46681 //Roo.log("SELECT CALLED");
46684 selectByValue : function(xv, scrollIntoView){
46685 var ar = this.getValueArray();
46688 Roo.each(ar, function(v) {
46689 if(v === undefined || v === null){
46692 var r = this.findRecord(this.valueField, v);
46694 sels.push(this.store.indexOf(r))
46698 this.view.select(sels);
46704 onSelect : function(record, index){
46705 // Roo.log("onselect Called");
46706 // this is only called by the clear button now..
46707 this.view.clearSelections();
46708 this.setValue('[]');
46709 if (this.value != this.valueBefore) {
46710 this.fireEvent('change', this, this.value, this.valueBefore);
46711 this.valueBefore = this.value;
46714 getValueArray : function()
46719 //Roo.log(this.value);
46720 if (typeof(this.value) == 'undefined') {
46723 var ar = Roo.decode(this.value);
46724 return ar instanceof Array ? ar : []; //?? valid?
46727 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
46732 expand : function ()
46735 Roo.form.ComboCheck.superclass.expand.call(this);
46736 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
46737 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
46742 collapse : function(){
46743 Roo.form.ComboCheck.superclass.collapse.call(this);
46744 var sl = this.view.getSelectedIndexes();
46745 var st = this.store;
46749 Roo.each(sl, function(i) {
46751 nv.push(r.get(this.valueField));
46753 this.setValue(Roo.encode(nv));
46754 if (this.value != this.valueBefore) {
46756 this.fireEvent('change', this, this.value, this.valueBefore);
46757 this.valueBefore = this.value;
46762 setValue : function(v){
46766 var vals = this.getValueArray();
46768 Roo.each(vals, function(k) {
46769 var r = this.findRecord(this.valueField, k);
46771 tv.push(r.data[this.displayField]);
46772 }else if(this.valueNotFoundText !== undefined){
46773 tv.push( this.valueNotFoundText );
46778 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
46779 this.hiddenField.value = v;
46785 * Ext JS Library 1.1.1
46786 * Copyright(c) 2006-2007, Ext JS, LLC.
46788 * Originally Released Under LGPL - original licence link has changed is not relivant.
46791 * <script type="text/javascript">
46795 * @class Roo.form.Signature
46796 * @extends Roo.form.Field
46800 * @param {Object} config Configuration options
46803 Roo.form.Signature = function(config){
46804 Roo.form.Signature.superclass.constructor.call(this, config);
46806 this.addEvents({// not in used??
46809 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
46810 * @param {Roo.form.Signature} combo This combo box
46815 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
46816 * @param {Roo.form.ComboBox} combo This combo box
46817 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
46823 Roo.extend(Roo.form.Signature, Roo.form.Field, {
46825 * @cfg {Object} labels Label to use when rendering a form.
46829 * confirm : "Confirm"
46834 confirm : "Confirm"
46837 * @cfg {Number} width The signature panel width (defaults to 300)
46841 * @cfg {Number} height The signature panel height (defaults to 100)
46845 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
46847 allowBlank : false,
46850 // {Object} signPanel The signature SVG panel element (defaults to {})
46852 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
46853 isMouseDown : false,
46854 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
46855 isConfirmed : false,
46856 // {String} signatureTmp SVG mapping string (defaults to empty string)
46860 defaultAutoCreate : { // modified by initCompnoent..
46866 onRender : function(ct, position){
46868 Roo.form.Signature.superclass.onRender.call(this, ct, position);
46870 this.wrap = this.el.wrap({
46871 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
46874 this.createToolbar(this);
46875 this.signPanel = this.wrap.createChild({
46877 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
46881 this.svgID = Roo.id();
46882 this.svgEl = this.signPanel.createChild({
46883 xmlns : 'http://www.w3.org/2000/svg',
46885 id : this.svgID + "-svg",
46887 height: this.height,
46888 viewBox: '0 0 '+this.width+' '+this.height,
46892 id: this.svgID + "-svg-r",
46894 height: this.height,
46899 id: this.svgID + "-svg-l",
46901 y1: (this.height*0.8), // start set the line in 80% of height
46902 x2: this.width, // end
46903 y2: (this.height*0.8), // end set the line in 80% of height
46905 'stroke-width': "1",
46906 'stroke-dasharray': "3",
46907 'shape-rendering': "crispEdges",
46908 'pointer-events': "none"
46912 id: this.svgID + "-svg-p",
46914 'stroke-width': "3",
46916 'pointer-events': 'none'
46921 this.svgBox = this.svgEl.dom.getScreenCTM();
46923 createSVG : function(){
46924 var svg = this.signPanel;
46925 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
46928 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
46929 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
46930 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
46931 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
46932 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
46933 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
46934 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
46937 isTouchEvent : function(e){
46938 return e.type.match(/^touch/);
46940 getCoords : function (e) {
46941 var pt = this.svgEl.dom.createSVGPoint();
46944 if (this.isTouchEvent(e)) {
46945 pt.x = e.targetTouches[0].clientX
46946 pt.y = e.targetTouches[0].clientY;
46948 var a = this.svgEl.dom.getScreenCTM();
46949 var b = a.inverse();
46950 var mx = pt.matrixTransform(b);
46951 return mx.x + ',' + mx.y;
46953 //mouse event headler
46954 down : function (e) {
46955 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
46956 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
46958 this.isMouseDown = true;
46960 e.preventDefault();
46962 move : function (e) {
46963 if (this.isMouseDown) {
46964 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
46965 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
46968 e.preventDefault();
46970 up : function (e) {
46971 this.isMouseDown = false;
46972 var sp = this.signatureTmp.split(' ');
46975 if(!sp[sp.length-2].match(/^L/)){
46979 this.signatureTmp = sp.join(" ");
46982 if(this.getValue() != this.signatureTmp){
46983 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
46984 this.isConfirmed = false;
46986 e.preventDefault();
46990 * Protected method that will not generally be called directly. It
46991 * is called when the editor creates its toolbar. Override this method if you need to
46992 * add custom toolbar buttons.
46993 * @param {HtmlEditor} editor
46995 createToolbar : function(editor){
46996 function btn(id, toggle, handler){
46997 var xid = fid + '-'+ id ;
47001 cls : 'x-btn-icon x-edit-'+id,
47002 enableToggle:toggle !== false,
47003 scope: editor, // was editor...
47004 handler:handler||editor.relayBtnCmd,
47005 clickEvent:'mousedown',
47006 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47012 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47016 cls : ' x-signature-btn x-signature-'+id,
47017 scope: editor, // was editor...
47018 handler: this.reset,
47019 clickEvent:'mousedown',
47020 text: this.labels.clear
47027 cls : ' x-signature-btn x-signature-'+id,
47028 scope: editor, // was editor...
47029 handler: this.confirmHandler,
47030 clickEvent:'mousedown',
47031 text: this.labels.confirm
47038 * when user is clicked confirm then show this image.....
47040 * @return {String} Image Data URI
47042 getImageDataURI : function(){
47043 var svg = this.svgEl.dom.parentNode.innerHTML;
47044 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47049 * @return {Boolean} this.isConfirmed
47051 getConfirmed : function(){
47052 return this.isConfirmed;
47056 * @return {Number} this.width
47058 getWidth : function(){
47063 * @return {Number} this.height
47065 getHeight : function(){
47066 return this.height;
47069 getSignature : function(){
47070 return this.signatureTmp;
47073 reset : function(){
47074 this.signatureTmp = '';
47075 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47076 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47077 this.isConfirmed = false;
47078 Roo.form.Signature.superclass.reset.call(this);
47080 setSignature : function(s){
47081 this.signatureTmp = s;
47082 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47083 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47085 this.isConfirmed = false;
47086 Roo.form.Signature.superclass.reset.call(this);
47089 // Roo.log(this.signPanel.dom.contentWindow.up())
47092 setConfirmed : function(){
47096 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47099 confirmHandler : function(){
47100 if(!this.getSignature()){
47104 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47105 this.setValue(this.getSignature());
47106 this.isConfirmed = true;
47108 this.fireEvent('confirm', this);
47111 // Subclasses should provide the validation implementation by overriding this
47112 validateValue : function(value){
47113 if(this.allowBlank){
47117 if(this.isConfirmed){
47124 * Ext JS Library 1.1.1
47125 * Copyright(c) 2006-2007, Ext JS, LLC.
47127 * Originally Released Under LGPL - original licence link has changed is not relivant.
47130 * <script type="text/javascript">
47135 * @class Roo.form.ComboBox
47136 * @extends Roo.form.TriggerField
47137 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47139 * Create a new ComboBox.
47140 * @param {Object} config Configuration options
47142 Roo.form.Select = function(config){
47143 Roo.form.Select.superclass.constructor.call(this, config);
47147 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47149 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47152 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47153 * rendering into an Roo.Editor, defaults to false)
47156 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47157 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47160 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47163 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47164 * the dropdown list (defaults to undefined, with no header element)
47168 * @cfg {String/Roo.Template} tpl The template to use to render the output
47172 defaultAutoCreate : {tag: "select" },
47174 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47176 listWidth: undefined,
47178 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47179 * mode = 'remote' or 'text' if mode = 'local')
47181 displayField: undefined,
47183 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47184 * mode = 'remote' or 'value' if mode = 'local').
47185 * Note: use of a valueField requires the user make a selection
47186 * in order for a value to be mapped.
47188 valueField: undefined,
47192 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47193 * field's data value (defaults to the underlying DOM element's name)
47195 hiddenName: undefined,
47197 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47201 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47203 selectedClass: 'x-combo-selected',
47205 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47206 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47207 * which displays a downward arrow icon).
47209 triggerClass : 'x-form-arrow-trigger',
47211 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47215 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47216 * anchor positions (defaults to 'tl-bl')
47218 listAlign: 'tl-bl?',
47220 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47224 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47225 * query specified by the allQuery config option (defaults to 'query')
47227 triggerAction: 'query',
47229 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47230 * (defaults to 4, does not apply if editable = false)
47234 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47235 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47239 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47240 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47244 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47245 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47249 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47250 * when editable = true (defaults to false)
47252 selectOnFocus:false,
47254 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47256 queryParam: 'query',
47258 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47259 * when mode = 'remote' (defaults to 'Loading...')
47261 loadingText: 'Loading...',
47263 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47267 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47271 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47272 * traditional select (defaults to true)
47276 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47280 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47284 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47285 * listWidth has a higher value)
47289 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47290 * allow the user to set arbitrary text into the field (defaults to false)
47292 forceSelection:false,
47294 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47295 * if typeAhead = true (defaults to 250)
47297 typeAheadDelay : 250,
47299 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47300 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47302 valueNotFoundText : undefined,
47305 * @cfg {String} defaultValue The value displayed after loading the store.
47310 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47312 blockFocus : false,
47315 * @cfg {Boolean} disableClear Disable showing of clear button.
47317 disableClear : false,
47319 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47321 alwaysQuery : false,
47327 // element that contains real text value.. (when hidden is used..)
47330 onRender : function(ct, position){
47331 Roo.form.Field.prototype.onRender.call(this, ct, position);
47334 this.store.on('beforeload', this.onBeforeLoad, this);
47335 this.store.on('load', this.onLoad, this);
47336 this.store.on('loadexception', this.onLoadException, this);
47337 this.store.load({});
47345 initEvents : function(){
47346 //Roo.form.ComboBox.superclass.initEvents.call(this);
47350 onDestroy : function(){
47353 this.store.un('beforeload', this.onBeforeLoad, this);
47354 this.store.un('load', this.onLoad, this);
47355 this.store.un('loadexception', this.onLoadException, this);
47357 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47361 fireKey : function(e){
47362 if(e.isNavKeyPress() && !this.list.isVisible()){
47363 this.fireEvent("specialkey", this, e);
47368 onResize: function(w, h){
47376 * Allow or prevent the user from directly editing the field text. If false is passed,
47377 * the user will only be able to select from the items defined in the dropdown list. This method
47378 * is the runtime equivalent of setting the 'editable' config option at config time.
47379 * @param {Boolean} value True to allow the user to directly edit the field text
47381 setEditable : function(value){
47386 onBeforeLoad : function(){
47388 Roo.log("Select before load");
47391 this.innerList.update(this.loadingText ?
47392 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47393 //this.restrictHeight();
47394 this.selectedIndex = -1;
47398 onLoad : function(){
47401 var dom = this.el.dom;
47402 dom.innerHTML = '';
47403 var od = dom.ownerDocument;
47405 if (this.emptyText) {
47406 var op = od.createElement('option');
47407 op.setAttribute('value', '');
47408 op.innerHTML = String.format('{0}', this.emptyText);
47409 dom.appendChild(op);
47411 if(this.store.getCount() > 0){
47413 var vf = this.valueField;
47414 var df = this.displayField;
47415 this.store.data.each(function(r) {
47416 // which colmsn to use... testing - cdoe / title..
47417 var op = od.createElement('option');
47418 op.setAttribute('value', r.data[vf]);
47419 op.innerHTML = String.format('{0}', r.data[df]);
47420 dom.appendChild(op);
47422 if (typeof(this.defaultValue != 'undefined')) {
47423 this.setValue(this.defaultValue);
47428 //this.onEmptyResults();
47433 onLoadException : function()
47435 dom.innerHTML = '';
47437 Roo.log("Select on load exception");
47441 Roo.log(this.store.reader.jsonData);
47442 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47443 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47449 onTypeAhead : function(){
47454 onSelect : function(record, index){
47455 Roo.log('on select?');
47457 if(this.fireEvent('beforeselect', this, record, index) !== false){
47458 this.setFromData(index > -1 ? record.data : false);
47460 this.fireEvent('select', this, record, index);
47465 * Returns the currently selected field value or empty string if no value is set.
47466 * @return {String} value The selected value
47468 getValue : function(){
47469 var dom = this.el.dom;
47470 this.value = dom.options[dom.selectedIndex].value;
47476 * Clears any text/value currently set in the field
47478 clearValue : function(){
47480 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47485 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47486 * will be displayed in the field. If the value does not match the data value of an existing item,
47487 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47488 * Otherwise the field will be blank (although the value will still be set).
47489 * @param {String} value The value to match
47491 setValue : function(v){
47492 var d = this.el.dom;
47493 for (var i =0; i < d.options.length;i++) {
47494 if (v == d.options[i].value) {
47495 d.selectedIndex = i;
47503 * @property {Object} the last set data for the element
47508 * Sets the value of the field based on a object which is related to the record format for the store.
47509 * @param {Object} value the value to set as. or false on reset?
47511 setFromData : function(o){
47512 Roo.log('setfrom data?');
47518 reset : function(){
47522 findRecord : function(prop, value){
47527 if(this.store.getCount() > 0){
47528 this.store.each(function(r){
47529 if(r.data[prop] == value){
47539 getName: function()
47541 // returns hidden if it's set..
47542 if (!this.rendered) {return ''};
47543 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47551 onEmptyResults : function(){
47552 Roo.log('empty results');
47557 * Returns true if the dropdown list is expanded, else false.
47559 isExpanded : function(){
47564 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47565 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47566 * @param {String} value The data value of the item to select
47567 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47568 * selected item if it is not currently in view (defaults to true)
47569 * @return {Boolean} True if the value matched an item in the list, else false
47571 selectByValue : function(v, scrollIntoView){
47572 Roo.log('select By Value');
47575 if(v !== undefined && v !== null){
47576 var r = this.findRecord(this.valueField || this.displayField, v);
47578 this.select(this.store.indexOf(r), scrollIntoView);
47586 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47587 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47588 * @param {Number} index The zero-based index of the list item to select
47589 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47590 * selected item if it is not currently in view (defaults to true)
47592 select : function(index, scrollIntoView){
47593 Roo.log('select ');
47596 this.selectedIndex = index;
47597 this.view.select(index);
47598 if(scrollIntoView !== false){
47599 var el = this.view.getNode(index);
47601 this.innerList.scrollChildIntoView(el, false);
47609 validateBlur : function(){
47616 initQuery : function(){
47617 this.doQuery(this.getRawValue());
47621 doForce : function(){
47622 if(this.el.dom.value.length > 0){
47623 this.el.dom.value =
47624 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47630 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47631 * query allowing the query action to be canceled if needed.
47632 * @param {String} query The SQL query to execute
47633 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47634 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47635 * saved in the current store (defaults to false)
47637 doQuery : function(q, forceAll){
47639 Roo.log('doQuery?');
47640 if(q === undefined || q === null){
47645 forceAll: forceAll,
47649 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47653 forceAll = qe.forceAll;
47654 if(forceAll === true || (q.length >= this.minChars)){
47655 if(this.lastQuery != q || this.alwaysQuery){
47656 this.lastQuery = q;
47657 if(this.mode == 'local'){
47658 this.selectedIndex = -1;
47660 this.store.clearFilter();
47662 this.store.filter(this.displayField, q);
47666 this.store.baseParams[this.queryParam] = q;
47668 params: this.getParams(q)
47673 this.selectedIndex = -1;
47680 getParams : function(q){
47682 //p[this.queryParam] = q;
47685 p.limit = this.pageSize;
47691 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47693 collapse : function(){
47698 collapseIf : function(e){
47703 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47705 expand : function(){
47713 * @cfg {Boolean} grow
47717 * @cfg {Number} growMin
47721 * @cfg {Number} growMax
47729 setWidth : function()
47733 getResizeEl : function(){
47736 });//<script type="text/javasscript">
47740 * @class Roo.DDView
47741 * A DnD enabled version of Roo.View.
47742 * @param {Element/String} container The Element in which to create the View.
47743 * @param {String} tpl The template string used to create the markup for each element of the View
47744 * @param {Object} config The configuration properties. These include all the config options of
47745 * {@link Roo.View} plus some specific to this class.<br>
47747 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
47748 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
47750 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
47751 .x-view-drag-insert-above {
47752 border-top:1px dotted #3366cc;
47754 .x-view-drag-insert-below {
47755 border-bottom:1px dotted #3366cc;
47761 Roo.DDView = function(container, tpl, config) {
47762 Roo.DDView.superclass.constructor.apply(this, arguments);
47763 this.getEl().setStyle("outline", "0px none");
47764 this.getEl().unselectable();
47765 if (this.dragGroup) {
47766 this.setDraggable(this.dragGroup.split(","));
47768 if (this.dropGroup) {
47769 this.setDroppable(this.dropGroup.split(","));
47771 if (this.deletable) {
47772 this.setDeletable();
47774 this.isDirtyFlag = false;
47780 Roo.extend(Roo.DDView, Roo.View, {
47781 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
47782 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
47783 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
47784 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
47788 reset: Roo.emptyFn,
47790 clearInvalid: Roo.form.Field.prototype.clearInvalid,
47792 validate: function() {
47796 destroy: function() {
47797 this.purgeListeners();
47798 this.getEl.removeAllListeners();
47799 this.getEl().remove();
47800 if (this.dragZone) {
47801 if (this.dragZone.destroy) {
47802 this.dragZone.destroy();
47805 if (this.dropZone) {
47806 if (this.dropZone.destroy) {
47807 this.dropZone.destroy();
47812 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
47813 getName: function() {
47817 /** Loads the View from a JSON string representing the Records to put into the Store. */
47818 setValue: function(v) {
47820 throw "DDView.setValue(). DDView must be constructed with a valid Store";
47823 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
47824 this.store.proxy = new Roo.data.MemoryProxy(data);
47828 /** @return {String} a parenthesised list of the ids of the Records in the View. */
47829 getValue: function() {
47831 this.store.each(function(rec) {
47832 result += rec.id + ',';
47834 return result.substr(0, result.length - 1) + ')';
47837 getIds: function() {
47838 var i = 0, result = new Array(this.store.getCount());
47839 this.store.each(function(rec) {
47840 result[i++] = rec.id;
47845 isDirty: function() {
47846 return this.isDirtyFlag;
47850 * Part of the Roo.dd.DropZone interface. If no target node is found, the
47851 * whole Element becomes the target, and this causes the drop gesture to append.
47853 getTargetFromEvent : function(e) {
47854 var target = e.getTarget();
47855 while ((target !== null) && (target.parentNode != this.el.dom)) {
47856 target = target.parentNode;
47859 target = this.el.dom.lastChild || this.el.dom;
47865 * Create the drag data which consists of an object which has the property "ddel" as
47866 * the drag proxy element.
47868 getDragData : function(e) {
47869 var target = this.findItemFromChild(e.getTarget());
47871 this.handleSelection(e);
47872 var selNodes = this.getSelectedNodes();
47875 copy: this.copy || (this.allowCopy && e.ctrlKey),
47879 var selectedIndices = this.getSelectedIndexes();
47880 for (var i = 0; i < selectedIndices.length; i++) {
47881 dragData.records.push(this.store.getAt(selectedIndices[i]));
47883 if (selNodes.length == 1) {
47884 dragData.ddel = target.cloneNode(true); // the div element
47886 var div = document.createElement('div'); // create the multi element drag "ghost"
47887 div.className = 'multi-proxy';
47888 for (var i = 0, len = selNodes.length; i < len; i++) {
47889 div.appendChild(selNodes[i].cloneNode(true));
47891 dragData.ddel = div;
47893 //console.log(dragData)
47894 //console.log(dragData.ddel.innerHTML)
47897 //console.log('nodragData')
47901 /** Specify to which ddGroup items in this DDView may be dragged. */
47902 setDraggable: function(ddGroup) {
47903 if (ddGroup instanceof Array) {
47904 Roo.each(ddGroup, this.setDraggable, this);
47907 if (this.dragZone) {
47908 this.dragZone.addToGroup(ddGroup);
47910 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
47911 containerScroll: true,
47915 // Draggability implies selection. DragZone's mousedown selects the element.
47916 if (!this.multiSelect) { this.singleSelect = true; }
47918 // Wire the DragZone's handlers up to methods in *this*
47919 this.dragZone.getDragData = this.getDragData.createDelegate(this);
47923 /** Specify from which ddGroup this DDView accepts drops. */
47924 setDroppable: function(ddGroup) {
47925 if (ddGroup instanceof Array) {
47926 Roo.each(ddGroup, this.setDroppable, this);
47929 if (this.dropZone) {
47930 this.dropZone.addToGroup(ddGroup);
47932 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
47933 containerScroll: true,
47937 // Wire the DropZone's handlers up to methods in *this*
47938 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
47939 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
47940 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
47941 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
47942 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
47946 /** Decide whether to drop above or below a View node. */
47947 getDropPoint : function(e, n, dd){
47948 if (n == this.el.dom) { return "above"; }
47949 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
47950 var c = t + (b - t) / 2;
47951 var y = Roo.lib.Event.getPageY(e);
47959 onNodeEnter : function(n, dd, e, data){
47963 onNodeOver : function(n, dd, e, data){
47964 var pt = this.getDropPoint(e, n, dd);
47965 // set the insert point style on the target node
47966 var dragElClass = this.dropNotAllowed;
47969 if (pt == "above"){
47970 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
47971 targetElClass = "x-view-drag-insert-above";
47973 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
47974 targetElClass = "x-view-drag-insert-below";
47976 if (this.lastInsertClass != targetElClass){
47977 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
47978 this.lastInsertClass = targetElClass;
47981 return dragElClass;
47984 onNodeOut : function(n, dd, e, data){
47985 this.removeDropIndicators(n);
47988 onNodeDrop : function(n, dd, e, data){
47989 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
47992 var pt = this.getDropPoint(e, n, dd);
47993 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
47994 if (pt == "below") { insertAt++; }
47995 for (var i = 0; i < data.records.length; i++) {
47996 var r = data.records[i];
47997 var dup = this.store.getById(r.id);
47998 if (dup && (dd != this.dragZone)) {
47999 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48002 this.store.insert(insertAt++, r.copy());
48004 data.source.isDirtyFlag = true;
48006 this.store.insert(insertAt++, r);
48008 this.isDirtyFlag = true;
48011 this.dragZone.cachedTarget = null;
48015 removeDropIndicators : function(n){
48017 Roo.fly(n).removeClass([
48018 "x-view-drag-insert-above",
48019 "x-view-drag-insert-below"]);
48020 this.lastInsertClass = "_noclass";
48025 * Utility method. Add a delete option to the DDView's context menu.
48026 * @param {String} imageUrl The URL of the "delete" icon image.
48028 setDeletable: function(imageUrl) {
48029 if (!this.singleSelect && !this.multiSelect) {
48030 this.singleSelect = true;
48032 var c = this.getContextMenu();
48033 this.contextMenu.on("itemclick", function(item) {
48036 this.remove(this.getSelectedIndexes());
48040 this.contextMenu.add({
48047 /** Return the context menu for this DDView. */
48048 getContextMenu: function() {
48049 if (!this.contextMenu) {
48050 // Create the View's context menu
48051 this.contextMenu = new Roo.menu.Menu({
48052 id: this.id + "-contextmenu"
48054 this.el.on("contextmenu", this.showContextMenu, this);
48056 return this.contextMenu;
48059 disableContextMenu: function() {
48060 if (this.contextMenu) {
48061 this.el.un("contextmenu", this.showContextMenu, this);
48065 showContextMenu: function(e, item) {
48066 item = this.findItemFromChild(e.getTarget());
48069 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48070 this.contextMenu.showAt(e.getXY());
48075 * Remove {@link Roo.data.Record}s at the specified indices.
48076 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48078 remove: function(selectedIndices) {
48079 selectedIndices = [].concat(selectedIndices);
48080 for (var i = 0; i < selectedIndices.length; i++) {
48081 var rec = this.store.getAt(selectedIndices[i]);
48082 this.store.remove(rec);
48087 * Double click fires the event, but also, if this is draggable, and there is only one other
48088 * related DropZone, it transfers the selected node.
48090 onDblClick : function(e){
48091 var item = this.findItemFromChild(e.getTarget());
48093 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48096 if (this.dragGroup) {
48097 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48098 while (targets.indexOf(this.dropZone) > -1) {
48099 targets.remove(this.dropZone);
48101 if (targets.length == 1) {
48102 this.dragZone.cachedTarget = null;
48103 var el = Roo.get(targets[0].getEl());
48104 var box = el.getBox(true);
48105 targets[0].onNodeDrop(el.dom, {
48107 xy: [box.x, box.y + box.height - 1]
48108 }, null, this.getDragData(e));
48114 handleSelection: function(e) {
48115 this.dragZone.cachedTarget = null;
48116 var item = this.findItemFromChild(e.getTarget());
48118 this.clearSelections(true);
48121 if (item && (this.multiSelect || this.singleSelect)){
48122 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48123 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48124 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48125 this.unselect(item);
48127 this.select(item, this.multiSelect && e.ctrlKey);
48128 this.lastSelection = item;
48133 onItemClick : function(item, index, e){
48134 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48140 unselect : function(nodeInfo, suppressEvent){
48141 var node = this.getNode(nodeInfo);
48142 if(node && this.isSelected(node)){
48143 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48144 Roo.fly(node).removeClass(this.selectedClass);
48145 this.selections.remove(node);
48146 if(!suppressEvent){
48147 this.fireEvent("selectionchange", this, this.selections);
48155 * Ext JS Library 1.1.1
48156 * Copyright(c) 2006-2007, Ext JS, LLC.
48158 * Originally Released Under LGPL - original licence link has changed is not relivant.
48161 * <script type="text/javascript">
48165 * @class Roo.LayoutManager
48166 * @extends Roo.util.Observable
48167 * Base class for layout managers.
48169 Roo.LayoutManager = function(container, config){
48170 Roo.LayoutManager.superclass.constructor.call(this);
48171 this.el = Roo.get(container);
48172 // ie scrollbar fix
48173 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48174 document.body.scroll = "no";
48175 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48176 this.el.position('relative');
48178 this.id = this.el.id;
48179 this.el.addClass("x-layout-container");
48180 /** false to disable window resize monitoring @type Boolean */
48181 this.monitorWindowResize = true;
48186 * Fires when a layout is performed.
48187 * @param {Roo.LayoutManager} this
48191 * @event regionresized
48192 * Fires when the user resizes a region.
48193 * @param {Roo.LayoutRegion} region The resized region
48194 * @param {Number} newSize The new size (width for east/west, height for north/south)
48196 "regionresized" : true,
48198 * @event regioncollapsed
48199 * Fires when a region is collapsed.
48200 * @param {Roo.LayoutRegion} region The collapsed region
48202 "regioncollapsed" : true,
48204 * @event regionexpanded
48205 * Fires when a region is expanded.
48206 * @param {Roo.LayoutRegion} region The expanded region
48208 "regionexpanded" : true
48210 this.updating = false;
48211 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48214 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48216 * Returns true if this layout is currently being updated
48217 * @return {Boolean}
48219 isUpdating : function(){
48220 return this.updating;
48224 * Suspend the LayoutManager from doing auto-layouts while
48225 * making multiple add or remove calls
48227 beginUpdate : function(){
48228 this.updating = true;
48232 * Restore auto-layouts and optionally disable the manager from performing a layout
48233 * @param {Boolean} noLayout true to disable a layout update
48235 endUpdate : function(noLayout){
48236 this.updating = false;
48242 layout: function(){
48246 onRegionResized : function(region, newSize){
48247 this.fireEvent("regionresized", region, newSize);
48251 onRegionCollapsed : function(region){
48252 this.fireEvent("regioncollapsed", region);
48255 onRegionExpanded : function(region){
48256 this.fireEvent("regionexpanded", region);
48260 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48261 * performs box-model adjustments.
48262 * @return {Object} The size as an object {width: (the width), height: (the height)}
48264 getViewSize : function(){
48266 if(this.el.dom != document.body){
48267 size = this.el.getSize();
48269 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48271 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48272 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48277 * Returns the Element this layout is bound to.
48278 * @return {Roo.Element}
48280 getEl : function(){
48285 * Returns the specified region.
48286 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48287 * @return {Roo.LayoutRegion}
48289 getRegion : function(target){
48290 return this.regions[target.toLowerCase()];
48293 onWindowResize : function(){
48294 if(this.monitorWindowResize){
48300 * Ext JS Library 1.1.1
48301 * Copyright(c) 2006-2007, Ext JS, LLC.
48303 * Originally Released Under LGPL - original licence link has changed is not relivant.
48306 * <script type="text/javascript">
48309 * @class Roo.BorderLayout
48310 * @extends Roo.LayoutManager
48311 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48312 * please see: <br><br>
48313 * <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>
48314 * <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>
48317 var layout = new Roo.BorderLayout(document.body, {
48351 preferredTabWidth: 150
48356 var CP = Roo.ContentPanel;
48358 layout.beginUpdate();
48359 layout.add("north", new CP("north", "North"));
48360 layout.add("south", new CP("south", {title: "South", closable: true}));
48361 layout.add("west", new CP("west", {title: "West"}));
48362 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48363 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48364 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48365 layout.getRegion("center").showPanel("center1");
48366 layout.endUpdate();
48369 <b>The container the layout is rendered into can be either the body element or any other element.
48370 If it is not the body element, the container needs to either be an absolute positioned element,
48371 or you will need to add "position:relative" to the css of the container. You will also need to specify
48372 the container size if it is not the body element.</b>
48375 * Create a new BorderLayout
48376 * @param {String/HTMLElement/Element} container The container this layout is bound to
48377 * @param {Object} config Configuration options
48379 Roo.BorderLayout = function(container, config){
48380 config = config || {};
48381 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48382 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48383 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48384 var target = this.factory.validRegions[i];
48385 if(config[target]){
48386 this.addRegion(target, config[target]);
48391 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48393 * Creates and adds a new region if it doesn't already exist.
48394 * @param {String} target The target region key (north, south, east, west or center).
48395 * @param {Object} config The regions config object
48396 * @return {BorderLayoutRegion} The new region
48398 addRegion : function(target, config){
48399 if(!this.regions[target]){
48400 var r = this.factory.create(target, this, config);
48401 this.bindRegion(target, r);
48403 return this.regions[target];
48407 bindRegion : function(name, r){
48408 this.regions[name] = r;
48409 r.on("visibilitychange", this.layout, this);
48410 r.on("paneladded", this.layout, this);
48411 r.on("panelremoved", this.layout, this);
48412 r.on("invalidated", this.layout, this);
48413 r.on("resized", this.onRegionResized, this);
48414 r.on("collapsed", this.onRegionCollapsed, this);
48415 r.on("expanded", this.onRegionExpanded, this);
48419 * Performs a layout update.
48421 layout : function(){
48422 if(this.updating) return;
48423 var size = this.getViewSize();
48424 var w = size.width;
48425 var h = size.height;
48430 //var x = 0, y = 0;
48432 var rs = this.regions;
48433 var north = rs["north"];
48434 var south = rs["south"];
48435 var west = rs["west"];
48436 var east = rs["east"];
48437 var center = rs["center"];
48438 //if(this.hideOnLayout){ // not supported anymore
48439 //c.el.setStyle("display", "none");
48441 if(north && north.isVisible()){
48442 var b = north.getBox();
48443 var m = north.getMargins();
48444 b.width = w - (m.left+m.right);
48447 centerY = b.height + b.y + m.bottom;
48448 centerH -= centerY;
48449 north.updateBox(this.safeBox(b));
48451 if(south && south.isVisible()){
48452 var b = south.getBox();
48453 var m = south.getMargins();
48454 b.width = w - (m.left+m.right);
48456 var totalHeight = (b.height + m.top + m.bottom);
48457 b.y = h - totalHeight + m.top;
48458 centerH -= totalHeight;
48459 south.updateBox(this.safeBox(b));
48461 if(west && west.isVisible()){
48462 var b = west.getBox();
48463 var m = west.getMargins();
48464 b.height = centerH - (m.top+m.bottom);
48466 b.y = centerY + m.top;
48467 var totalWidth = (b.width + m.left + m.right);
48468 centerX += totalWidth;
48469 centerW -= totalWidth;
48470 west.updateBox(this.safeBox(b));
48472 if(east && east.isVisible()){
48473 var b = east.getBox();
48474 var m = east.getMargins();
48475 b.height = centerH - (m.top+m.bottom);
48476 var totalWidth = (b.width + m.left + m.right);
48477 b.x = w - totalWidth + m.left;
48478 b.y = centerY + m.top;
48479 centerW -= totalWidth;
48480 east.updateBox(this.safeBox(b));
48483 var m = center.getMargins();
48485 x: centerX + m.left,
48486 y: centerY + m.top,
48487 width: centerW - (m.left+m.right),
48488 height: centerH - (m.top+m.bottom)
48490 //if(this.hideOnLayout){
48491 //center.el.setStyle("display", "block");
48493 center.updateBox(this.safeBox(centerBox));
48496 this.fireEvent("layout", this);
48500 safeBox : function(box){
48501 box.width = Math.max(0, box.width);
48502 box.height = Math.max(0, box.height);
48507 * Adds a ContentPanel (or subclass) to this layout.
48508 * @param {String} target The target region key (north, south, east, west or center).
48509 * @param {Roo.ContentPanel} panel The panel to add
48510 * @return {Roo.ContentPanel} The added panel
48512 add : function(target, panel){
48514 target = target.toLowerCase();
48515 return this.regions[target].add(panel);
48519 * Remove a ContentPanel (or subclass) to this layout.
48520 * @param {String} target The target region key (north, south, east, west or center).
48521 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48522 * @return {Roo.ContentPanel} The removed panel
48524 remove : function(target, panel){
48525 target = target.toLowerCase();
48526 return this.regions[target].remove(panel);
48530 * Searches all regions for a panel with the specified id
48531 * @param {String} panelId
48532 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48534 findPanel : function(panelId){
48535 var rs = this.regions;
48536 for(var target in rs){
48537 if(typeof rs[target] != "function"){
48538 var p = rs[target].getPanel(panelId);
48548 * Searches all regions for a panel with the specified id and activates (shows) it.
48549 * @param {String/ContentPanel} panelId The panels id or the panel itself
48550 * @return {Roo.ContentPanel} The shown panel or null
48552 showPanel : function(panelId) {
48553 var rs = this.regions;
48554 for(var target in rs){
48555 var r = rs[target];
48556 if(typeof r != "function"){
48557 if(r.hasPanel(panelId)){
48558 return r.showPanel(panelId);
48566 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48567 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48569 restoreState : function(provider){
48571 provider = Roo.state.Manager;
48573 var sm = new Roo.LayoutStateManager();
48574 sm.init(this, provider);
48578 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48579 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48580 * a valid ContentPanel config object. Example:
48582 // Create the main layout
48583 var layout = new Roo.BorderLayout('main-ct', {
48594 // Create and add multiple ContentPanels at once via configs
48597 id: 'source-files',
48599 title:'Ext Source Files',
48612 * @param {Object} regions An object containing ContentPanel configs by region name
48614 batchAdd : function(regions){
48615 this.beginUpdate();
48616 for(var rname in regions){
48617 var lr = this.regions[rname];
48619 this.addTypedPanels(lr, regions[rname]);
48626 addTypedPanels : function(lr, ps){
48627 if(typeof ps == 'string'){
48628 lr.add(new Roo.ContentPanel(ps));
48630 else if(ps instanceof Array){
48631 for(var i =0, len = ps.length; i < len; i++){
48632 this.addTypedPanels(lr, ps[i]);
48635 else if(!ps.events){ // raw config?
48637 delete ps.el; // prevent conflict
48638 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48640 else { // panel object assumed!
48645 * Adds a xtype elements to the layout.
48649 xtype : 'ContentPanel',
48656 xtype : 'NestedLayoutPanel',
48662 items : [ ... list of content panels or nested layout panels.. ]
48666 * @param {Object} cfg Xtype definition of item to add.
48668 addxtype : function(cfg)
48670 // basically accepts a pannel...
48671 // can accept a layout region..!?!?
48672 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48674 if (!cfg.xtype.match(/Panel$/)) {
48679 if (typeof(cfg.region) == 'undefined') {
48680 Roo.log("Failed to add Panel, region was not set");
48684 var region = cfg.region;
48690 xitems = cfg.items;
48697 case 'ContentPanel': // ContentPanel (el, cfg)
48698 case 'ScrollPanel': // ContentPanel (el, cfg)
48700 if(cfg.autoCreate) {
48701 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48703 var el = this.el.createChild();
48704 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48707 this.add(region, ret);
48711 case 'TreePanel': // our new panel!
48712 cfg.el = this.el.createChild();
48713 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48714 this.add(region, ret);
48717 case 'NestedLayoutPanel':
48718 // create a new Layout (which is a Border Layout...
48719 var el = this.el.createChild();
48720 var clayout = cfg.layout;
48722 clayout.items = clayout.items || [];
48723 // replace this exitems with the clayout ones..
48724 xitems = clayout.items;
48727 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
48728 cfg.background = false;
48730 var layout = new Roo.BorderLayout(el, clayout);
48732 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
48733 //console.log('adding nested layout panel ' + cfg.toSource());
48734 this.add(region, ret);
48735 nb = {}; /// find first...
48740 // needs grid and region
48742 //var el = this.getRegion(region).el.createChild();
48743 var el = this.el.createChild();
48744 // create the grid first...
48746 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
48748 if (region == 'center' && this.active ) {
48749 cfg.background = false;
48751 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
48753 this.add(region, ret);
48754 if (cfg.background) {
48755 ret.on('activate', function(gp) {
48756 if (!gp.grid.rendered) {
48771 if (typeof(Roo[cfg.xtype]) != 'undefined') {
48773 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48774 this.add(region, ret);
48777 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
48781 // GridPanel (grid, cfg)
48784 this.beginUpdate();
48788 Roo.each(xitems, function(i) {
48789 region = nb && i.region ? i.region : false;
48791 var add = ret.addxtype(i);
48794 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
48795 if (!i.background) {
48796 abn[region] = nb[region] ;
48803 // make the last non-background panel active..
48804 //if (nb) { Roo.log(abn); }
48807 for(var r in abn) {
48808 region = this.getRegion(r);
48810 // tried using nb[r], but it does not work..
48812 region.showPanel(abn[r]);
48823 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
48824 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
48825 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
48826 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
48829 var CP = Roo.ContentPanel;
48831 var layout = Roo.BorderLayout.create({
48835 panels: [new CP("north", "North")]
48844 panels: [new CP("west", {title: "West"})]
48853 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
48862 panels: [new CP("south", {title: "South", closable: true})]
48869 preferredTabWidth: 150,
48871 new CP("center1", {title: "Close Me", closable: true}),
48872 new CP("center2", {title: "Center Panel", closable: false})
48877 layout.getRegion("center").showPanel("center1");
48882 Roo.BorderLayout.create = function(config, targetEl){
48883 var layout = new Roo.BorderLayout(targetEl || document.body, config);
48884 layout.beginUpdate();
48885 var regions = Roo.BorderLayout.RegionFactory.validRegions;
48886 for(var j = 0, jlen = regions.length; j < jlen; j++){
48887 var lr = regions[j];
48888 if(layout.regions[lr] && config[lr].panels){
48889 var r = layout.regions[lr];
48890 var ps = config[lr].panels;
48891 layout.addTypedPanels(r, ps);
48894 layout.endUpdate();
48899 Roo.BorderLayout.RegionFactory = {
48901 validRegions : ["north","south","east","west","center"],
48904 create : function(target, mgr, config){
48905 target = target.toLowerCase();
48906 if(config.lightweight || config.basic){
48907 return new Roo.BasicLayoutRegion(mgr, config, target);
48911 return new Roo.NorthLayoutRegion(mgr, config);
48913 return new Roo.SouthLayoutRegion(mgr, config);
48915 return new Roo.EastLayoutRegion(mgr, config);
48917 return new Roo.WestLayoutRegion(mgr, config);
48919 return new Roo.CenterLayoutRegion(mgr, config);
48921 throw 'Layout region "'+target+'" not supported.';
48925 * Ext JS Library 1.1.1
48926 * Copyright(c) 2006-2007, Ext JS, LLC.
48928 * Originally Released Under LGPL - original licence link has changed is not relivant.
48931 * <script type="text/javascript">
48935 * @class Roo.BasicLayoutRegion
48936 * @extends Roo.util.Observable
48937 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
48938 * and does not have a titlebar, tabs or any other features. All it does is size and position
48939 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
48941 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
48943 this.position = pos;
48946 * @scope Roo.BasicLayoutRegion
48950 * @event beforeremove
48951 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
48952 * @param {Roo.LayoutRegion} this
48953 * @param {Roo.ContentPanel} panel The panel
48954 * @param {Object} e The cancel event object
48956 "beforeremove" : true,
48958 * @event invalidated
48959 * Fires when the layout for this region is changed.
48960 * @param {Roo.LayoutRegion} this
48962 "invalidated" : true,
48964 * @event visibilitychange
48965 * Fires when this region is shown or hidden
48966 * @param {Roo.LayoutRegion} this
48967 * @param {Boolean} visibility true or false
48969 "visibilitychange" : true,
48971 * @event paneladded
48972 * Fires when a panel is added.
48973 * @param {Roo.LayoutRegion} this
48974 * @param {Roo.ContentPanel} panel The panel
48976 "paneladded" : true,
48978 * @event panelremoved
48979 * Fires when a panel is removed.
48980 * @param {Roo.LayoutRegion} this
48981 * @param {Roo.ContentPanel} panel The panel
48983 "panelremoved" : true,
48986 * Fires when this region is collapsed.
48987 * @param {Roo.LayoutRegion} this
48989 "collapsed" : true,
48992 * Fires when this region is expanded.
48993 * @param {Roo.LayoutRegion} this
48998 * Fires when this region is slid into view.
48999 * @param {Roo.LayoutRegion} this
49001 "slideshow" : true,
49004 * Fires when this region slides out of view.
49005 * @param {Roo.LayoutRegion} this
49007 "slidehide" : true,
49009 * @event panelactivated
49010 * Fires when a panel is activated.
49011 * @param {Roo.LayoutRegion} this
49012 * @param {Roo.ContentPanel} panel The activated panel
49014 "panelactivated" : true,
49017 * Fires when the user resizes this region.
49018 * @param {Roo.LayoutRegion} this
49019 * @param {Number} newSize The new size (width for east/west, height for north/south)
49023 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49024 this.panels = new Roo.util.MixedCollection();
49025 this.panels.getKey = this.getPanelId.createDelegate(this);
49027 this.activePanel = null;
49028 // ensure listeners are added...
49030 if (config.listeners || config.events) {
49031 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49032 listeners : config.listeners || {},
49033 events : config.events || {}
49037 if(skipConfig !== true){
49038 this.applyConfig(config);
49042 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49043 getPanelId : function(p){
49047 applyConfig : function(config){
49048 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49049 this.config = config;
49054 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49055 * the width, for horizontal (north, south) the height.
49056 * @param {Number} newSize The new width or height
49058 resizeTo : function(newSize){
49059 var el = this.el ? this.el :
49060 (this.activePanel ? this.activePanel.getEl() : null);
49062 switch(this.position){
49065 el.setWidth(newSize);
49066 this.fireEvent("resized", this, newSize);
49070 el.setHeight(newSize);
49071 this.fireEvent("resized", this, newSize);
49077 getBox : function(){
49078 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49081 getMargins : function(){
49082 return this.margins;
49085 updateBox : function(box){
49087 var el = this.activePanel.getEl();
49088 el.dom.style.left = box.x + "px";
49089 el.dom.style.top = box.y + "px";
49090 this.activePanel.setSize(box.width, box.height);
49094 * Returns the container element for this region.
49095 * @return {Roo.Element}
49097 getEl : function(){
49098 return this.activePanel;
49102 * Returns true if this region is currently visible.
49103 * @return {Boolean}
49105 isVisible : function(){
49106 return this.activePanel ? true : false;
49109 setActivePanel : function(panel){
49110 panel = this.getPanel(panel);
49111 if(this.activePanel && this.activePanel != panel){
49112 this.activePanel.setActiveState(false);
49113 this.activePanel.getEl().setLeftTop(-10000,-10000);
49115 this.activePanel = panel;
49116 panel.setActiveState(true);
49118 panel.setSize(this.box.width, this.box.height);
49120 this.fireEvent("panelactivated", this, panel);
49121 this.fireEvent("invalidated");
49125 * Show the specified panel.
49126 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49127 * @return {Roo.ContentPanel} The shown panel or null
49129 showPanel : function(panel){
49130 if(panel = this.getPanel(panel)){
49131 this.setActivePanel(panel);
49137 * Get the active panel for this region.
49138 * @return {Roo.ContentPanel} The active panel or null
49140 getActivePanel : function(){
49141 return this.activePanel;
49145 * Add the passed ContentPanel(s)
49146 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49147 * @return {Roo.ContentPanel} The panel added (if only one was added)
49149 add : function(panel){
49150 if(arguments.length > 1){
49151 for(var i = 0, len = arguments.length; i < len; i++) {
49152 this.add(arguments[i]);
49156 if(this.hasPanel(panel)){
49157 this.showPanel(panel);
49160 var el = panel.getEl();
49161 if(el.dom.parentNode != this.mgr.el.dom){
49162 this.mgr.el.dom.appendChild(el.dom);
49164 if(panel.setRegion){
49165 panel.setRegion(this);
49167 this.panels.add(panel);
49168 el.setStyle("position", "absolute");
49169 if(!panel.background){
49170 this.setActivePanel(panel);
49171 if(this.config.initialSize && this.panels.getCount()==1){
49172 this.resizeTo(this.config.initialSize);
49175 this.fireEvent("paneladded", this, panel);
49180 * Returns true if the panel is in this region.
49181 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49182 * @return {Boolean}
49184 hasPanel : function(panel){
49185 if(typeof panel == "object"){ // must be panel obj
49186 panel = panel.getId();
49188 return this.getPanel(panel) ? true : false;
49192 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49193 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49194 * @param {Boolean} preservePanel Overrides the config preservePanel option
49195 * @return {Roo.ContentPanel} The panel that was removed
49197 remove : function(panel, preservePanel){
49198 panel = this.getPanel(panel);
49203 this.fireEvent("beforeremove", this, panel, e);
49204 if(e.cancel === true){
49207 var panelId = panel.getId();
49208 this.panels.removeKey(panelId);
49213 * Returns the panel specified or null if it's not in this region.
49214 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49215 * @return {Roo.ContentPanel}
49217 getPanel : function(id){
49218 if(typeof id == "object"){ // must be panel obj
49221 return this.panels.get(id);
49225 * Returns this regions position (north/south/east/west/center).
49228 getPosition: function(){
49229 return this.position;
49233 * Ext JS Library 1.1.1
49234 * Copyright(c) 2006-2007, Ext JS, LLC.
49236 * Originally Released Under LGPL - original licence link has changed is not relivant.
49239 * <script type="text/javascript">
49243 * @class Roo.LayoutRegion
49244 * @extends Roo.BasicLayoutRegion
49245 * This class represents a region in a layout manager.
49246 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49247 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49248 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49249 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49250 * @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})
49251 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49252 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49253 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49254 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49255 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49256 * @cfg {String} title The title for the region (overrides panel titles)
49257 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49258 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49259 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49260 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49261 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49262 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49263 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49264 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49265 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49266 * @cfg {Boolean} showPin True to show a pin button
49267 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49268 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49269 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49270 * @cfg {Number} width For East/West panels
49271 * @cfg {Number} height For North/South panels
49272 * @cfg {Boolean} split To show the splitter
49273 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49275 Roo.LayoutRegion = function(mgr, config, pos){
49276 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49277 var dh = Roo.DomHelper;
49278 /** This region's container element
49279 * @type Roo.Element */
49280 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49281 /** This region's title element
49282 * @type Roo.Element */
49284 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49285 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49286 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49288 this.titleEl.enableDisplayMode();
49289 /** This region's title text element
49290 * @type HTMLElement */
49291 this.titleTextEl = this.titleEl.dom.firstChild;
49292 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49293 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49294 this.closeBtn.enableDisplayMode();
49295 this.closeBtn.on("click", this.closeClicked, this);
49296 this.closeBtn.hide();
49298 this.createBody(config);
49299 this.visible = true;
49300 this.collapsed = false;
49302 if(config.hideWhenEmpty){
49304 this.on("paneladded", this.validateVisibility, this);
49305 this.on("panelremoved", this.validateVisibility, this);
49307 this.applyConfig(config);
49310 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49312 createBody : function(){
49313 /** This region's body element
49314 * @type Roo.Element */
49315 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49318 applyConfig : function(c){
49319 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49320 var dh = Roo.DomHelper;
49321 if(c.titlebar !== false){
49322 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49323 this.collapseBtn.on("click", this.collapse, this);
49324 this.collapseBtn.enableDisplayMode();
49326 if(c.showPin === true || this.showPin){
49327 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49328 this.stickBtn.enableDisplayMode();
49329 this.stickBtn.on("click", this.expand, this);
49330 this.stickBtn.hide();
49333 /** This region's collapsed element
49334 * @type Roo.Element */
49335 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49336 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49338 if(c.floatable !== false){
49339 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49340 this.collapsedEl.on("click", this.collapseClick, this);
49343 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49344 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49345 id: "message", unselectable: "on", style:{"float":"left"}});
49346 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49348 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49349 this.expandBtn.on("click", this.expand, this);
49351 if(this.collapseBtn){
49352 this.collapseBtn.setVisible(c.collapsible == true);
49354 this.cmargins = c.cmargins || this.cmargins ||
49355 (this.position == "west" || this.position == "east" ?
49356 {top: 0, left: 2, right:2, bottom: 0} :
49357 {top: 2, left: 0, right:0, bottom: 2});
49358 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49359 this.bottomTabs = c.tabPosition != "top";
49360 this.autoScroll = c.autoScroll || false;
49361 if(this.autoScroll){
49362 this.bodyEl.setStyle("overflow", "auto");
49364 this.bodyEl.setStyle("overflow", "hidden");
49366 //if(c.titlebar !== false){
49367 if((!c.titlebar && !c.title) || c.titlebar === false){
49368 this.titleEl.hide();
49370 this.titleEl.show();
49372 this.titleTextEl.innerHTML = c.title;
49376 this.duration = c.duration || .30;
49377 this.slideDuration = c.slideDuration || .45;
49380 this.collapse(true);
49387 * Returns true if this region is currently visible.
49388 * @return {Boolean}
49390 isVisible : function(){
49391 return this.visible;
49395 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49396 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49398 setCollapsedTitle : function(title){
49399 title = title || " ";
49400 if(this.collapsedTitleTextEl){
49401 this.collapsedTitleTextEl.innerHTML = title;
49405 getBox : function(){
49407 if(!this.collapsed){
49408 b = this.el.getBox(false, true);
49410 b = this.collapsedEl.getBox(false, true);
49415 getMargins : function(){
49416 return this.collapsed ? this.cmargins : this.margins;
49419 highlight : function(){
49420 this.el.addClass("x-layout-panel-dragover");
49423 unhighlight : function(){
49424 this.el.removeClass("x-layout-panel-dragover");
49427 updateBox : function(box){
49429 if(!this.collapsed){
49430 this.el.dom.style.left = box.x + "px";
49431 this.el.dom.style.top = box.y + "px";
49432 this.updateBody(box.width, box.height);
49434 this.collapsedEl.dom.style.left = box.x + "px";
49435 this.collapsedEl.dom.style.top = box.y + "px";
49436 this.collapsedEl.setSize(box.width, box.height);
49439 this.tabs.autoSizeTabs();
49443 updateBody : function(w, h){
49445 this.el.setWidth(w);
49446 w -= this.el.getBorderWidth("rl");
49447 if(this.config.adjustments){
49448 w += this.config.adjustments[0];
49452 this.el.setHeight(h);
49453 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49454 h -= this.el.getBorderWidth("tb");
49455 if(this.config.adjustments){
49456 h += this.config.adjustments[1];
49458 this.bodyEl.setHeight(h);
49460 h = this.tabs.syncHeight(h);
49463 if(this.panelSize){
49464 w = w !== null ? w : this.panelSize.width;
49465 h = h !== null ? h : this.panelSize.height;
49467 if(this.activePanel){
49468 var el = this.activePanel.getEl();
49469 w = w !== null ? w : el.getWidth();
49470 h = h !== null ? h : el.getHeight();
49471 this.panelSize = {width: w, height: h};
49472 this.activePanel.setSize(w, h);
49474 if(Roo.isIE && this.tabs){
49475 this.tabs.el.repaint();
49480 * Returns the container element for this region.
49481 * @return {Roo.Element}
49483 getEl : function(){
49488 * Hides this region.
49491 if(!this.collapsed){
49492 this.el.dom.style.left = "-2000px";
49495 this.collapsedEl.dom.style.left = "-2000px";
49496 this.collapsedEl.hide();
49498 this.visible = false;
49499 this.fireEvent("visibilitychange", this, false);
49503 * Shows this region if it was previously hidden.
49506 if(!this.collapsed){
49509 this.collapsedEl.show();
49511 this.visible = true;
49512 this.fireEvent("visibilitychange", this, true);
49515 closeClicked : function(){
49516 if(this.activePanel){
49517 this.remove(this.activePanel);
49521 collapseClick : function(e){
49523 e.stopPropagation();
49526 e.stopPropagation();
49532 * Collapses this region.
49533 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49535 collapse : function(skipAnim){
49536 if(this.collapsed) return;
49537 this.collapsed = true;
49539 this.split.el.hide();
49541 if(this.config.animate && skipAnim !== true){
49542 this.fireEvent("invalidated", this);
49543 this.animateCollapse();
49545 this.el.setLocation(-20000,-20000);
49547 this.collapsedEl.show();
49548 this.fireEvent("collapsed", this);
49549 this.fireEvent("invalidated", this);
49553 animateCollapse : function(){
49558 * Expands this region if it was previously collapsed.
49559 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49560 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49562 expand : function(e, skipAnim){
49563 if(e) e.stopPropagation();
49564 if(!this.collapsed || this.el.hasActiveFx()) return;
49566 this.afterSlideIn();
49569 this.collapsed = false;
49570 if(this.config.animate && skipAnim !== true){
49571 this.animateExpand();
49575 this.split.el.show();
49577 this.collapsedEl.setLocation(-2000,-2000);
49578 this.collapsedEl.hide();
49579 this.fireEvent("invalidated", this);
49580 this.fireEvent("expanded", this);
49584 animateExpand : function(){
49588 initTabs : function()
49590 this.bodyEl.setStyle("overflow", "hidden");
49591 var ts = new Roo.TabPanel(
49594 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49595 disableTooltips: this.config.disableTabTips,
49596 toolbar : this.config.toolbar
49599 if(this.config.hideTabs){
49600 ts.stripWrap.setDisplayed(false);
49603 ts.resizeTabs = this.config.resizeTabs === true;
49604 ts.minTabWidth = this.config.minTabWidth || 40;
49605 ts.maxTabWidth = this.config.maxTabWidth || 250;
49606 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49607 ts.monitorResize = false;
49608 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49609 ts.bodyEl.addClass('x-layout-tabs-body');
49610 this.panels.each(this.initPanelAsTab, this);
49613 initPanelAsTab : function(panel){
49614 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49615 this.config.closeOnTab && panel.isClosable());
49616 if(panel.tabTip !== undefined){
49617 ti.setTooltip(panel.tabTip);
49619 ti.on("activate", function(){
49620 this.setActivePanel(panel);
49622 if(this.config.closeOnTab){
49623 ti.on("beforeclose", function(t, e){
49625 this.remove(panel);
49631 updatePanelTitle : function(panel, title){
49632 if(this.activePanel == panel){
49633 this.updateTitle(title);
49636 var ti = this.tabs.getTab(panel.getEl().id);
49638 if(panel.tabTip !== undefined){
49639 ti.setTooltip(panel.tabTip);
49644 updateTitle : function(title){
49645 if(this.titleTextEl && !this.config.title){
49646 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49650 setActivePanel : function(panel){
49651 panel = this.getPanel(panel);
49652 if(this.activePanel && this.activePanel != panel){
49653 this.activePanel.setActiveState(false);
49655 this.activePanel = panel;
49656 panel.setActiveState(true);
49657 if(this.panelSize){
49658 panel.setSize(this.panelSize.width, this.panelSize.height);
49661 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49663 this.updateTitle(panel.getTitle());
49665 this.fireEvent("invalidated", this);
49667 this.fireEvent("panelactivated", this, panel);
49671 * Shows the specified panel.
49672 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49673 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49675 showPanel : function(panel){
49676 if(panel = this.getPanel(panel)){
49678 var tab = this.tabs.getTab(panel.getEl().id);
49679 if(tab.isHidden()){
49680 this.tabs.unhideTab(tab.id);
49684 this.setActivePanel(panel);
49691 * Get the active panel for this region.
49692 * @return {Roo.ContentPanel} The active panel or null
49694 getActivePanel : function(){
49695 return this.activePanel;
49698 validateVisibility : function(){
49699 if(this.panels.getCount() < 1){
49700 this.updateTitle(" ");
49701 this.closeBtn.hide();
49704 if(!this.isVisible()){
49711 * Adds the passed ContentPanel(s) to this region.
49712 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49713 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
49715 add : function(panel){
49716 if(arguments.length > 1){
49717 for(var i = 0, len = arguments.length; i < len; i++) {
49718 this.add(arguments[i]);
49722 if(this.hasPanel(panel)){
49723 this.showPanel(panel);
49726 panel.setRegion(this);
49727 this.panels.add(panel);
49728 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
49729 this.bodyEl.dom.appendChild(panel.getEl().dom);
49730 if(panel.background !== true){
49731 this.setActivePanel(panel);
49733 this.fireEvent("paneladded", this, panel);
49739 this.initPanelAsTab(panel);
49741 if(panel.background !== true){
49742 this.tabs.activate(panel.getEl().id);
49744 this.fireEvent("paneladded", this, panel);
49749 * Hides the tab for the specified panel.
49750 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49752 hidePanel : function(panel){
49753 if(this.tabs && (panel = this.getPanel(panel))){
49754 this.tabs.hideTab(panel.getEl().id);
49759 * Unhides the tab for a previously hidden panel.
49760 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49762 unhidePanel : function(panel){
49763 if(this.tabs && (panel = this.getPanel(panel))){
49764 this.tabs.unhideTab(panel.getEl().id);
49768 clearPanels : function(){
49769 while(this.panels.getCount() > 0){
49770 this.remove(this.panels.first());
49775 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49776 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
49777 * @param {Boolean} preservePanel Overrides the config preservePanel option
49778 * @return {Roo.ContentPanel} The panel that was removed
49780 remove : function(panel, preservePanel){
49781 panel = this.getPanel(panel);
49786 this.fireEvent("beforeremove", this, panel, e);
49787 if(e.cancel === true){
49790 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
49791 var panelId = panel.getId();
49792 this.panels.removeKey(panelId);
49794 document.body.appendChild(panel.getEl().dom);
49797 this.tabs.removeTab(panel.getEl().id);
49798 }else if (!preservePanel){
49799 this.bodyEl.dom.removeChild(panel.getEl().dom);
49801 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
49802 var p = this.panels.first();
49803 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
49804 tempEl.appendChild(p.getEl().dom);
49805 this.bodyEl.update("");
49806 this.bodyEl.dom.appendChild(p.getEl().dom);
49808 this.updateTitle(p.getTitle());
49810 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49811 this.setActivePanel(p);
49813 panel.setRegion(null);
49814 if(this.activePanel == panel){
49815 this.activePanel = null;
49817 if(this.config.autoDestroy !== false && preservePanel !== true){
49818 try{panel.destroy();}catch(e){}
49820 this.fireEvent("panelremoved", this, panel);
49825 * Returns the TabPanel component used by this region
49826 * @return {Roo.TabPanel}
49828 getTabs : function(){
49832 createTool : function(parentEl, className){
49833 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
49834 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
49835 btn.addClassOnOver("x-layout-tools-button-over");
49840 * Ext JS Library 1.1.1
49841 * Copyright(c) 2006-2007, Ext JS, LLC.
49843 * Originally Released Under LGPL - original licence link has changed is not relivant.
49846 * <script type="text/javascript">
49852 * @class Roo.SplitLayoutRegion
49853 * @extends Roo.LayoutRegion
49854 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
49856 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
49857 this.cursor = cursor;
49858 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
49861 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
49862 splitTip : "Drag to resize.",
49863 collapsibleSplitTip : "Drag to resize. Double click to hide.",
49864 useSplitTips : false,
49866 applyConfig : function(config){
49867 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
49870 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
49871 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
49872 /** The SplitBar for this region
49873 * @type Roo.SplitBar */
49874 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
49875 this.split.on("moved", this.onSplitMove, this);
49876 this.split.useShim = config.useShim === true;
49877 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
49878 if(this.useSplitTips){
49879 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
49881 if(config.collapsible){
49882 this.split.el.on("dblclick", this.collapse, this);
49885 if(typeof config.minSize != "undefined"){
49886 this.split.minSize = config.minSize;
49888 if(typeof config.maxSize != "undefined"){
49889 this.split.maxSize = config.maxSize;
49891 if(config.hideWhenEmpty || config.hidden || config.collapsed){
49892 this.hideSplitter();
49897 getHMaxSize : function(){
49898 var cmax = this.config.maxSize || 10000;
49899 var center = this.mgr.getRegion("center");
49900 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
49903 getVMaxSize : function(){
49904 var cmax = this.config.maxSize || 10000;
49905 var center = this.mgr.getRegion("center");
49906 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
49909 onSplitMove : function(split, newSize){
49910 this.fireEvent("resized", this, newSize);
49914 * Returns the {@link Roo.SplitBar} for this region.
49915 * @return {Roo.SplitBar}
49917 getSplitBar : function(){
49922 this.hideSplitter();
49923 Roo.SplitLayoutRegion.superclass.hide.call(this);
49926 hideSplitter : function(){
49928 this.split.el.setLocation(-2000,-2000);
49929 this.split.el.hide();
49935 this.split.el.show();
49937 Roo.SplitLayoutRegion.superclass.show.call(this);
49940 beforeSlide: function(){
49941 if(Roo.isGecko){// firefox overflow auto bug workaround
49942 this.bodyEl.clip();
49943 if(this.tabs) this.tabs.bodyEl.clip();
49944 if(this.activePanel){
49945 this.activePanel.getEl().clip();
49947 if(this.activePanel.beforeSlide){
49948 this.activePanel.beforeSlide();
49954 afterSlide : function(){
49955 if(Roo.isGecko){// firefox overflow auto bug workaround
49956 this.bodyEl.unclip();
49957 if(this.tabs) this.tabs.bodyEl.unclip();
49958 if(this.activePanel){
49959 this.activePanel.getEl().unclip();
49960 if(this.activePanel.afterSlide){
49961 this.activePanel.afterSlide();
49967 initAutoHide : function(){
49968 if(this.autoHide !== false){
49969 if(!this.autoHideHd){
49970 var st = new Roo.util.DelayedTask(this.slideIn, this);
49971 this.autoHideHd = {
49972 "mouseout": function(e){
49973 if(!e.within(this.el, true)){
49977 "mouseover" : function(e){
49983 this.el.on(this.autoHideHd);
49987 clearAutoHide : function(){
49988 if(this.autoHide !== false){
49989 this.el.un("mouseout", this.autoHideHd.mouseout);
49990 this.el.un("mouseover", this.autoHideHd.mouseover);
49994 clearMonitor : function(){
49995 Roo.get(document).un("click", this.slideInIf, this);
49998 // these names are backwards but not changed for compat
49999 slideOut : function(){
50000 if(this.isSlid || this.el.hasActiveFx()){
50003 this.isSlid = true;
50004 if(this.collapseBtn){
50005 this.collapseBtn.hide();
50007 this.closeBtnState = this.closeBtn.getStyle('display');
50008 this.closeBtn.hide();
50010 this.stickBtn.show();
50013 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50014 this.beforeSlide();
50015 this.el.setStyle("z-index", 10001);
50016 this.el.slideIn(this.getSlideAnchor(), {
50017 callback: function(){
50019 this.initAutoHide();
50020 Roo.get(document).on("click", this.slideInIf, this);
50021 this.fireEvent("slideshow", this);
50028 afterSlideIn : function(){
50029 this.clearAutoHide();
50030 this.isSlid = false;
50031 this.clearMonitor();
50032 this.el.setStyle("z-index", "");
50033 if(this.collapseBtn){
50034 this.collapseBtn.show();
50036 this.closeBtn.setStyle('display', this.closeBtnState);
50038 this.stickBtn.hide();
50040 this.fireEvent("slidehide", this);
50043 slideIn : function(cb){
50044 if(!this.isSlid || this.el.hasActiveFx()){
50048 this.isSlid = false;
50049 this.beforeSlide();
50050 this.el.slideOut(this.getSlideAnchor(), {
50051 callback: function(){
50052 this.el.setLeftTop(-10000, -10000);
50054 this.afterSlideIn();
50062 slideInIf : function(e){
50063 if(!e.within(this.el)){
50068 animateCollapse : function(){
50069 this.beforeSlide();
50070 this.el.setStyle("z-index", 20000);
50071 var anchor = this.getSlideAnchor();
50072 this.el.slideOut(anchor, {
50073 callback : function(){
50074 this.el.setStyle("z-index", "");
50075 this.collapsedEl.slideIn(anchor, {duration:.3});
50077 this.el.setLocation(-10000,-10000);
50079 this.fireEvent("collapsed", this);
50086 animateExpand : function(){
50087 this.beforeSlide();
50088 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50089 this.el.setStyle("z-index", 20000);
50090 this.collapsedEl.hide({
50093 this.el.slideIn(this.getSlideAnchor(), {
50094 callback : function(){
50095 this.el.setStyle("z-index", "");
50098 this.split.el.show();
50100 this.fireEvent("invalidated", this);
50101 this.fireEvent("expanded", this);
50129 getAnchor : function(){
50130 return this.anchors[this.position];
50133 getCollapseAnchor : function(){
50134 return this.canchors[this.position];
50137 getSlideAnchor : function(){
50138 return this.sanchors[this.position];
50141 getAlignAdj : function(){
50142 var cm = this.cmargins;
50143 switch(this.position){
50159 getExpandAdj : function(){
50160 var c = this.collapsedEl, cm = this.cmargins;
50161 switch(this.position){
50163 return [-(cm.right+c.getWidth()+cm.left), 0];
50166 return [cm.right+c.getWidth()+cm.left, 0];
50169 return [0, -(cm.top+cm.bottom+c.getHeight())];
50172 return [0, cm.top+cm.bottom+c.getHeight()];
50178 * Ext JS Library 1.1.1
50179 * Copyright(c) 2006-2007, Ext JS, LLC.
50181 * Originally Released Under LGPL - original licence link has changed is not relivant.
50184 * <script type="text/javascript">
50187 * These classes are private internal classes
50189 Roo.CenterLayoutRegion = function(mgr, config){
50190 Roo.LayoutRegion.call(this, mgr, config, "center");
50191 this.visible = true;
50192 this.minWidth = config.minWidth || 20;
50193 this.minHeight = config.minHeight || 20;
50196 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50198 // center panel can't be hidden
50202 // center panel can't be hidden
50205 getMinWidth: function(){
50206 return this.minWidth;
50209 getMinHeight: function(){
50210 return this.minHeight;
50215 Roo.NorthLayoutRegion = function(mgr, config){
50216 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50218 this.split.placement = Roo.SplitBar.TOP;
50219 this.split.orientation = Roo.SplitBar.VERTICAL;
50220 this.split.el.addClass("x-layout-split-v");
50222 var size = config.initialSize || config.height;
50223 if(typeof size != "undefined"){
50224 this.el.setHeight(size);
50227 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50228 orientation: Roo.SplitBar.VERTICAL,
50229 getBox : function(){
50230 if(this.collapsed){
50231 return this.collapsedEl.getBox();
50233 var box = this.el.getBox();
50235 box.height += this.split.el.getHeight();
50240 updateBox : function(box){
50241 if(this.split && !this.collapsed){
50242 box.height -= this.split.el.getHeight();
50243 this.split.el.setLeft(box.x);
50244 this.split.el.setTop(box.y+box.height);
50245 this.split.el.setWidth(box.width);
50247 if(this.collapsed){
50248 this.updateBody(box.width, null);
50250 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50254 Roo.SouthLayoutRegion = function(mgr, config){
50255 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50257 this.split.placement = Roo.SplitBar.BOTTOM;
50258 this.split.orientation = Roo.SplitBar.VERTICAL;
50259 this.split.el.addClass("x-layout-split-v");
50261 var size = config.initialSize || config.height;
50262 if(typeof size != "undefined"){
50263 this.el.setHeight(size);
50266 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50267 orientation: Roo.SplitBar.VERTICAL,
50268 getBox : function(){
50269 if(this.collapsed){
50270 return this.collapsedEl.getBox();
50272 var box = this.el.getBox();
50274 var sh = this.split.el.getHeight();
50281 updateBox : function(box){
50282 if(this.split && !this.collapsed){
50283 var sh = this.split.el.getHeight();
50286 this.split.el.setLeft(box.x);
50287 this.split.el.setTop(box.y-sh);
50288 this.split.el.setWidth(box.width);
50290 if(this.collapsed){
50291 this.updateBody(box.width, null);
50293 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50297 Roo.EastLayoutRegion = function(mgr, config){
50298 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50300 this.split.placement = Roo.SplitBar.RIGHT;
50301 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50302 this.split.el.addClass("x-layout-split-h");
50304 var size = config.initialSize || config.width;
50305 if(typeof size != "undefined"){
50306 this.el.setWidth(size);
50309 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50310 orientation: Roo.SplitBar.HORIZONTAL,
50311 getBox : function(){
50312 if(this.collapsed){
50313 return this.collapsedEl.getBox();
50315 var box = this.el.getBox();
50317 var sw = this.split.el.getWidth();
50324 updateBox : function(box){
50325 if(this.split && !this.collapsed){
50326 var sw = this.split.el.getWidth();
50328 this.split.el.setLeft(box.x);
50329 this.split.el.setTop(box.y);
50330 this.split.el.setHeight(box.height);
50333 if(this.collapsed){
50334 this.updateBody(null, box.height);
50336 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50340 Roo.WestLayoutRegion = function(mgr, config){
50341 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50343 this.split.placement = Roo.SplitBar.LEFT;
50344 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50345 this.split.el.addClass("x-layout-split-h");
50347 var size = config.initialSize || config.width;
50348 if(typeof size != "undefined"){
50349 this.el.setWidth(size);
50352 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50353 orientation: Roo.SplitBar.HORIZONTAL,
50354 getBox : function(){
50355 if(this.collapsed){
50356 return this.collapsedEl.getBox();
50358 var box = this.el.getBox();
50360 box.width += this.split.el.getWidth();
50365 updateBox : function(box){
50366 if(this.split && !this.collapsed){
50367 var sw = this.split.el.getWidth();
50369 this.split.el.setLeft(box.x+box.width);
50370 this.split.el.setTop(box.y);
50371 this.split.el.setHeight(box.height);
50373 if(this.collapsed){
50374 this.updateBody(null, box.height);
50376 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50381 * Ext JS Library 1.1.1
50382 * Copyright(c) 2006-2007, Ext JS, LLC.
50384 * Originally Released Under LGPL - original licence link has changed is not relivant.
50387 * <script type="text/javascript">
50392 * Private internal class for reading and applying state
50394 Roo.LayoutStateManager = function(layout){
50395 // default empty state
50404 Roo.LayoutStateManager.prototype = {
50405 init : function(layout, provider){
50406 this.provider = provider;
50407 var state = provider.get(layout.id+"-layout-state");
50409 var wasUpdating = layout.isUpdating();
50411 layout.beginUpdate();
50413 for(var key in state){
50414 if(typeof state[key] != "function"){
50415 var rstate = state[key];
50416 var r = layout.getRegion(key);
50419 r.resizeTo(rstate.size);
50421 if(rstate.collapsed == true){
50424 r.expand(null, true);
50430 layout.endUpdate();
50432 this.state = state;
50434 this.layout = layout;
50435 layout.on("regionresized", this.onRegionResized, this);
50436 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50437 layout.on("regionexpanded", this.onRegionExpanded, this);
50440 storeState : function(){
50441 this.provider.set(this.layout.id+"-layout-state", this.state);
50444 onRegionResized : function(region, newSize){
50445 this.state[region.getPosition()].size = newSize;
50449 onRegionCollapsed : function(region){
50450 this.state[region.getPosition()].collapsed = true;
50454 onRegionExpanded : function(region){
50455 this.state[region.getPosition()].collapsed = false;
50460 * Ext JS Library 1.1.1
50461 * Copyright(c) 2006-2007, Ext JS, LLC.
50463 * Originally Released Under LGPL - original licence link has changed is not relivant.
50466 * <script type="text/javascript">
50469 * @class Roo.ContentPanel
50470 * @extends Roo.util.Observable
50471 * A basic ContentPanel element.
50472 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50473 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50474 * @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
50475 * @cfg {Boolean} closable True if the panel can be closed/removed
50476 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50477 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50478 * @cfg {Toolbar} toolbar A toolbar for this panel
50479 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50480 * @cfg {String} title The title for this panel
50481 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50482 * @cfg {String} url Calls {@link #setUrl} with this value
50483 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50484 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50485 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50486 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50489 * Create a new ContentPanel.
50490 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50491 * @param {String/Object} config A string to set only the title or a config object
50492 * @param {String} content (optional) Set the HTML content for this panel
50493 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50495 Roo.ContentPanel = function(el, config, content){
50499 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50503 if (config && config.parentLayout) {
50504 el = config.parentLayout.el.createChild();
50507 if(el.autoCreate){ // xtype is available if this is called from factory
50511 this.el = Roo.get(el);
50512 if(!this.el && config && config.autoCreate){
50513 if(typeof config.autoCreate == "object"){
50514 if(!config.autoCreate.id){
50515 config.autoCreate.id = config.id||el;
50517 this.el = Roo.DomHelper.append(document.body,
50518 config.autoCreate, true);
50520 this.el = Roo.DomHelper.append(document.body,
50521 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50524 this.closable = false;
50525 this.loaded = false;
50526 this.active = false;
50527 if(typeof config == "string"){
50528 this.title = config;
50530 Roo.apply(this, config);
50533 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50534 this.wrapEl = this.el.wrap();
50535 this.toolbar.container = this.el.insertSibling(false, 'before');
50536 this.toolbar = new Roo.Toolbar(this.toolbar);
50539 // xtype created footer. - not sure if will work as we normally have to render first..
50540 if (this.footer && !this.footer.el && this.footer.xtype) {
50541 if (!this.wrapEl) {
50542 this.wrapEl = this.el.wrap();
50545 this.footer.container = this.wrapEl.createChild();
50547 this.footer = Roo.factory(this.footer, Roo);
50552 this.resizeEl = Roo.get(this.resizeEl, true);
50554 this.resizeEl = this.el;
50556 // handle view.xtype
50564 * Fires when this panel is activated.
50565 * @param {Roo.ContentPanel} this
50569 * @event deactivate
50570 * Fires when this panel is activated.
50571 * @param {Roo.ContentPanel} this
50573 "deactivate" : true,
50577 * Fires when this panel is resized if fitToFrame is true.
50578 * @param {Roo.ContentPanel} this
50579 * @param {Number} width The width after any component adjustments
50580 * @param {Number} height The height after any component adjustments
50586 * Fires when this tab is created
50587 * @param {Roo.ContentPanel} this
50598 if(this.autoScroll){
50599 this.resizeEl.setStyle("overflow", "auto");
50601 // fix randome scrolling
50602 this.el.on('scroll', function() {
50603 Roo.log('fix random scolling');
50604 this.scrollTo('top',0);
50607 content = content || this.content;
50609 this.setContent(content);
50611 if(config && config.url){
50612 this.setUrl(this.url, this.params, this.loadOnce);
50617 Roo.ContentPanel.superclass.constructor.call(this);
50619 if (this.view && typeof(this.view.xtype) != 'undefined') {
50620 this.view.el = this.el.appendChild(document.createElement("div"));
50621 this.view = Roo.factory(this.view);
50622 this.view.render && this.view.render(false, '');
50626 this.fireEvent('render', this);
50629 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50631 setRegion : function(region){
50632 this.region = region;
50634 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50636 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50641 * Returns the toolbar for this Panel if one was configured.
50642 * @return {Roo.Toolbar}
50644 getToolbar : function(){
50645 return this.toolbar;
50648 setActiveState : function(active){
50649 this.active = active;
50651 this.fireEvent("deactivate", this);
50653 this.fireEvent("activate", this);
50657 * Updates this panel's element
50658 * @param {String} content The new content
50659 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50661 setContent : function(content, loadScripts){
50662 this.el.update(content, loadScripts);
50665 ignoreResize : function(w, h){
50666 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50669 this.lastSize = {width: w, height: h};
50674 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50675 * @return {Roo.UpdateManager} The UpdateManager
50677 getUpdateManager : function(){
50678 return this.el.getUpdateManager();
50681 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50682 * @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:
50685 url: "your-url.php",
50686 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50687 callback: yourFunction,
50688 scope: yourObject, //(optional scope)
50691 text: "Loading...",
50696 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50697 * 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.
50698 * @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}
50699 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50700 * @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.
50701 * @return {Roo.ContentPanel} this
50704 var um = this.el.getUpdateManager();
50705 um.update.apply(um, arguments);
50711 * 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.
50712 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
50713 * @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)
50714 * @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)
50715 * @return {Roo.UpdateManager} The UpdateManager
50717 setUrl : function(url, params, loadOnce){
50718 if(this.refreshDelegate){
50719 this.removeListener("activate", this.refreshDelegate);
50721 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
50722 this.on("activate", this.refreshDelegate);
50723 return this.el.getUpdateManager();
50726 _handleRefresh : function(url, params, loadOnce){
50727 if(!loadOnce || !this.loaded){
50728 var updater = this.el.getUpdateManager();
50729 updater.update(url, params, this._setLoaded.createDelegate(this));
50733 _setLoaded : function(){
50734 this.loaded = true;
50738 * Returns this panel's id
50741 getId : function(){
50746 * Returns this panel's element - used by regiosn to add.
50747 * @return {Roo.Element}
50749 getEl : function(){
50750 return this.wrapEl || this.el;
50753 adjustForComponents : function(width, height)
50755 //Roo.log('adjustForComponents ');
50756 if(this.resizeEl != this.el){
50757 width -= this.el.getFrameWidth('lr');
50758 height -= this.el.getFrameWidth('tb');
50761 var te = this.toolbar.getEl();
50762 height -= te.getHeight();
50763 te.setWidth(width);
50766 var te = this.footer.getEl();
50767 Roo.log("footer:" + te.getHeight());
50769 height -= te.getHeight();
50770 te.setWidth(width);
50774 if(this.adjustments){
50775 width += this.adjustments[0];
50776 height += this.adjustments[1];
50778 return {"width": width, "height": height};
50781 setSize : function(width, height){
50782 if(this.fitToFrame && !this.ignoreResize(width, height)){
50783 if(this.fitContainer && this.resizeEl != this.el){
50784 this.el.setSize(width, height);
50786 var size = this.adjustForComponents(width, height);
50787 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
50788 this.fireEvent('resize', this, size.width, size.height);
50793 * Returns this panel's title
50796 getTitle : function(){
50801 * Set this panel's title
50802 * @param {String} title
50804 setTitle : function(title){
50805 this.title = title;
50807 this.region.updatePanelTitle(this, title);
50812 * Returns true is this panel was configured to be closable
50813 * @return {Boolean}
50815 isClosable : function(){
50816 return this.closable;
50819 beforeSlide : function(){
50821 this.resizeEl.clip();
50824 afterSlide : function(){
50826 this.resizeEl.unclip();
50830 * Force a content refresh from the URL specified in the {@link #setUrl} method.
50831 * Will fail silently if the {@link #setUrl} method has not been called.
50832 * This does not activate the panel, just updates its content.
50834 refresh : function(){
50835 if(this.refreshDelegate){
50836 this.loaded = false;
50837 this.refreshDelegate();
50842 * Destroys this panel
50844 destroy : function(){
50845 this.el.removeAllListeners();
50846 var tempEl = document.createElement("span");
50847 tempEl.appendChild(this.el.dom);
50848 tempEl.innerHTML = "";
50854 * form - if the content panel contains a form - this is a reference to it.
50855 * @type {Roo.form.Form}
50859 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
50860 * This contains a reference to it.
50866 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
50876 * @param {Object} cfg Xtype definition of item to add.
50879 addxtype : function(cfg) {
50881 if (cfg.xtype.match(/^Form$/)) {
50884 //if (this.footer) {
50885 // el = this.footer.container.insertSibling(false, 'before');
50887 el = this.el.createChild();
50890 this.form = new Roo.form.Form(cfg);
50893 if ( this.form.allItems.length) this.form.render(el.dom);
50896 // should only have one of theses..
50897 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
50898 // views.. should not be just added - used named prop 'view''
50900 cfg.el = this.el.appendChild(document.createElement("div"));
50903 var ret = new Roo.factory(cfg);
50905 ret.render && ret.render(false, ''); // render blank..
50914 * @class Roo.GridPanel
50915 * @extends Roo.ContentPanel
50917 * Create a new GridPanel.
50918 * @param {Roo.grid.Grid} grid The grid for this panel
50919 * @param {String/Object} config A string to set only the panel's title, or a config object
50921 Roo.GridPanel = function(grid, config){
50924 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
50925 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
50927 this.wrapper.dom.appendChild(grid.getGridEl().dom);
50929 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
50932 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
50934 // xtype created footer. - not sure if will work as we normally have to render first..
50935 if (this.footer && !this.footer.el && this.footer.xtype) {
50937 this.footer.container = this.grid.getView().getFooterPanel(true);
50938 this.footer.dataSource = this.grid.dataSource;
50939 this.footer = Roo.factory(this.footer, Roo);
50943 grid.monitorWindowResize = false; // turn off autosizing
50944 grid.autoHeight = false;
50945 grid.autoWidth = false;
50947 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
50950 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
50951 getId : function(){
50952 return this.grid.id;
50956 * Returns the grid for this panel
50957 * @return {Roo.grid.Grid}
50959 getGrid : function(){
50963 setSize : function(width, height){
50964 if(!this.ignoreResize(width, height)){
50965 var grid = this.grid;
50966 var size = this.adjustForComponents(width, height);
50967 grid.getGridEl().setSize(size.width, size.height);
50972 beforeSlide : function(){
50973 this.grid.getView().scroller.clip();
50976 afterSlide : function(){
50977 this.grid.getView().scroller.unclip();
50980 destroy : function(){
50981 this.grid.destroy();
50983 Roo.GridPanel.superclass.destroy.call(this);
50989 * @class Roo.NestedLayoutPanel
50990 * @extends Roo.ContentPanel
50992 * Create a new NestedLayoutPanel.
50995 * @param {Roo.BorderLayout} layout The layout for this panel
50996 * @param {String/Object} config A string to set only the title or a config object
50998 Roo.NestedLayoutPanel = function(layout, config)
51000 // construct with only one argument..
51001 /* FIXME - implement nicer consturctors
51002 if (layout.layout) {
51004 layout = config.layout;
51005 delete config.layout;
51007 if (layout.xtype && !layout.getEl) {
51008 // then layout needs constructing..
51009 layout = Roo.factory(layout, Roo);
51014 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51016 layout.monitorWindowResize = false; // turn off autosizing
51017 this.layout = layout;
51018 this.layout.getEl().addClass("x-layout-nested-layout");
51025 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51027 setSize : function(width, height){
51028 if(!this.ignoreResize(width, height)){
51029 var size = this.adjustForComponents(width, height);
51030 var el = this.layout.getEl();
51031 el.setSize(size.width, size.height);
51032 var touch = el.dom.offsetWidth;
51033 this.layout.layout();
51034 // ie requires a double layout on the first pass
51035 if(Roo.isIE && !this.initialized){
51036 this.initialized = true;
51037 this.layout.layout();
51042 // activate all subpanels if not currently active..
51044 setActiveState : function(active){
51045 this.active = active;
51047 this.fireEvent("deactivate", this);
51051 this.fireEvent("activate", this);
51052 // not sure if this should happen before or after..
51053 if (!this.layout) {
51054 return; // should not happen..
51057 for (var r in this.layout.regions) {
51058 reg = this.layout.getRegion(r);
51059 if (reg.getActivePanel()) {
51060 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51061 reg.setActivePanel(reg.getActivePanel());
51064 if (!reg.panels.length) {
51067 reg.showPanel(reg.getPanel(0));
51076 * Returns the nested BorderLayout for this panel
51077 * @return {Roo.BorderLayout}
51079 getLayout : function(){
51080 return this.layout;
51084 * Adds a xtype elements to the layout of the nested panel
51088 xtype : 'ContentPanel',
51095 xtype : 'NestedLayoutPanel',
51101 items : [ ... list of content panels or nested layout panels.. ]
51105 * @param {Object} cfg Xtype definition of item to add.
51107 addxtype : function(cfg) {
51108 return this.layout.addxtype(cfg);
51113 Roo.ScrollPanel = function(el, config, content){
51114 config = config || {};
51115 config.fitToFrame = true;
51116 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51118 this.el.dom.style.overflow = "hidden";
51119 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51120 this.el.removeClass("x-layout-inactive-content");
51121 this.el.on("mousewheel", this.onWheel, this);
51123 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51124 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51125 up.unselectable(); down.unselectable();
51126 up.on("click", this.scrollUp, this);
51127 down.on("click", this.scrollDown, this);
51128 up.addClassOnOver("x-scroller-btn-over");
51129 down.addClassOnOver("x-scroller-btn-over");
51130 up.addClassOnClick("x-scroller-btn-click");
51131 down.addClassOnClick("x-scroller-btn-click");
51132 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51134 this.resizeEl = this.el;
51135 this.el = wrap; this.up = up; this.down = down;
51138 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51140 wheelIncrement : 5,
51141 scrollUp : function(){
51142 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51145 scrollDown : function(){
51146 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51149 afterScroll : function(){
51150 var el = this.resizeEl;
51151 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51152 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51153 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51156 setSize : function(){
51157 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51158 this.afterScroll();
51161 onWheel : function(e){
51162 var d = e.getWheelDelta();
51163 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51164 this.afterScroll();
51168 setContent : function(content, loadScripts){
51169 this.resizeEl.update(content, loadScripts);
51183 * @class Roo.TreePanel
51184 * @extends Roo.ContentPanel
51186 * Create a new TreePanel. - defaults to fit/scoll contents.
51187 * @param {String/Object} config A string to set only the panel's title, or a config object
51188 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51190 Roo.TreePanel = function(config){
51191 var el = config.el;
51192 var tree = config.tree;
51193 delete config.tree;
51194 delete config.el; // hopefull!
51196 // wrapper for IE7 strict & safari scroll issue
51198 var treeEl = el.createChild();
51199 config.resizeEl = treeEl;
51203 Roo.TreePanel.superclass.constructor.call(this, el, config);
51206 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51207 //console.log(tree);
51208 this.on('activate', function()
51210 if (this.tree.rendered) {
51213 //console.log('render tree');
51214 this.tree.render();
51216 // this should not be needed.. - it's actually the 'el' that resizes?
51217 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51219 //this.on('resize', function (cp, w, h) {
51220 // this.tree.innerCt.setWidth(w);
51221 // this.tree.innerCt.setHeight(h);
51222 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51229 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51246 * Ext JS Library 1.1.1
51247 * Copyright(c) 2006-2007, Ext JS, LLC.
51249 * Originally Released Under LGPL - original licence link has changed is not relivant.
51252 * <script type="text/javascript">
51257 * @class Roo.ReaderLayout
51258 * @extends Roo.BorderLayout
51259 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51260 * center region containing two nested regions (a top one for a list view and one for item preview below),
51261 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51262 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51263 * expedites the setup of the overall layout and regions for this common application style.
51266 var reader = new Roo.ReaderLayout();
51267 var CP = Roo.ContentPanel; // shortcut for adding
51269 reader.beginUpdate();
51270 reader.add("north", new CP("north", "North"));
51271 reader.add("west", new CP("west", {title: "West"}));
51272 reader.add("east", new CP("east", {title: "East"}));
51274 reader.regions.listView.add(new CP("listView", "List"));
51275 reader.regions.preview.add(new CP("preview", "Preview"));
51276 reader.endUpdate();
51279 * Create a new ReaderLayout
51280 * @param {Object} config Configuration options
51281 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51282 * document.body if omitted)
51284 Roo.ReaderLayout = function(config, renderTo){
51285 var c = config || {size:{}};
51286 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51287 north: c.north !== false ? Roo.apply({
51291 }, c.north) : false,
51292 west: c.west !== false ? Roo.apply({
51300 margins:{left:5,right:0,bottom:5,top:5},
51301 cmargins:{left:5,right:5,bottom:5,top:5}
51302 }, c.west) : false,
51303 east: c.east !== false ? Roo.apply({
51311 margins:{left:0,right:5,bottom:5,top:5},
51312 cmargins:{left:5,right:5,bottom:5,top:5}
51313 }, c.east) : false,
51314 center: Roo.apply({
51315 tabPosition: 'top',
51319 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51323 this.el.addClass('x-reader');
51325 this.beginUpdate();
51327 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51328 south: c.preview !== false ? Roo.apply({
51335 cmargins:{top:5,left:0, right:0, bottom:0}
51336 }, c.preview) : false,
51337 center: Roo.apply({
51343 this.add('center', new Roo.NestedLayoutPanel(inner,
51344 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51348 this.regions.preview = inner.getRegion('south');
51349 this.regions.listView = inner.getRegion('center');
51352 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51354 * Ext JS Library 1.1.1
51355 * Copyright(c) 2006-2007, Ext JS, LLC.
51357 * Originally Released Under LGPL - original licence link has changed is not relivant.
51360 * <script type="text/javascript">
51364 * @class Roo.grid.Grid
51365 * @extends Roo.util.Observable
51366 * This class represents the primary interface of a component based grid control.
51367 * <br><br>Usage:<pre><code>
51368 var grid = new Roo.grid.Grid("my-container-id", {
51371 selModel: mySelectionModel,
51372 autoSizeColumns: true,
51373 monitorWindowResize: false,
51374 trackMouseOver: true
51379 * <b>Common Problems:</b><br/>
51380 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51381 * element will correct this<br/>
51382 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51383 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51384 * are unpredictable.<br/>
51385 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51386 * grid to calculate dimensions/offsets.<br/>
51388 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51389 * The container MUST have some type of size defined for the grid to fill. The container will be
51390 * automatically set to position relative if it isn't already.
51391 * @param {Object} config A config object that sets properties on this grid.
51393 Roo.grid.Grid = function(container, config){
51394 // initialize the container
51395 this.container = Roo.get(container);
51396 this.container.update("");
51397 this.container.setStyle("overflow", "hidden");
51398 this.container.addClass('x-grid-container');
51400 this.id = this.container.id;
51402 Roo.apply(this, config);
51403 // check and correct shorthanded configs
51405 this.dataSource = this.ds;
51409 this.colModel = this.cm;
51413 this.selModel = this.sm;
51417 if (this.selModel) {
51418 this.selModel = Roo.factory(this.selModel, Roo.grid);
51419 this.sm = this.selModel;
51420 this.sm.xmodule = this.xmodule || false;
51422 if (typeof(this.colModel.config) == 'undefined') {
51423 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51424 this.cm = this.colModel;
51425 this.cm.xmodule = this.xmodule || false;
51427 if (this.dataSource) {
51428 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51429 this.ds = this.dataSource;
51430 this.ds.xmodule = this.xmodule || false;
51437 this.container.setWidth(this.width);
51441 this.container.setHeight(this.height);
51448 * The raw click event for the entire grid.
51449 * @param {Roo.EventObject} e
51454 * The raw dblclick event for the entire grid.
51455 * @param {Roo.EventObject} e
51459 * @event contextmenu
51460 * The raw contextmenu event for the entire grid.
51461 * @param {Roo.EventObject} e
51463 "contextmenu" : true,
51466 * The raw mousedown event for the entire grid.
51467 * @param {Roo.EventObject} e
51469 "mousedown" : true,
51472 * The raw mouseup event for the entire grid.
51473 * @param {Roo.EventObject} e
51478 * The raw mouseover event for the entire grid.
51479 * @param {Roo.EventObject} e
51481 "mouseover" : true,
51484 * The raw mouseout event for the entire grid.
51485 * @param {Roo.EventObject} e
51490 * The raw keypress event for the entire grid.
51491 * @param {Roo.EventObject} e
51496 * The raw keydown event for the entire grid.
51497 * @param {Roo.EventObject} e
51505 * Fires when a cell is clicked
51506 * @param {Grid} this
51507 * @param {Number} rowIndex
51508 * @param {Number} columnIndex
51509 * @param {Roo.EventObject} e
51511 "cellclick" : true,
51513 * @event celldblclick
51514 * Fires when a cell is double clicked
51515 * @param {Grid} this
51516 * @param {Number} rowIndex
51517 * @param {Number} columnIndex
51518 * @param {Roo.EventObject} e
51520 "celldblclick" : true,
51523 * Fires when a row is clicked
51524 * @param {Grid} this
51525 * @param {Number} rowIndex
51526 * @param {Roo.EventObject} e
51530 * @event rowdblclick
51531 * Fires when a row is double clicked
51532 * @param {Grid} this
51533 * @param {Number} rowIndex
51534 * @param {Roo.EventObject} e
51536 "rowdblclick" : true,
51538 * @event headerclick
51539 * Fires when a header is clicked
51540 * @param {Grid} this
51541 * @param {Number} columnIndex
51542 * @param {Roo.EventObject} e
51544 "headerclick" : true,
51546 * @event headerdblclick
51547 * Fires when a header cell is double clicked
51548 * @param {Grid} this
51549 * @param {Number} columnIndex
51550 * @param {Roo.EventObject} e
51552 "headerdblclick" : true,
51554 * @event rowcontextmenu
51555 * Fires when a row is right clicked
51556 * @param {Grid} this
51557 * @param {Number} rowIndex
51558 * @param {Roo.EventObject} e
51560 "rowcontextmenu" : true,
51562 * @event cellcontextmenu
51563 * Fires when a cell is right clicked
51564 * @param {Grid} this
51565 * @param {Number} rowIndex
51566 * @param {Number} cellIndex
51567 * @param {Roo.EventObject} e
51569 "cellcontextmenu" : true,
51571 * @event headercontextmenu
51572 * Fires when a header is right clicked
51573 * @param {Grid} this
51574 * @param {Number} columnIndex
51575 * @param {Roo.EventObject} e
51577 "headercontextmenu" : true,
51579 * @event bodyscroll
51580 * Fires when the body element is scrolled
51581 * @param {Number} scrollLeft
51582 * @param {Number} scrollTop
51584 "bodyscroll" : true,
51586 * @event columnresize
51587 * Fires when the user resizes a column
51588 * @param {Number} columnIndex
51589 * @param {Number} newSize
51591 "columnresize" : true,
51593 * @event columnmove
51594 * Fires when the user moves a column
51595 * @param {Number} oldIndex
51596 * @param {Number} newIndex
51598 "columnmove" : true,
51601 * Fires when row(s) start being dragged
51602 * @param {Grid} this
51603 * @param {Roo.GridDD} dd The drag drop object
51604 * @param {event} e The raw browser event
51606 "startdrag" : true,
51609 * Fires when a drag operation is complete
51610 * @param {Grid} this
51611 * @param {Roo.GridDD} dd The drag drop object
51612 * @param {event} e The raw browser event
51617 * Fires when dragged row(s) are dropped on a valid DD target
51618 * @param {Grid} this
51619 * @param {Roo.GridDD} dd The drag drop object
51620 * @param {String} targetId The target drag drop object
51621 * @param {event} e The raw browser event
51626 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51627 * @param {Grid} this
51628 * @param {Roo.GridDD} dd The drag drop object
51629 * @param {String} targetId The target drag drop object
51630 * @param {event} e The raw browser event
51635 * Fires when the dragged row(s) first cross another DD target while being dragged
51636 * @param {Grid} this
51637 * @param {Roo.GridDD} dd The drag drop object
51638 * @param {String} targetId The target drag drop object
51639 * @param {event} e The raw browser event
51641 "dragenter" : true,
51644 * Fires when the dragged row(s) leave another DD target while being dragged
51645 * @param {Grid} this
51646 * @param {Roo.GridDD} dd The drag drop object
51647 * @param {String} targetId The target drag drop object
51648 * @param {event} e The raw browser event
51653 * Fires when a row is rendered, so you can change add a style to it.
51654 * @param {GridView} gridview The grid view
51655 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51661 * Fires when the grid is rendered
51662 * @param {Grid} grid
51667 Roo.grid.Grid.superclass.constructor.call(this);
51669 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51672 * @cfg {String} ddGroup - drag drop group.
51676 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51678 minColumnWidth : 25,
51681 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51682 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51683 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51685 autoSizeColumns : false,
51688 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51690 autoSizeHeaders : true,
51693 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51695 monitorWindowResize : true,
51698 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51699 * rows measured to get a columns size. Default is 0 (all rows).
51701 maxRowsToMeasure : 0,
51704 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51706 trackMouseOver : true,
51709 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
51713 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
51715 enableDragDrop : false,
51718 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
51720 enableColumnMove : true,
51723 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
51725 enableColumnHide : true,
51728 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
51730 enableRowHeightSync : false,
51733 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
51738 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
51740 autoHeight : false,
51743 * @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.
51745 autoExpandColumn : false,
51748 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
51751 autoExpandMin : 50,
51754 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
51756 autoExpandMax : 1000,
51759 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
51764 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
51768 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
51778 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
51779 * of a fixed width. Default is false.
51782 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
51785 * Called once after all setup has been completed and the grid is ready to be rendered.
51786 * @return {Roo.grid.Grid} this
51788 render : function()
51790 var c = this.container;
51791 // try to detect autoHeight/width mode
51792 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
51793 this.autoHeight = true;
51795 var view = this.getView();
51798 c.on("click", this.onClick, this);
51799 c.on("dblclick", this.onDblClick, this);
51800 c.on("contextmenu", this.onContextMenu, this);
51801 c.on("keydown", this.onKeyDown, this);
51803 c.on("touchstart", this.onTouchStart, this);
51806 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
51808 this.getSelectionModel().init(this);
51813 this.loadMask = new Roo.LoadMask(this.container,
51814 Roo.apply({store:this.dataSource}, this.loadMask));
51818 if (this.toolbar && this.toolbar.xtype) {
51819 this.toolbar.container = this.getView().getHeaderPanel(true);
51820 this.toolbar = new Roo.Toolbar(this.toolbar);
51822 if (this.footer && this.footer.xtype) {
51823 this.footer.dataSource = this.getDataSource();
51824 this.footer.container = this.getView().getFooterPanel(true);
51825 this.footer = Roo.factory(this.footer, Roo);
51827 if (this.dropTarget && this.dropTarget.xtype) {
51828 delete this.dropTarget.xtype;
51829 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
51833 this.rendered = true;
51834 this.fireEvent('render', this);
51839 * Reconfigures the grid to use a different Store and Column Model.
51840 * The View will be bound to the new objects and refreshed.
51841 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
51842 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
51844 reconfigure : function(dataSource, colModel){
51846 this.loadMask.destroy();
51847 this.loadMask = new Roo.LoadMask(this.container,
51848 Roo.apply({store:dataSource}, this.loadMask));
51850 this.view.bind(dataSource, colModel);
51851 this.dataSource = dataSource;
51852 this.colModel = colModel;
51853 this.view.refresh(true);
51857 onKeyDown : function(e){
51858 this.fireEvent("keydown", e);
51862 * Destroy this grid.
51863 * @param {Boolean} removeEl True to remove the element
51865 destroy : function(removeEl, keepListeners){
51867 this.loadMask.destroy();
51869 var c = this.container;
51870 c.removeAllListeners();
51871 this.view.destroy();
51872 this.colModel.purgeListeners();
51873 if(!keepListeners){
51874 this.purgeListeners();
51877 if(removeEl === true){
51883 processEvent : function(name, e){
51884 // does this fire select???
51885 Roo.log('grid:processEvent ' + name);
51887 if (name != 'touchstart' ) {
51888 this.fireEvent(name, e);
51891 var t = e.getTarget();
51893 var header = v.findHeaderIndex(t);
51894 if(header !== false){
51895 var ename = name == 'touchstart' ? 'click' : name;
51897 this.fireEvent("header" + ename, this, header, e);
51899 var row = v.findRowIndex(t);
51900 var cell = v.findCellIndex(t);
51901 if (name == 'touchstart') {
51902 // first touch is always a click.
51903 // hopefull this happens after selection is updated.?
51906 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
51907 var cs = this.selModel.getSelectedCell();
51908 if (row == cs[0] && cell == cs[1]){
51912 if (typeof(this.selModel.getSelections) != 'undefined') {
51913 var cs = this.selModel.getSelections();
51914 var ds = this.dataSource;
51915 if (cs.length == 1 && ds.getAt(row) == cs[0]){
51926 this.fireEvent("row" + name, this, row, e);
51927 if(cell !== false){
51928 this.fireEvent("cell" + name, this, row, cell, e);
51935 onClick : function(e){
51936 this.processEvent("click", e);
51939 onTouchStart : function(e){
51940 this.processEvent("touchstart", e);
51944 onContextMenu : function(e, t){
51945 this.processEvent("contextmenu", e);
51949 onDblClick : function(e){
51950 this.processEvent("dblclick", e);
51954 walkCells : function(row, col, step, fn, scope){
51955 var cm = this.colModel, clen = cm.getColumnCount();
51956 var ds = this.dataSource, rlen = ds.getCount(), first = true;
51968 if(fn.call(scope || this, row, col, cm) === true){
51986 if(fn.call(scope || this, row, col, cm) === true){
51998 getSelections : function(){
51999 return this.selModel.getSelections();
52003 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52004 * but if manual update is required this method will initiate it.
52006 autoSize : function(){
52008 this.view.layout();
52009 if(this.view.adjustForScroll){
52010 this.view.adjustForScroll();
52016 * Returns the grid's underlying element.
52017 * @return {Element} The element
52019 getGridEl : function(){
52020 return this.container;
52023 // private for compatibility, overridden by editor grid
52024 stopEditing : function(){},
52027 * Returns the grid's SelectionModel.
52028 * @return {SelectionModel}
52030 getSelectionModel : function(){
52031 if(!this.selModel){
52032 this.selModel = new Roo.grid.RowSelectionModel();
52034 return this.selModel;
52038 * Returns the grid's DataSource.
52039 * @return {DataSource}
52041 getDataSource : function(){
52042 return this.dataSource;
52046 * Returns the grid's ColumnModel.
52047 * @return {ColumnModel}
52049 getColumnModel : function(){
52050 return this.colModel;
52054 * Returns the grid's GridView object.
52055 * @return {GridView}
52057 getView : function(){
52059 this.view = new Roo.grid.GridView(this.viewConfig);
52064 * Called to get grid's drag proxy text, by default returns this.ddText.
52067 getDragDropText : function(){
52068 var count = this.selModel.getCount();
52069 return String.format(this.ddText, count, count == 1 ? '' : 's');
52073 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52074 * %0 is replaced with the number of selected rows.
52077 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52079 * Ext JS Library 1.1.1
52080 * Copyright(c) 2006-2007, Ext JS, LLC.
52082 * Originally Released Under LGPL - original licence link has changed is not relivant.
52085 * <script type="text/javascript">
52088 Roo.grid.AbstractGridView = function(){
52092 "beforerowremoved" : true,
52093 "beforerowsinserted" : true,
52094 "beforerefresh" : true,
52095 "rowremoved" : true,
52096 "rowsinserted" : true,
52097 "rowupdated" : true,
52100 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52103 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52104 rowClass : "x-grid-row",
52105 cellClass : "x-grid-cell",
52106 tdClass : "x-grid-td",
52107 hdClass : "x-grid-hd",
52108 splitClass : "x-grid-hd-split",
52110 init: function(grid){
52112 var cid = this.grid.getGridEl().id;
52113 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52114 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52115 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52116 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52119 getColumnRenderers : function(){
52120 var renderers = [];
52121 var cm = this.grid.colModel;
52122 var colCount = cm.getColumnCount();
52123 for(var i = 0; i < colCount; i++){
52124 renderers[i] = cm.getRenderer(i);
52129 getColumnIds : function(){
52131 var cm = this.grid.colModel;
52132 var colCount = cm.getColumnCount();
52133 for(var i = 0; i < colCount; i++){
52134 ids[i] = cm.getColumnId(i);
52139 getDataIndexes : function(){
52140 if(!this.indexMap){
52141 this.indexMap = this.buildIndexMap();
52143 return this.indexMap.colToData;
52146 getColumnIndexByDataIndex : function(dataIndex){
52147 if(!this.indexMap){
52148 this.indexMap = this.buildIndexMap();
52150 return this.indexMap.dataToCol[dataIndex];
52154 * Set a css style for a column dynamically.
52155 * @param {Number} colIndex The index of the column
52156 * @param {String} name The css property name
52157 * @param {String} value The css value
52159 setCSSStyle : function(colIndex, name, value){
52160 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52161 Roo.util.CSS.updateRule(selector, name, value);
52164 generateRules : function(cm){
52165 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52166 Roo.util.CSS.removeStyleSheet(rulesId);
52167 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52168 var cid = cm.getColumnId(i);
52169 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52170 this.tdSelector, cid, " {\n}\n",
52171 this.hdSelector, cid, " {\n}\n",
52172 this.splitSelector, cid, " {\n}\n");
52174 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52178 * Ext JS Library 1.1.1
52179 * Copyright(c) 2006-2007, Ext JS, LLC.
52181 * Originally Released Under LGPL - original licence link has changed is not relivant.
52184 * <script type="text/javascript">
52188 // This is a support class used internally by the Grid components
52189 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52191 this.view = grid.getView();
52192 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52193 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52195 this.setHandleElId(Roo.id(hd));
52196 this.setOuterHandleElId(Roo.id(hd2));
52198 this.scroll = false;
52200 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52202 getDragData : function(e){
52203 var t = Roo.lib.Event.getTarget(e);
52204 var h = this.view.findHeaderCell(t);
52206 return {ddel: h.firstChild, header:h};
52211 onInitDrag : function(e){
52212 this.view.headersDisabled = true;
52213 var clone = this.dragData.ddel.cloneNode(true);
52214 clone.id = Roo.id();
52215 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52216 this.proxy.update(clone);
52220 afterValidDrop : function(){
52222 setTimeout(function(){
52223 v.headersDisabled = false;
52227 afterInvalidDrop : function(){
52229 setTimeout(function(){
52230 v.headersDisabled = false;
52236 * Ext JS Library 1.1.1
52237 * Copyright(c) 2006-2007, Ext JS, LLC.
52239 * Originally Released Under LGPL - original licence link has changed is not relivant.
52242 * <script type="text/javascript">
52245 // This is a support class used internally by the Grid components
52246 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52248 this.view = grid.getView();
52249 // split the proxies so they don't interfere with mouse events
52250 this.proxyTop = Roo.DomHelper.append(document.body, {
52251 cls:"col-move-top", html:" "
52253 this.proxyBottom = Roo.DomHelper.append(document.body, {
52254 cls:"col-move-bottom", html:" "
52256 this.proxyTop.hide = this.proxyBottom.hide = function(){
52257 this.setLeftTop(-100,-100);
52258 this.setStyle("visibility", "hidden");
52260 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52261 // temporarily disabled
52262 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52263 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52265 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52266 proxyOffsets : [-4, -9],
52267 fly: Roo.Element.fly,
52269 getTargetFromEvent : function(e){
52270 var t = Roo.lib.Event.getTarget(e);
52271 var cindex = this.view.findCellIndex(t);
52272 if(cindex !== false){
52273 return this.view.getHeaderCell(cindex);
52278 nextVisible : function(h){
52279 var v = this.view, cm = this.grid.colModel;
52282 if(!cm.isHidden(v.getCellIndex(h))){
52290 prevVisible : function(h){
52291 var v = this.view, cm = this.grid.colModel;
52294 if(!cm.isHidden(v.getCellIndex(h))){
52302 positionIndicator : function(h, n, e){
52303 var x = Roo.lib.Event.getPageX(e);
52304 var r = Roo.lib.Dom.getRegion(n.firstChild);
52305 var px, pt, py = r.top + this.proxyOffsets[1];
52306 if((r.right - x) <= (r.right-r.left)/2){
52307 px = r.right+this.view.borderWidth;
52313 var oldIndex = this.view.getCellIndex(h);
52314 var newIndex = this.view.getCellIndex(n);
52316 if(this.grid.colModel.isFixed(newIndex)){
52320 var locked = this.grid.colModel.isLocked(newIndex);
52325 if(oldIndex < newIndex){
52328 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52331 px += this.proxyOffsets[0];
52332 this.proxyTop.setLeftTop(px, py);
52333 this.proxyTop.show();
52334 if(!this.bottomOffset){
52335 this.bottomOffset = this.view.mainHd.getHeight();
52337 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52338 this.proxyBottom.show();
52342 onNodeEnter : function(n, dd, e, data){
52343 if(data.header != n){
52344 this.positionIndicator(data.header, n, e);
52348 onNodeOver : function(n, dd, e, data){
52349 var result = false;
52350 if(data.header != n){
52351 result = this.positionIndicator(data.header, n, e);
52354 this.proxyTop.hide();
52355 this.proxyBottom.hide();
52357 return result ? this.dropAllowed : this.dropNotAllowed;
52360 onNodeOut : function(n, dd, e, data){
52361 this.proxyTop.hide();
52362 this.proxyBottom.hide();
52365 onNodeDrop : function(n, dd, e, data){
52366 var h = data.header;
52368 var cm = this.grid.colModel;
52369 var x = Roo.lib.Event.getPageX(e);
52370 var r = Roo.lib.Dom.getRegion(n.firstChild);
52371 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52372 var oldIndex = this.view.getCellIndex(h);
52373 var newIndex = this.view.getCellIndex(n);
52374 var locked = cm.isLocked(newIndex);
52378 if(oldIndex < newIndex){
52381 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52384 cm.setLocked(oldIndex, locked, true);
52385 cm.moveColumn(oldIndex, newIndex);
52386 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52394 * Ext JS Library 1.1.1
52395 * Copyright(c) 2006-2007, Ext JS, LLC.
52397 * Originally Released Under LGPL - original licence link has changed is not relivant.
52400 * <script type="text/javascript">
52404 * @class Roo.grid.GridView
52405 * @extends Roo.util.Observable
52408 * @param {Object} config
52410 Roo.grid.GridView = function(config){
52411 Roo.grid.GridView.superclass.constructor.call(this);
52414 Roo.apply(this, config);
52417 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52419 unselectable : 'unselectable="on"',
52420 unselectableCls : 'x-unselectable',
52423 rowClass : "x-grid-row",
52425 cellClass : "x-grid-col",
52427 tdClass : "x-grid-td",
52429 hdClass : "x-grid-hd",
52431 splitClass : "x-grid-split",
52433 sortClasses : ["sort-asc", "sort-desc"],
52435 enableMoveAnim : false,
52439 dh : Roo.DomHelper,
52441 fly : Roo.Element.fly,
52443 css : Roo.util.CSS,
52449 scrollIncrement : 22,
52451 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52453 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52455 bind : function(ds, cm){
52457 this.ds.un("load", this.onLoad, this);
52458 this.ds.un("datachanged", this.onDataChange, this);
52459 this.ds.un("add", this.onAdd, this);
52460 this.ds.un("remove", this.onRemove, this);
52461 this.ds.un("update", this.onUpdate, this);
52462 this.ds.un("clear", this.onClear, this);
52465 ds.on("load", this.onLoad, this);
52466 ds.on("datachanged", this.onDataChange, this);
52467 ds.on("add", this.onAdd, this);
52468 ds.on("remove", this.onRemove, this);
52469 ds.on("update", this.onUpdate, this);
52470 ds.on("clear", this.onClear, this);
52475 this.cm.un("widthchange", this.onColWidthChange, this);
52476 this.cm.un("headerchange", this.onHeaderChange, this);
52477 this.cm.un("hiddenchange", this.onHiddenChange, this);
52478 this.cm.un("columnmoved", this.onColumnMove, this);
52479 this.cm.un("columnlockchange", this.onColumnLock, this);
52482 this.generateRules(cm);
52483 cm.on("widthchange", this.onColWidthChange, this);
52484 cm.on("headerchange", this.onHeaderChange, this);
52485 cm.on("hiddenchange", this.onHiddenChange, this);
52486 cm.on("columnmoved", this.onColumnMove, this);
52487 cm.on("columnlockchange", this.onColumnLock, this);
52492 init: function(grid){
52493 Roo.grid.GridView.superclass.init.call(this, grid);
52495 this.bind(grid.dataSource, grid.colModel);
52497 grid.on("headerclick", this.handleHeaderClick, this);
52499 if(grid.trackMouseOver){
52500 grid.on("mouseover", this.onRowOver, this);
52501 grid.on("mouseout", this.onRowOut, this);
52503 grid.cancelTextSelection = function(){};
52504 this.gridId = grid.id;
52506 var tpls = this.templates || {};
52509 tpls.master = new Roo.Template(
52510 '<div class="x-grid" hidefocus="true">',
52511 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52512 '<div class="x-grid-topbar"></div>',
52513 '<div class="x-grid-scroller"><div></div></div>',
52514 '<div class="x-grid-locked">',
52515 '<div class="x-grid-header">{lockedHeader}</div>',
52516 '<div class="x-grid-body">{lockedBody}</div>',
52518 '<div class="x-grid-viewport">',
52519 '<div class="x-grid-header">{header}</div>',
52520 '<div class="x-grid-body">{body}</div>',
52522 '<div class="x-grid-bottombar"></div>',
52524 '<div class="x-grid-resize-proxy"> </div>',
52527 tpls.master.disableformats = true;
52531 tpls.header = new Roo.Template(
52532 '<table border="0" cellspacing="0" cellpadding="0">',
52533 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52536 tpls.header.disableformats = true;
52538 tpls.header.compile();
52541 tpls.hcell = new Roo.Template(
52542 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52543 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52546 tpls.hcell.disableFormats = true;
52548 tpls.hcell.compile();
52551 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52552 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52553 tpls.hsplit.disableFormats = true;
52555 tpls.hsplit.compile();
52558 tpls.body = new Roo.Template(
52559 '<table border="0" cellspacing="0" cellpadding="0">',
52560 "<tbody>{rows}</tbody>",
52563 tpls.body.disableFormats = true;
52565 tpls.body.compile();
52568 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52569 tpls.row.disableFormats = true;
52571 tpls.row.compile();
52574 tpls.cell = new Roo.Template(
52575 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52576 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52577 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52580 tpls.cell.disableFormats = true;
52582 tpls.cell.compile();
52584 this.templates = tpls;
52587 // remap these for backwards compat
52588 onColWidthChange : function(){
52589 this.updateColumns.apply(this, arguments);
52591 onHeaderChange : function(){
52592 this.updateHeaders.apply(this, arguments);
52594 onHiddenChange : function(){
52595 this.handleHiddenChange.apply(this, arguments);
52597 onColumnMove : function(){
52598 this.handleColumnMove.apply(this, arguments);
52600 onColumnLock : function(){
52601 this.handleLockChange.apply(this, arguments);
52604 onDataChange : function(){
52606 this.updateHeaderSortState();
52609 onClear : function(){
52613 onUpdate : function(ds, record){
52614 this.refreshRow(record);
52617 refreshRow : function(record){
52618 var ds = this.ds, index;
52619 if(typeof record == 'number'){
52621 record = ds.getAt(index);
52623 index = ds.indexOf(record);
52625 this.insertRows(ds, index, index, true);
52626 this.onRemove(ds, record, index+1, true);
52627 this.syncRowHeights(index, index);
52629 this.fireEvent("rowupdated", this, index, record);
52632 onAdd : function(ds, records, index){
52633 this.insertRows(ds, index, index + (records.length-1));
52636 onRemove : function(ds, record, index, isUpdate){
52637 if(isUpdate !== true){
52638 this.fireEvent("beforerowremoved", this, index, record);
52640 var bt = this.getBodyTable(), lt = this.getLockedTable();
52641 if(bt.rows[index]){
52642 bt.firstChild.removeChild(bt.rows[index]);
52644 if(lt.rows[index]){
52645 lt.firstChild.removeChild(lt.rows[index]);
52647 if(isUpdate !== true){
52648 this.stripeRows(index);
52649 this.syncRowHeights(index, index);
52651 this.fireEvent("rowremoved", this, index, record);
52655 onLoad : function(){
52656 this.scrollToTop();
52660 * Scrolls the grid to the top
52662 scrollToTop : function(){
52664 this.scroller.dom.scrollTop = 0;
52670 * Gets a panel in the header of the grid that can be used for toolbars etc.
52671 * After modifying the contents of this panel a call to grid.autoSize() may be
52672 * required to register any changes in size.
52673 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52674 * @return Roo.Element
52676 getHeaderPanel : function(doShow){
52678 this.headerPanel.show();
52680 return this.headerPanel;
52684 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52685 * After modifying the contents of this panel a call to grid.autoSize() may be
52686 * required to register any changes in size.
52687 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52688 * @return Roo.Element
52690 getFooterPanel : function(doShow){
52692 this.footerPanel.show();
52694 return this.footerPanel;
52697 initElements : function(){
52698 var E = Roo.Element;
52699 var el = this.grid.getGridEl().dom.firstChild;
52700 var cs = el.childNodes;
52702 this.el = new E(el);
52704 this.focusEl = new E(el.firstChild);
52705 this.focusEl.swallowEvent("click", true);
52707 this.headerPanel = new E(cs[1]);
52708 this.headerPanel.enableDisplayMode("block");
52710 this.scroller = new E(cs[2]);
52711 this.scrollSizer = new E(this.scroller.dom.firstChild);
52713 this.lockedWrap = new E(cs[3]);
52714 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
52715 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
52717 this.mainWrap = new E(cs[4]);
52718 this.mainHd = new E(this.mainWrap.dom.firstChild);
52719 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
52721 this.footerPanel = new E(cs[5]);
52722 this.footerPanel.enableDisplayMode("block");
52724 this.resizeProxy = new E(cs[6]);
52726 this.headerSelector = String.format(
52727 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
52728 this.lockedHd.id, this.mainHd.id
52731 this.splitterSelector = String.format(
52732 '#{0} div.x-grid-split, #{1} div.x-grid-split',
52733 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
52736 idToCssName : function(s)
52738 return s.replace(/[^a-z0-9]+/ig, '-');
52741 getHeaderCell : function(index){
52742 return Roo.DomQuery.select(this.headerSelector)[index];
52745 getHeaderCellMeasure : function(index){
52746 return this.getHeaderCell(index).firstChild;
52749 getHeaderCellText : function(index){
52750 return this.getHeaderCell(index).firstChild.firstChild;
52753 getLockedTable : function(){
52754 return this.lockedBody.dom.firstChild;
52757 getBodyTable : function(){
52758 return this.mainBody.dom.firstChild;
52761 getLockedRow : function(index){
52762 return this.getLockedTable().rows[index];
52765 getRow : function(index){
52766 return this.getBodyTable().rows[index];
52769 getRowComposite : function(index){
52771 this.rowEl = new Roo.CompositeElementLite();
52773 var els = [], lrow, mrow;
52774 if(lrow = this.getLockedRow(index)){
52777 if(mrow = this.getRow(index)){
52780 this.rowEl.elements = els;
52784 * Gets the 'td' of the cell
52786 * @param {Integer} rowIndex row to select
52787 * @param {Integer} colIndex column to select
52791 getCell : function(rowIndex, colIndex){
52792 var locked = this.cm.getLockedCount();
52794 if(colIndex < locked){
52795 source = this.lockedBody.dom.firstChild;
52797 source = this.mainBody.dom.firstChild;
52798 colIndex -= locked;
52800 return source.rows[rowIndex].childNodes[colIndex];
52803 getCellText : function(rowIndex, colIndex){
52804 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
52807 getCellBox : function(cell){
52808 var b = this.fly(cell).getBox();
52809 if(Roo.isOpera){ // opera fails to report the Y
52810 b.y = cell.offsetTop + this.mainBody.getY();
52815 getCellIndex : function(cell){
52816 var id = String(cell.className).match(this.cellRE);
52818 return parseInt(id[1], 10);
52823 findHeaderIndex : function(n){
52824 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52825 return r ? this.getCellIndex(r) : false;
52828 findHeaderCell : function(n){
52829 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
52830 return r ? r : false;
52833 findRowIndex : function(n){
52837 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
52838 return r ? r.rowIndex : false;
52841 findCellIndex : function(node){
52842 var stop = this.el.dom;
52843 while(node && node != stop){
52844 if(this.findRE.test(node.className)){
52845 return this.getCellIndex(node);
52847 node = node.parentNode;
52852 getColumnId : function(index){
52853 return this.cm.getColumnId(index);
52856 getSplitters : function()
52858 if(this.splitterSelector){
52859 return Roo.DomQuery.select(this.splitterSelector);
52865 getSplitter : function(index){
52866 return this.getSplitters()[index];
52869 onRowOver : function(e, t){
52871 if((row = this.findRowIndex(t)) !== false){
52872 this.getRowComposite(row).addClass("x-grid-row-over");
52876 onRowOut : function(e, t){
52878 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
52879 this.getRowComposite(row).removeClass("x-grid-row-over");
52883 renderHeaders : function(){
52885 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
52886 var cb = [], lb = [], sb = [], lsb = [], p = {};
52887 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52888 p.cellId = "x-grid-hd-0-" + i;
52889 p.splitId = "x-grid-csplit-0-" + i;
52890 p.id = cm.getColumnId(i);
52891 p.title = cm.getColumnTooltip(i) || "";
52892 p.value = cm.getColumnHeader(i) || "";
52893 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
52894 if(!cm.isLocked(i)){
52895 cb[cb.length] = ct.apply(p);
52896 sb[sb.length] = st.apply(p);
52898 lb[lb.length] = ct.apply(p);
52899 lsb[lsb.length] = st.apply(p);
52902 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
52903 ht.apply({cells: cb.join(""), splits:sb.join("")})];
52906 updateHeaders : function(){
52907 var html = this.renderHeaders();
52908 this.lockedHd.update(html[0]);
52909 this.mainHd.update(html[1]);
52913 * Focuses the specified row.
52914 * @param {Number} row The row index
52916 focusRow : function(row)
52918 //Roo.log('GridView.focusRow');
52919 var x = this.scroller.dom.scrollLeft;
52920 this.focusCell(row, 0, false);
52921 this.scroller.dom.scrollLeft = x;
52925 * Focuses the specified cell.
52926 * @param {Number} row The row index
52927 * @param {Number} col The column index
52928 * @param {Boolean} hscroll false to disable horizontal scrolling
52930 focusCell : function(row, col, hscroll)
52932 //Roo.log('GridView.focusCell');
52933 var el = this.ensureVisible(row, col, hscroll);
52934 this.focusEl.alignTo(el, "tl-tl");
52936 this.focusEl.focus();
52938 this.focusEl.focus.defer(1, this.focusEl);
52943 * Scrolls the specified cell into view
52944 * @param {Number} row The row index
52945 * @param {Number} col The column index
52946 * @param {Boolean} hscroll false to disable horizontal scrolling
52948 ensureVisible : function(row, col, hscroll)
52950 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
52951 //return null; //disable for testing.
52952 if(typeof row != "number"){
52953 row = row.rowIndex;
52955 if(row < 0 && row >= this.ds.getCount()){
52958 col = (col !== undefined ? col : 0);
52959 var cm = this.grid.colModel;
52960 while(cm.isHidden(col)){
52964 var el = this.getCell(row, col);
52968 var c = this.scroller.dom;
52970 var ctop = parseInt(el.offsetTop, 10);
52971 var cleft = parseInt(el.offsetLeft, 10);
52972 var cbot = ctop + el.offsetHeight;
52973 var cright = cleft + el.offsetWidth;
52975 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
52976 var stop = parseInt(c.scrollTop, 10);
52977 var sleft = parseInt(c.scrollLeft, 10);
52978 var sbot = stop + ch;
52979 var sright = sleft + c.clientWidth;
52981 Roo.log('GridView.ensureVisible:' +
52983 ' c.clientHeight:' + c.clientHeight +
52984 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
52992 c.scrollTop = ctop;
52993 //Roo.log("set scrolltop to ctop DISABLE?");
52994 }else if(cbot > sbot){
52995 //Roo.log("set scrolltop to cbot-ch");
52996 c.scrollTop = cbot-ch;
52999 if(hscroll !== false){
53001 c.scrollLeft = cleft;
53002 }else if(cright > sright){
53003 c.scrollLeft = cright-c.clientWidth;
53010 updateColumns : function(){
53011 this.grid.stopEditing();
53012 var cm = this.grid.colModel, colIds = this.getColumnIds();
53013 //var totalWidth = cm.getTotalWidth();
53015 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53016 //if(cm.isHidden(i)) continue;
53017 var w = cm.getColumnWidth(i);
53018 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53019 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53021 this.updateSplitters();
53024 generateRules : function(cm){
53025 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53026 Roo.util.CSS.removeStyleSheet(rulesId);
53027 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53028 var cid = cm.getColumnId(i);
53030 if(cm.config[i].align){
53031 align = 'text-align:'+cm.config[i].align+';';
53034 if(cm.isHidden(i)){
53035 hidden = 'display:none;';
53037 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53039 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53040 this.hdSelector, cid, " {\n", align, width, "}\n",
53041 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53042 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53044 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53047 updateSplitters : function(){
53048 var cm = this.cm, s = this.getSplitters();
53049 if(s){ // splitters not created yet
53050 var pos = 0, locked = true;
53051 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53052 if(cm.isHidden(i)) continue;
53053 var w = cm.getColumnWidth(i); // make sure it's a number
53054 if(!cm.isLocked(i) && locked){
53059 s[i].style.left = (pos-this.splitOffset) + "px";
53064 handleHiddenChange : function(colModel, colIndex, hidden){
53066 this.hideColumn(colIndex);
53068 this.unhideColumn(colIndex);
53072 hideColumn : function(colIndex){
53073 var cid = this.getColumnId(colIndex);
53074 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53075 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53077 this.updateHeaders();
53079 this.updateSplitters();
53083 unhideColumn : function(colIndex){
53084 var cid = this.getColumnId(colIndex);
53085 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53086 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53089 this.updateHeaders();
53091 this.updateSplitters();
53095 insertRows : function(dm, firstRow, lastRow, isUpdate){
53096 if(firstRow == 0 && lastRow == dm.getCount()-1){
53100 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53102 var s = this.getScrollState();
53103 var markup = this.renderRows(firstRow, lastRow);
53104 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53105 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53106 this.restoreScroll(s);
53108 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53109 this.syncRowHeights(firstRow, lastRow);
53110 this.stripeRows(firstRow);
53116 bufferRows : function(markup, target, index){
53117 var before = null, trows = target.rows, tbody = target.tBodies[0];
53118 if(index < trows.length){
53119 before = trows[index];
53121 var b = document.createElement("div");
53122 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53123 var rows = b.firstChild.rows;
53124 for(var i = 0, len = rows.length; i < len; i++){
53126 tbody.insertBefore(rows[0], before);
53128 tbody.appendChild(rows[0]);
53135 deleteRows : function(dm, firstRow, lastRow){
53136 if(dm.getRowCount()<1){
53137 this.fireEvent("beforerefresh", this);
53138 this.mainBody.update("");
53139 this.lockedBody.update("");
53140 this.fireEvent("refresh", this);
53142 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53143 var bt = this.getBodyTable();
53144 var tbody = bt.firstChild;
53145 var rows = bt.rows;
53146 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53147 tbody.removeChild(rows[firstRow]);
53149 this.stripeRows(firstRow);
53150 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53154 updateRows : function(dataSource, firstRow, lastRow){
53155 var s = this.getScrollState();
53157 this.restoreScroll(s);
53160 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53164 this.updateHeaderSortState();
53167 getScrollState : function(){
53169 var sb = this.scroller.dom;
53170 return {left: sb.scrollLeft, top: sb.scrollTop};
53173 stripeRows : function(startRow){
53174 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53177 startRow = startRow || 0;
53178 var rows = this.getBodyTable().rows;
53179 var lrows = this.getLockedTable().rows;
53180 var cls = ' x-grid-row-alt ';
53181 for(var i = startRow, len = rows.length; i < len; i++){
53182 var row = rows[i], lrow = lrows[i];
53183 var isAlt = ((i+1) % 2 == 0);
53184 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53185 if(isAlt == hasAlt){
53189 row.className += " x-grid-row-alt";
53191 row.className = row.className.replace("x-grid-row-alt", "");
53194 lrow.className = row.className;
53199 restoreScroll : function(state){
53200 //Roo.log('GridView.restoreScroll');
53201 var sb = this.scroller.dom;
53202 sb.scrollLeft = state.left;
53203 sb.scrollTop = state.top;
53207 syncScroll : function(){
53208 //Roo.log('GridView.syncScroll');
53209 var sb = this.scroller.dom;
53210 var sh = this.mainHd.dom;
53211 var bs = this.mainBody.dom;
53212 var lv = this.lockedBody.dom;
53213 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53214 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53217 handleScroll : function(e){
53219 var sb = this.scroller.dom;
53220 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53224 handleWheel : function(e){
53225 var d = e.getWheelDelta();
53226 this.scroller.dom.scrollTop -= d*22;
53227 // set this here to prevent jumpy scrolling on large tables
53228 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53232 renderRows : function(startRow, endRow){
53233 // pull in all the crap needed to render rows
53234 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53235 var colCount = cm.getColumnCount();
53237 if(ds.getCount() < 1){
53241 // build a map for all the columns
53243 for(var i = 0; i < colCount; i++){
53244 var name = cm.getDataIndex(i);
53246 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53247 renderer : cm.getRenderer(i),
53248 id : cm.getColumnId(i),
53249 locked : cm.isLocked(i)
53253 startRow = startRow || 0;
53254 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53256 // records to render
53257 var rs = ds.getRange(startRow, endRow);
53259 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53262 // As much as I hate to duplicate code, this was branched because FireFox really hates
53263 // [].join("") on strings. The performance difference was substantial enough to
53264 // branch this function
53265 doRender : Roo.isGecko ?
53266 function(cs, rs, ds, startRow, colCount, stripe){
53267 var ts = this.templates, ct = ts.cell, rt = ts.row;
53269 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53271 var hasListener = this.grid.hasListener('rowclass');
53273 for(var j = 0, len = rs.length; j < len; j++){
53274 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53275 for(var i = 0; i < colCount; i++){
53277 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53279 p.css = p.attr = "";
53280 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53281 if(p.value == undefined || p.value === "") p.value = " ";
53282 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53283 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53285 var markup = ct.apply(p);
53293 if(stripe && ((rowIndex+1) % 2 == 0)){
53294 alt.push("x-grid-row-alt")
53297 alt.push( " x-grid-dirty-row");
53300 if(this.getRowClass){
53301 alt.push(this.getRowClass(r, rowIndex));
53307 rowIndex : rowIndex,
53310 this.grid.fireEvent('rowclass', this, rowcfg);
53311 alt.push(rowcfg.rowClass);
53313 rp.alt = alt.join(" ");
53314 lbuf+= rt.apply(rp);
53316 buf+= rt.apply(rp);
53318 return [lbuf, buf];
53320 function(cs, rs, ds, startRow, colCount, stripe){
53321 var ts = this.templates, ct = ts.cell, rt = ts.row;
53323 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53324 var hasListener = this.grid.hasListener('rowclass');
53327 for(var j = 0, len = rs.length; j < len; j++){
53328 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53329 for(var i = 0; i < colCount; i++){
53331 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53333 p.css = p.attr = "";
53334 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53335 if(p.value == undefined || p.value === "") p.value = " ";
53336 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53337 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53340 var markup = ct.apply(p);
53342 cb[cb.length] = markup;
53344 lcb[lcb.length] = markup;
53348 if(stripe && ((rowIndex+1) % 2 == 0)){
53349 alt.push( "x-grid-row-alt");
53352 alt.push(" x-grid-dirty-row");
53355 if(this.getRowClass){
53356 alt.push( this.getRowClass(r, rowIndex));
53362 rowIndex : rowIndex,
53365 this.grid.fireEvent('rowclass', this, rowcfg);
53366 alt.push(rowcfg.rowClass);
53368 rp.alt = alt.join(" ");
53369 rp.cells = lcb.join("");
53370 lbuf[lbuf.length] = rt.apply(rp);
53371 rp.cells = cb.join("");
53372 buf[buf.length] = rt.apply(rp);
53374 return [lbuf.join(""), buf.join("")];
53377 renderBody : function(){
53378 var markup = this.renderRows();
53379 var bt = this.templates.body;
53380 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53384 * Refreshes the grid
53385 * @param {Boolean} headersToo
53387 refresh : function(headersToo){
53388 this.fireEvent("beforerefresh", this);
53389 this.grid.stopEditing();
53390 var result = this.renderBody();
53391 this.lockedBody.update(result[0]);
53392 this.mainBody.update(result[1]);
53393 if(headersToo === true){
53394 this.updateHeaders();
53395 this.updateColumns();
53396 this.updateSplitters();
53397 this.updateHeaderSortState();
53399 this.syncRowHeights();
53401 this.fireEvent("refresh", this);
53404 handleColumnMove : function(cm, oldIndex, newIndex){
53405 this.indexMap = null;
53406 var s = this.getScrollState();
53407 this.refresh(true);
53408 this.restoreScroll(s);
53409 this.afterMove(newIndex);
53412 afterMove : function(colIndex){
53413 if(this.enableMoveAnim && Roo.enableFx){
53414 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53416 // if multisort - fix sortOrder, and reload..
53417 if (this.grid.dataSource.multiSort) {
53418 // the we can call sort again..
53419 var dm = this.grid.dataSource;
53420 var cm = this.grid.colModel;
53422 for(var i = 0; i < cm.config.length; i++ ) {
53424 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53425 continue; // dont' bother, it's not in sort list or being set.
53428 so.push(cm.config[i].dataIndex);
53431 dm.load(dm.lastOptions);
53438 updateCell : function(dm, rowIndex, dataIndex){
53439 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53440 if(typeof colIndex == "undefined"){ // not present in grid
53443 var cm = this.grid.colModel;
53444 var cell = this.getCell(rowIndex, colIndex);
53445 var cellText = this.getCellText(rowIndex, colIndex);
53448 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53449 id : cm.getColumnId(colIndex),
53450 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53452 var renderer = cm.getRenderer(colIndex);
53453 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53454 if(typeof val == "undefined" || val === "") val = " ";
53455 cellText.innerHTML = val;
53456 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53457 this.syncRowHeights(rowIndex, rowIndex);
53460 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53462 if(this.grid.autoSizeHeaders){
53463 var h = this.getHeaderCellMeasure(colIndex);
53464 maxWidth = Math.max(maxWidth, h.scrollWidth);
53467 if(this.cm.isLocked(colIndex)){
53468 tb = this.getLockedTable();
53471 tb = this.getBodyTable();
53472 index = colIndex - this.cm.getLockedCount();
53475 var rows = tb.rows;
53476 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53477 for(var i = 0; i < stopIndex; i++){
53478 var cell = rows[i].childNodes[index].firstChild;
53479 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53482 return maxWidth + /*margin for error in IE*/ 5;
53485 * Autofit a column to its content.
53486 * @param {Number} colIndex
53487 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53489 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53490 if(this.cm.isHidden(colIndex)){
53491 return; // can't calc a hidden column
53494 var cid = this.cm.getColumnId(colIndex);
53495 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53496 if(this.grid.autoSizeHeaders){
53497 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53500 var newWidth = this.calcColumnWidth(colIndex);
53501 this.cm.setColumnWidth(colIndex,
53502 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53503 if(!suppressEvent){
53504 this.grid.fireEvent("columnresize", colIndex, newWidth);
53509 * Autofits all columns to their content and then expands to fit any extra space in the grid
53511 autoSizeColumns : function(){
53512 var cm = this.grid.colModel;
53513 var colCount = cm.getColumnCount();
53514 for(var i = 0; i < colCount; i++){
53515 this.autoSizeColumn(i, true, true);
53517 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53520 this.updateColumns();
53526 * Autofits all columns to the grid's width proportionate with their current size
53527 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53529 fitColumns : function(reserveScrollSpace){
53530 var cm = this.grid.colModel;
53531 var colCount = cm.getColumnCount();
53535 for (i = 0; i < colCount; i++){
53536 if(!cm.isHidden(i) && !cm.isFixed(i)){
53537 w = cm.getColumnWidth(i);
53543 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53544 if(reserveScrollSpace){
53547 var frac = (avail - cm.getTotalWidth())/width;
53548 while (cols.length){
53551 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53553 this.updateColumns();
53557 onRowSelect : function(rowIndex){
53558 var row = this.getRowComposite(rowIndex);
53559 row.addClass("x-grid-row-selected");
53562 onRowDeselect : function(rowIndex){
53563 var row = this.getRowComposite(rowIndex);
53564 row.removeClass("x-grid-row-selected");
53567 onCellSelect : function(row, col){
53568 var cell = this.getCell(row, col);
53570 Roo.fly(cell).addClass("x-grid-cell-selected");
53574 onCellDeselect : function(row, col){
53575 var cell = this.getCell(row, col);
53577 Roo.fly(cell).removeClass("x-grid-cell-selected");
53581 updateHeaderSortState : function(){
53583 // sort state can be single { field: xxx, direction : yyy}
53584 // or { xxx=>ASC , yyy : DESC ..... }
53587 if (!this.ds.multiSort) {
53588 var state = this.ds.getSortState();
53592 mstate[state.field] = state.direction;
53593 // FIXME... - this is not used here.. but might be elsewhere..
53594 this.sortState = state;
53597 mstate = this.ds.sortToggle;
53599 //remove existing sort classes..
53601 var sc = this.sortClasses;
53602 var hds = this.el.select(this.headerSelector).removeClass(sc);
53604 for(var f in mstate) {
53606 var sortColumn = this.cm.findColumnIndex(f);
53608 if(sortColumn != -1){
53609 var sortDir = mstate[f];
53610 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53619 handleHeaderClick : function(g, index,e){
53621 Roo.log("header click");
53624 // touch events on header are handled by context
53625 this.handleHdCtx(g,index,e);
53630 if(this.headersDisabled){
53633 var dm = g.dataSource, cm = g.colModel;
53634 if(!cm.isSortable(index)){
53639 if (dm.multiSort) {
53640 // update the sortOrder
53642 for(var i = 0; i < cm.config.length; i++ ) {
53644 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53645 continue; // dont' bother, it's not in sort list or being set.
53648 so.push(cm.config[i].dataIndex);
53654 dm.sort(cm.getDataIndex(index));
53658 destroy : function(){
53660 this.colMenu.removeAll();
53661 Roo.menu.MenuMgr.unregister(this.colMenu);
53662 this.colMenu.getEl().remove();
53663 delete this.colMenu;
53666 this.hmenu.removeAll();
53667 Roo.menu.MenuMgr.unregister(this.hmenu);
53668 this.hmenu.getEl().remove();
53671 if(this.grid.enableColumnMove){
53672 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53674 for(var dd in dds){
53675 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53676 var elid = dds[dd].dragElId;
53678 Roo.get(elid).remove();
53679 } else if(dds[dd].config.isTarget){
53680 dds[dd].proxyTop.remove();
53681 dds[dd].proxyBottom.remove();
53684 if(Roo.dd.DDM.locationCache[dd]){
53685 delete Roo.dd.DDM.locationCache[dd];
53688 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53691 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53692 this.bind(null, null);
53693 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53696 handleLockChange : function(){
53697 this.refresh(true);
53700 onDenyColumnLock : function(){
53704 onDenyColumnHide : function(){
53708 handleHdMenuClick : function(item){
53709 var index = this.hdCtxIndex;
53710 var cm = this.cm, ds = this.ds;
53713 ds.sort(cm.getDataIndex(index), "ASC");
53716 ds.sort(cm.getDataIndex(index), "DESC");
53719 var lc = cm.getLockedCount();
53720 if(cm.getColumnCount(true) <= lc+1){
53721 this.onDenyColumnLock();
53725 cm.setLocked(index, true, true);
53726 cm.moveColumn(index, lc);
53727 this.grid.fireEvent("columnmove", index, lc);
53729 cm.setLocked(index, true);
53733 var lc = cm.getLockedCount();
53734 if((lc-1) != index){
53735 cm.setLocked(index, false, true);
53736 cm.moveColumn(index, lc-1);
53737 this.grid.fireEvent("columnmove", index, lc-1);
53739 cm.setLocked(index, false);
53742 case 'wider': // used to expand cols on touch..
53744 var cw = cm.getColumnWidth(index);
53745 cw += (item.id == 'wider' ? 1 : -1) * 50;
53746 cw = Math.max(0, cw);
53747 cw = Math.min(cw,4000);
53748 cm.setColumnWidth(index, cw);
53752 index = cm.getIndexById(item.id.substr(4));
53754 if(item.checked && cm.getColumnCount(true) <= 1){
53755 this.onDenyColumnHide();
53758 cm.setHidden(index, item.checked);
53764 beforeColMenuShow : function(){
53765 var cm = this.cm, colCount = cm.getColumnCount();
53766 this.colMenu.removeAll();
53767 for(var i = 0; i < colCount; i++){
53768 this.colMenu.add(new Roo.menu.CheckItem({
53769 id: "col-"+cm.getColumnId(i),
53770 text: cm.getColumnHeader(i),
53771 checked: !cm.isHidden(i),
53777 handleHdCtx : function(g, index, e){
53779 var hd = this.getHeaderCell(index);
53780 this.hdCtxIndex = index;
53781 var ms = this.hmenu.items, cm = this.cm;
53782 ms.get("asc").setDisabled(!cm.isSortable(index));
53783 ms.get("desc").setDisabled(!cm.isSortable(index));
53784 if(this.grid.enableColLock !== false){
53785 ms.get("lock").setDisabled(cm.isLocked(index));
53786 ms.get("unlock").setDisabled(!cm.isLocked(index));
53788 this.hmenu.show(hd, "tl-bl");
53791 handleHdOver : function(e){
53792 var hd = this.findHeaderCell(e.getTarget());
53793 if(hd && !this.headersDisabled){
53794 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
53795 this.fly(hd).addClass("x-grid-hd-over");
53800 handleHdOut : function(e){
53801 var hd = this.findHeaderCell(e.getTarget());
53803 this.fly(hd).removeClass("x-grid-hd-over");
53807 handleSplitDblClick : function(e, t){
53808 var i = this.getCellIndex(t);
53809 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
53810 this.autoSizeColumn(i, true);
53815 render : function(){
53818 var colCount = cm.getColumnCount();
53820 if(this.grid.monitorWindowResize === true){
53821 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53823 var header = this.renderHeaders();
53824 var body = this.templates.body.apply({rows:""});
53825 var html = this.templates.master.apply({
53828 lockedHeader: header[0],
53832 //this.updateColumns();
53834 this.grid.getGridEl().dom.innerHTML = html;
53836 this.initElements();
53838 // a kludge to fix the random scolling effect in webkit
53839 this.el.on("scroll", function() {
53840 this.el.dom.scrollTop=0; // hopefully not recursive..
53843 this.scroller.on("scroll", this.handleScroll, this);
53844 this.lockedBody.on("mousewheel", this.handleWheel, this);
53845 this.mainBody.on("mousewheel", this.handleWheel, this);
53847 this.mainHd.on("mouseover", this.handleHdOver, this);
53848 this.mainHd.on("mouseout", this.handleHdOut, this);
53849 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
53850 {delegate: "."+this.splitClass});
53852 this.lockedHd.on("mouseover", this.handleHdOver, this);
53853 this.lockedHd.on("mouseout", this.handleHdOut, this);
53854 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
53855 {delegate: "."+this.splitClass});
53857 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
53858 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53861 this.updateSplitters();
53863 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
53864 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53865 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
53868 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
53869 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
53871 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
53872 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
53874 if(this.grid.enableColLock !== false){
53875 this.hmenu.add('-',
53876 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
53877 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
53881 this.hmenu.add('-',
53882 {id:"wider", text: this.columnsWiderText},
53883 {id:"narrow", text: this.columnsNarrowText }
53889 if(this.grid.enableColumnHide !== false){
53891 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
53892 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
53893 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
53895 this.hmenu.add('-',
53896 {id:"columns", text: this.columnsText, menu: this.colMenu}
53899 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
53901 this.grid.on("headercontextmenu", this.handleHdCtx, this);
53904 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
53905 this.dd = new Roo.grid.GridDragZone(this.grid, {
53906 ddGroup : this.grid.ddGroup || 'GridDD'
53912 for(var i = 0; i < colCount; i++){
53913 if(cm.isHidden(i)){
53914 this.hideColumn(i);
53916 if(cm.config[i].align){
53917 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
53918 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
53922 this.updateHeaderSortState();
53924 this.beforeInitialResize();
53927 // two part rendering gives faster view to the user
53928 this.renderPhase2.defer(1, this);
53931 renderPhase2 : function(){
53932 // render the rows now
53934 if(this.grid.autoSizeColumns){
53935 this.autoSizeColumns();
53939 beforeInitialResize : function(){
53943 onColumnSplitterMoved : function(i, w){
53944 this.userResized = true;
53945 var cm = this.grid.colModel;
53946 cm.setColumnWidth(i, w, true);
53947 var cid = cm.getColumnId(i);
53948 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53949 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
53950 this.updateSplitters();
53952 this.grid.fireEvent("columnresize", i, w);
53955 syncRowHeights : function(startIndex, endIndex){
53956 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
53957 startIndex = startIndex || 0;
53958 var mrows = this.getBodyTable().rows;
53959 var lrows = this.getLockedTable().rows;
53960 var len = mrows.length-1;
53961 endIndex = Math.min(endIndex || len, len);
53962 for(var i = startIndex; i <= endIndex; i++){
53963 var m = mrows[i], l = lrows[i];
53964 var h = Math.max(m.offsetHeight, l.offsetHeight);
53965 m.style.height = l.style.height = h + "px";
53970 layout : function(initialRender, is2ndPass){
53972 var auto = g.autoHeight;
53973 var scrollOffset = 16;
53974 var c = g.getGridEl(), cm = this.cm,
53975 expandCol = g.autoExpandColumn,
53977 //c.beginMeasure();
53979 if(!c.dom.offsetWidth){ // display:none?
53981 this.lockedWrap.show();
53982 this.mainWrap.show();
53987 var hasLock = this.cm.isLocked(0);
53989 var tbh = this.headerPanel.getHeight();
53990 var bbh = this.footerPanel.getHeight();
53993 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
53994 var newHeight = ch + c.getBorderWidth("tb");
53996 newHeight = Math.min(g.maxHeight, newHeight);
53998 c.setHeight(newHeight);
54002 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54005 var s = this.scroller;
54007 var csize = c.getSize(true);
54009 this.el.setSize(csize.width, csize.height);
54011 this.headerPanel.setWidth(csize.width);
54012 this.footerPanel.setWidth(csize.width);
54014 var hdHeight = this.mainHd.getHeight();
54015 var vw = csize.width;
54016 var vh = csize.height - (tbh + bbh);
54020 var bt = this.getBodyTable();
54021 var ltWidth = hasLock ?
54022 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54024 var scrollHeight = bt.offsetHeight;
54025 var scrollWidth = ltWidth + bt.offsetWidth;
54026 var vscroll = false, hscroll = false;
54028 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54030 var lw = this.lockedWrap, mw = this.mainWrap;
54031 var lb = this.lockedBody, mb = this.mainBody;
54033 setTimeout(function(){
54034 var t = s.dom.offsetTop;
54035 var w = s.dom.clientWidth,
54036 h = s.dom.clientHeight;
54039 lw.setSize(ltWidth, h);
54041 mw.setLeftTop(ltWidth, t);
54042 mw.setSize(w-ltWidth, h);
54044 lb.setHeight(h-hdHeight);
54045 mb.setHeight(h-hdHeight);
54047 if(is2ndPass !== true && !gv.userResized && expandCol){
54048 // high speed resize without full column calculation
54050 var ci = cm.getIndexById(expandCol);
54052 ci = cm.findColumnIndex(expandCol);
54054 ci = Math.max(0, ci); // make sure it's got at least the first col.
54055 var expandId = cm.getColumnId(ci);
54056 var tw = cm.getTotalWidth(false);
54057 var currentWidth = cm.getColumnWidth(ci);
54058 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54059 if(currentWidth != cw){
54060 cm.setColumnWidth(ci, cw, true);
54061 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54062 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54063 gv.updateSplitters();
54064 gv.layout(false, true);
54076 onWindowResize : function(){
54077 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54083 appendFooter : function(parentEl){
54087 sortAscText : "Sort Ascending",
54088 sortDescText : "Sort Descending",
54089 lockText : "Lock Column",
54090 unlockText : "Unlock Column",
54091 columnsText : "Columns",
54093 columnsWiderText : "Wider",
54094 columnsNarrowText : "Thinner"
54098 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54099 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54100 this.proxy.el.addClass('x-grid3-col-dd');
54103 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54104 handleMouseDown : function(e){
54108 callHandleMouseDown : function(e){
54109 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54114 * Ext JS Library 1.1.1
54115 * Copyright(c) 2006-2007, Ext JS, LLC.
54117 * Originally Released Under LGPL - original licence link has changed is not relivant.
54120 * <script type="text/javascript">
54124 // This is a support class used internally by the Grid components
54125 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54127 this.view = grid.getView();
54128 this.proxy = this.view.resizeProxy;
54129 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54130 "gridSplitters" + this.grid.getGridEl().id, {
54131 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54133 this.setHandleElId(Roo.id(hd));
54134 this.setOuterHandleElId(Roo.id(hd2));
54135 this.scroll = false;
54137 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54138 fly: Roo.Element.fly,
54140 b4StartDrag : function(x, y){
54141 this.view.headersDisabled = true;
54142 this.proxy.setHeight(this.view.mainWrap.getHeight());
54143 var w = this.cm.getColumnWidth(this.cellIndex);
54144 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54145 this.resetConstraints();
54146 this.setXConstraint(minw, 1000);
54147 this.setYConstraint(0, 0);
54148 this.minX = x - minw;
54149 this.maxX = x + 1000;
54151 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54155 handleMouseDown : function(e){
54156 ev = Roo.EventObject.setEvent(e);
54157 var t = this.fly(ev.getTarget());
54158 if(t.hasClass("x-grid-split")){
54159 this.cellIndex = this.view.getCellIndex(t.dom);
54160 this.split = t.dom;
54161 this.cm = this.grid.colModel;
54162 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54163 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54168 endDrag : function(e){
54169 this.view.headersDisabled = false;
54170 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54171 var diff = endX - this.startPos;
54172 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54175 autoOffset : function(){
54176 this.setDelta(0,0);
54180 * Ext JS Library 1.1.1
54181 * Copyright(c) 2006-2007, Ext JS, LLC.
54183 * Originally Released Under LGPL - original licence link has changed is not relivant.
54186 * <script type="text/javascript">
54190 // This is a support class used internally by the Grid components
54191 Roo.grid.GridDragZone = function(grid, config){
54192 this.view = grid.getView();
54193 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54194 if(this.view.lockedBody){
54195 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54196 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54198 this.scroll = false;
54200 this.ddel = document.createElement('div');
54201 this.ddel.className = 'x-grid-dd-wrap';
54204 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54205 ddGroup : "GridDD",
54207 getDragData : function(e){
54208 var t = Roo.lib.Event.getTarget(e);
54209 var rowIndex = this.view.findRowIndex(t);
54210 var sm = this.grid.selModel;
54212 //Roo.log(rowIndex);
54214 if (sm.getSelectedCell) {
54215 // cell selection..
54216 if (!sm.getSelectedCell()) {
54219 if (rowIndex != sm.getSelectedCell()[0]) {
54225 if(rowIndex !== false){
54230 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54232 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54235 if (e.hasModifier()){
54236 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54239 Roo.log("getDragData");
54244 rowIndex: rowIndex,
54245 selections:sm.getSelections ? sm.getSelections() : (
54246 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54253 onInitDrag : function(e){
54254 var data = this.dragData;
54255 this.ddel.innerHTML = this.grid.getDragDropText();
54256 this.proxy.update(this.ddel);
54257 // fire start drag?
54260 afterRepair : function(){
54261 this.dragging = false;
54264 getRepairXY : function(e, data){
54268 onEndDrag : function(data, e){
54272 onValidDrop : function(dd, e, id){
54277 beforeInvalidDrop : function(e, id){
54282 * Ext JS Library 1.1.1
54283 * Copyright(c) 2006-2007, Ext JS, LLC.
54285 * Originally Released Under LGPL - original licence link has changed is not relivant.
54288 * <script type="text/javascript">
54293 * @class Roo.grid.ColumnModel
54294 * @extends Roo.util.Observable
54295 * This is the default implementation of a ColumnModel used by the Grid. It defines
54296 * the columns in the grid.
54299 var colModel = new Roo.grid.ColumnModel([
54300 {header: "Ticker", width: 60, sortable: true, locked: true},
54301 {header: "Company Name", width: 150, sortable: true},
54302 {header: "Market Cap.", width: 100, sortable: true},
54303 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54304 {header: "Employees", width: 100, sortable: true, resizable: false}
54309 * The config options listed for this class are options which may appear in each
54310 * individual column definition.
54311 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54313 * @param {Object} config An Array of column config objects. See this class's
54314 * config objects for details.
54316 Roo.grid.ColumnModel = function(config){
54318 * The config passed into the constructor
54320 this.config = config;
54323 // if no id, create one
54324 // if the column does not have a dataIndex mapping,
54325 // map it to the order it is in the config
54326 for(var i = 0, len = config.length; i < len; i++){
54328 if(typeof c.dataIndex == "undefined"){
54331 if(typeof c.renderer == "string"){
54332 c.renderer = Roo.util.Format[c.renderer];
54334 if(typeof c.id == "undefined"){
54337 if(c.editor && c.editor.xtype){
54338 c.editor = Roo.factory(c.editor, Roo.grid);
54340 if(c.editor && c.editor.isFormField){
54341 c.editor = new Roo.grid.GridEditor(c.editor);
54343 this.lookup[c.id] = c;
54347 * The width of columns which have no width specified (defaults to 100)
54350 this.defaultWidth = 100;
54353 * Default sortable of columns which have no sortable specified (defaults to false)
54356 this.defaultSortable = false;
54360 * @event widthchange
54361 * Fires when the width of a column changes.
54362 * @param {ColumnModel} this
54363 * @param {Number} columnIndex The column index
54364 * @param {Number} newWidth The new width
54366 "widthchange": true,
54368 * @event headerchange
54369 * Fires when the text of a header changes.
54370 * @param {ColumnModel} this
54371 * @param {Number} columnIndex The column index
54372 * @param {Number} newText The new header text
54374 "headerchange": true,
54376 * @event hiddenchange
54377 * Fires when a column is hidden or "unhidden".
54378 * @param {ColumnModel} this
54379 * @param {Number} columnIndex The column index
54380 * @param {Boolean} hidden true if hidden, false otherwise
54382 "hiddenchange": true,
54384 * @event columnmoved
54385 * Fires when a column is moved.
54386 * @param {ColumnModel} this
54387 * @param {Number} oldIndex
54388 * @param {Number} newIndex
54390 "columnmoved" : true,
54392 * @event columlockchange
54393 * Fires when a column's locked state is changed
54394 * @param {ColumnModel} this
54395 * @param {Number} colIndex
54396 * @param {Boolean} locked true if locked
54398 "columnlockchange" : true
54400 Roo.grid.ColumnModel.superclass.constructor.call(this);
54402 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54404 * @cfg {String} header The header text to display in the Grid view.
54407 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54408 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54409 * specified, the column's index is used as an index into the Record's data Array.
54412 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54413 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54416 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54417 * Defaults to the value of the {@link #defaultSortable} property.
54418 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54421 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54424 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54427 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54430 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54433 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54434 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54435 * default renderer uses the raw data value.
54438 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54441 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54445 * Returns the id of the column at the specified index.
54446 * @param {Number} index The column index
54447 * @return {String} the id
54449 getColumnId : function(index){
54450 return this.config[index].id;
54454 * Returns the column for a specified id.
54455 * @param {String} id The column id
54456 * @return {Object} the column
54458 getColumnById : function(id){
54459 return this.lookup[id];
54464 * Returns the column for a specified dataIndex.
54465 * @param {String} dataIndex The column dataIndex
54466 * @return {Object|Boolean} the column or false if not found
54468 getColumnByDataIndex: function(dataIndex){
54469 var index = this.findColumnIndex(dataIndex);
54470 return index > -1 ? this.config[index] : false;
54474 * Returns the index for a specified column id.
54475 * @param {String} id The column id
54476 * @return {Number} the index, or -1 if not found
54478 getIndexById : function(id){
54479 for(var i = 0, len = this.config.length; i < len; i++){
54480 if(this.config[i].id == id){
54488 * Returns the index for a specified column dataIndex.
54489 * @param {String} dataIndex The column dataIndex
54490 * @return {Number} the index, or -1 if not found
54493 findColumnIndex : function(dataIndex){
54494 for(var i = 0, len = this.config.length; i < len; i++){
54495 if(this.config[i].dataIndex == dataIndex){
54503 moveColumn : function(oldIndex, newIndex){
54504 var c = this.config[oldIndex];
54505 this.config.splice(oldIndex, 1);
54506 this.config.splice(newIndex, 0, c);
54507 this.dataMap = null;
54508 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54511 isLocked : function(colIndex){
54512 return this.config[colIndex].locked === true;
54515 setLocked : function(colIndex, value, suppressEvent){
54516 if(this.isLocked(colIndex) == value){
54519 this.config[colIndex].locked = value;
54520 if(!suppressEvent){
54521 this.fireEvent("columnlockchange", this, colIndex, value);
54525 getTotalLockedWidth : function(){
54526 var totalWidth = 0;
54527 for(var i = 0; i < this.config.length; i++){
54528 if(this.isLocked(i) && !this.isHidden(i)){
54529 this.totalWidth += this.getColumnWidth(i);
54535 getLockedCount : function(){
54536 for(var i = 0, len = this.config.length; i < len; i++){
54537 if(!this.isLocked(i)){
54544 * Returns the number of columns.
54547 getColumnCount : function(visibleOnly){
54548 if(visibleOnly === true){
54550 for(var i = 0, len = this.config.length; i < len; i++){
54551 if(!this.isHidden(i)){
54557 return this.config.length;
54561 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54562 * @param {Function} fn
54563 * @param {Object} scope (optional)
54564 * @return {Array} result
54566 getColumnsBy : function(fn, scope){
54568 for(var i = 0, len = this.config.length; i < len; i++){
54569 var c = this.config[i];
54570 if(fn.call(scope||this, c, i) === true){
54578 * Returns true if the specified column is sortable.
54579 * @param {Number} col The column index
54580 * @return {Boolean}
54582 isSortable : function(col){
54583 if(typeof this.config[col].sortable == "undefined"){
54584 return this.defaultSortable;
54586 return this.config[col].sortable;
54590 * Returns the rendering (formatting) function defined for the column.
54591 * @param {Number} col The column index.
54592 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54594 getRenderer : function(col){
54595 if(!this.config[col].renderer){
54596 return Roo.grid.ColumnModel.defaultRenderer;
54598 return this.config[col].renderer;
54602 * Sets the rendering (formatting) function for a column.
54603 * @param {Number} col The column index
54604 * @param {Function} fn The function to use to process the cell's raw data
54605 * to return HTML markup for the grid view. The render function is called with
54606 * the following parameters:<ul>
54607 * <li>Data value.</li>
54608 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54609 * <li>css A CSS style string to apply to the table cell.</li>
54610 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54611 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54612 * <li>Row index</li>
54613 * <li>Column index</li>
54614 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54616 setRenderer : function(col, fn){
54617 this.config[col].renderer = fn;
54621 * Returns the width for the specified column.
54622 * @param {Number} col The column index
54625 getColumnWidth : function(col){
54626 return this.config[col].width * 1 || this.defaultWidth;
54630 * Sets the width for a column.
54631 * @param {Number} col The column index
54632 * @param {Number} width The new width
54634 setColumnWidth : function(col, width, suppressEvent){
54635 this.config[col].width = width;
54636 this.totalWidth = null;
54637 if(!suppressEvent){
54638 this.fireEvent("widthchange", this, col, width);
54643 * Returns the total width of all columns.
54644 * @param {Boolean} includeHidden True to include hidden column widths
54647 getTotalWidth : function(includeHidden){
54648 if(!this.totalWidth){
54649 this.totalWidth = 0;
54650 for(var i = 0, len = this.config.length; i < len; i++){
54651 if(includeHidden || !this.isHidden(i)){
54652 this.totalWidth += this.getColumnWidth(i);
54656 return this.totalWidth;
54660 * Returns the header for the specified column.
54661 * @param {Number} col The column index
54664 getColumnHeader : function(col){
54665 return this.config[col].header;
54669 * Sets the header for a column.
54670 * @param {Number} col The column index
54671 * @param {String} header The new header
54673 setColumnHeader : function(col, header){
54674 this.config[col].header = header;
54675 this.fireEvent("headerchange", this, col, header);
54679 * Returns the tooltip for the specified column.
54680 * @param {Number} col The column index
54683 getColumnTooltip : function(col){
54684 return this.config[col].tooltip;
54687 * Sets the tooltip for a column.
54688 * @param {Number} col The column index
54689 * @param {String} tooltip The new tooltip
54691 setColumnTooltip : function(col, tooltip){
54692 this.config[col].tooltip = tooltip;
54696 * Returns the dataIndex for the specified column.
54697 * @param {Number} col The column index
54700 getDataIndex : function(col){
54701 return this.config[col].dataIndex;
54705 * Sets the dataIndex for a column.
54706 * @param {Number} col The column index
54707 * @param {Number} dataIndex The new dataIndex
54709 setDataIndex : function(col, dataIndex){
54710 this.config[col].dataIndex = dataIndex;
54716 * Returns true if the cell is editable.
54717 * @param {Number} colIndex The column index
54718 * @param {Number} rowIndex The row index
54719 * @return {Boolean}
54721 isCellEditable : function(colIndex, rowIndex){
54722 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
54726 * Returns the editor defined for the cell/column.
54727 * return false or null to disable editing.
54728 * @param {Number} colIndex The column index
54729 * @param {Number} rowIndex The row index
54732 getCellEditor : function(colIndex, rowIndex){
54733 return this.config[colIndex].editor;
54737 * Sets if a column is editable.
54738 * @param {Number} col The column index
54739 * @param {Boolean} editable True if the column is editable
54741 setEditable : function(col, editable){
54742 this.config[col].editable = editable;
54747 * Returns true if the column is hidden.
54748 * @param {Number} colIndex The column index
54749 * @return {Boolean}
54751 isHidden : function(colIndex){
54752 return this.config[colIndex].hidden;
54757 * Returns true if the column width cannot be changed
54759 isFixed : function(colIndex){
54760 return this.config[colIndex].fixed;
54764 * Returns true if the column can be resized
54765 * @return {Boolean}
54767 isResizable : function(colIndex){
54768 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
54771 * Sets if a column is hidden.
54772 * @param {Number} colIndex The column index
54773 * @param {Boolean} hidden True if the column is hidden
54775 setHidden : function(colIndex, hidden){
54776 this.config[colIndex].hidden = hidden;
54777 this.totalWidth = null;
54778 this.fireEvent("hiddenchange", this, colIndex, hidden);
54782 * Sets the editor for a column.
54783 * @param {Number} col The column index
54784 * @param {Object} editor The editor object
54786 setEditor : function(col, editor){
54787 this.config[col].editor = editor;
54791 Roo.grid.ColumnModel.defaultRenderer = function(value){
54792 if(typeof value == "string" && value.length < 1){
54798 // Alias for backwards compatibility
54799 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
54802 * Ext JS Library 1.1.1
54803 * Copyright(c) 2006-2007, Ext JS, LLC.
54805 * Originally Released Under LGPL - original licence link has changed is not relivant.
54808 * <script type="text/javascript">
54812 * @class Roo.grid.AbstractSelectionModel
54813 * @extends Roo.util.Observable
54814 * Abstract base class for grid SelectionModels. It provides the interface that should be
54815 * implemented by descendant classes. This class should not be directly instantiated.
54818 Roo.grid.AbstractSelectionModel = function(){
54819 this.locked = false;
54820 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
54823 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
54824 /** @ignore Called by the grid automatically. Do not call directly. */
54825 init : function(grid){
54831 * Locks the selections.
54834 this.locked = true;
54838 * Unlocks the selections.
54840 unlock : function(){
54841 this.locked = false;
54845 * Returns true if the selections are locked.
54846 * @return {Boolean}
54848 isLocked : function(){
54849 return this.locked;
54853 * Ext JS Library 1.1.1
54854 * Copyright(c) 2006-2007, Ext JS, LLC.
54856 * Originally Released Under LGPL - original licence link has changed is not relivant.
54859 * <script type="text/javascript">
54862 * @extends Roo.grid.AbstractSelectionModel
54863 * @class Roo.grid.RowSelectionModel
54864 * The default SelectionModel used by {@link Roo.grid.Grid}.
54865 * It supports multiple selections and keyboard selection/navigation.
54867 * @param {Object} config
54869 Roo.grid.RowSelectionModel = function(config){
54870 Roo.apply(this, config);
54871 this.selections = new Roo.util.MixedCollection(false, function(o){
54876 this.lastActive = false;
54880 * @event selectionchange
54881 * Fires when the selection changes
54882 * @param {SelectionModel} this
54884 "selectionchange" : true,
54886 * @event afterselectionchange
54887 * Fires after the selection changes (eg. by key press or clicking)
54888 * @param {SelectionModel} this
54890 "afterselectionchange" : true,
54892 * @event beforerowselect
54893 * Fires when a row is selected being selected, return false to cancel.
54894 * @param {SelectionModel} this
54895 * @param {Number} rowIndex The selected index
54896 * @param {Boolean} keepExisting False if other selections will be cleared
54898 "beforerowselect" : true,
54901 * Fires when a row is selected.
54902 * @param {SelectionModel} this
54903 * @param {Number} rowIndex The selected index
54904 * @param {Roo.data.Record} r The record
54906 "rowselect" : true,
54908 * @event rowdeselect
54909 * Fires when a row is deselected.
54910 * @param {SelectionModel} this
54911 * @param {Number} rowIndex The selected index
54913 "rowdeselect" : true
54915 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
54916 this.locked = false;
54919 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
54921 * @cfg {Boolean} singleSelect
54922 * True to allow selection of only one row at a time (defaults to false)
54924 singleSelect : false,
54927 initEvents : function(){
54929 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
54930 this.grid.on("mousedown", this.handleMouseDown, this);
54931 }else{ // allow click to work like normal
54932 this.grid.on("rowclick", this.handleDragableRowClick, this);
54935 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
54936 "up" : function(e){
54938 this.selectPrevious(e.shiftKey);
54939 }else if(this.last !== false && this.lastActive !== false){
54940 var last = this.last;
54941 this.selectRange(this.last, this.lastActive-1);
54942 this.grid.getView().focusRow(this.lastActive);
54943 if(last !== false){
54947 this.selectFirstRow();
54949 this.fireEvent("afterselectionchange", this);
54951 "down" : function(e){
54953 this.selectNext(e.shiftKey);
54954 }else if(this.last !== false && this.lastActive !== false){
54955 var last = this.last;
54956 this.selectRange(this.last, this.lastActive+1);
54957 this.grid.getView().focusRow(this.lastActive);
54958 if(last !== false){
54962 this.selectFirstRow();
54964 this.fireEvent("afterselectionchange", this);
54969 var view = this.grid.view;
54970 view.on("refresh", this.onRefresh, this);
54971 view.on("rowupdated", this.onRowUpdated, this);
54972 view.on("rowremoved", this.onRemove, this);
54976 onRefresh : function(){
54977 var ds = this.grid.dataSource, i, v = this.grid.view;
54978 var s = this.selections;
54979 s.each(function(r){
54980 if((i = ds.indexOfId(r.id)) != -1){
54989 onRemove : function(v, index, r){
54990 this.selections.remove(r);
54994 onRowUpdated : function(v, index, r){
54995 if(this.isSelected(r)){
54996 v.onRowSelect(index);
55002 * @param {Array} records The records to select
55003 * @param {Boolean} keepExisting (optional) True to keep existing selections
55005 selectRecords : function(records, keepExisting){
55007 this.clearSelections();
55009 var ds = this.grid.dataSource;
55010 for(var i = 0, len = records.length; i < len; i++){
55011 this.selectRow(ds.indexOf(records[i]), true);
55016 * Gets the number of selected rows.
55019 getCount : function(){
55020 return this.selections.length;
55024 * Selects the first row in the grid.
55026 selectFirstRow : function(){
55031 * Select the last row.
55032 * @param {Boolean} keepExisting (optional) True to keep existing selections
55034 selectLastRow : function(keepExisting){
55035 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55039 * Selects the row immediately following the last selected row.
55040 * @param {Boolean} keepExisting (optional) True to keep existing selections
55042 selectNext : function(keepExisting){
55043 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55044 this.selectRow(this.last+1, keepExisting);
55045 this.grid.getView().focusRow(this.last);
55050 * Selects the row that precedes the last selected row.
55051 * @param {Boolean} keepExisting (optional) True to keep existing selections
55053 selectPrevious : function(keepExisting){
55055 this.selectRow(this.last-1, keepExisting);
55056 this.grid.getView().focusRow(this.last);
55061 * Returns the selected records
55062 * @return {Array} Array of selected records
55064 getSelections : function(){
55065 return [].concat(this.selections.items);
55069 * Returns the first selected record.
55072 getSelected : function(){
55073 return this.selections.itemAt(0);
55078 * Clears all selections.
55080 clearSelections : function(fast){
55081 if(this.locked) return;
55083 var ds = this.grid.dataSource;
55084 var s = this.selections;
55085 s.each(function(r){
55086 this.deselectRow(ds.indexOfId(r.id));
55090 this.selections.clear();
55097 * Selects all rows.
55099 selectAll : function(){
55100 if(this.locked) return;
55101 this.selections.clear();
55102 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55103 this.selectRow(i, true);
55108 * Returns True if there is a selection.
55109 * @return {Boolean}
55111 hasSelection : function(){
55112 return this.selections.length > 0;
55116 * Returns True if the specified row is selected.
55117 * @param {Number/Record} record The record or index of the record to check
55118 * @return {Boolean}
55120 isSelected : function(index){
55121 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55122 return (r && this.selections.key(r.id) ? true : false);
55126 * Returns True if the specified record id is selected.
55127 * @param {String} id The id of record to check
55128 * @return {Boolean}
55130 isIdSelected : function(id){
55131 return (this.selections.key(id) ? true : false);
55135 handleMouseDown : function(e, t){
55136 var view = this.grid.getView(), rowIndex;
55137 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55140 if(e.shiftKey && this.last !== false){
55141 var last = this.last;
55142 this.selectRange(last, rowIndex, e.ctrlKey);
55143 this.last = last; // reset the last
55144 view.focusRow(rowIndex);
55146 var isSelected = this.isSelected(rowIndex);
55147 if(e.button !== 0 && isSelected){
55148 view.focusRow(rowIndex);
55149 }else if(e.ctrlKey && isSelected){
55150 this.deselectRow(rowIndex);
55151 }else if(!isSelected){
55152 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55153 view.focusRow(rowIndex);
55156 this.fireEvent("afterselectionchange", this);
55159 handleDragableRowClick : function(grid, rowIndex, e)
55161 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55162 this.selectRow(rowIndex, false);
55163 grid.view.focusRow(rowIndex);
55164 this.fireEvent("afterselectionchange", this);
55169 * Selects multiple rows.
55170 * @param {Array} rows Array of the indexes of the row to select
55171 * @param {Boolean} keepExisting (optional) True to keep existing selections
55173 selectRows : function(rows, keepExisting){
55175 this.clearSelections();
55177 for(var i = 0, len = rows.length; i < len; i++){
55178 this.selectRow(rows[i], true);
55183 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55184 * @param {Number} startRow The index of the first row in the range
55185 * @param {Number} endRow The index of the last row in the range
55186 * @param {Boolean} keepExisting (optional) True to retain existing selections
55188 selectRange : function(startRow, endRow, keepExisting){
55189 if(this.locked) return;
55191 this.clearSelections();
55193 if(startRow <= endRow){
55194 for(var i = startRow; i <= endRow; i++){
55195 this.selectRow(i, true);
55198 for(var i = startRow; i >= endRow; i--){
55199 this.selectRow(i, true);
55205 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55206 * @param {Number} startRow The index of the first row in the range
55207 * @param {Number} endRow The index of the last row in the range
55209 deselectRange : function(startRow, endRow, preventViewNotify){
55210 if(this.locked) return;
55211 for(var i = startRow; i <= endRow; i++){
55212 this.deselectRow(i, preventViewNotify);
55218 * @param {Number} row The index of the row to select
55219 * @param {Boolean} keepExisting (optional) True to keep existing selections
55221 selectRow : function(index, keepExisting, preventViewNotify){
55222 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55223 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55224 if(!keepExisting || this.singleSelect){
55225 this.clearSelections();
55227 var r = this.grid.dataSource.getAt(index);
55228 this.selections.add(r);
55229 this.last = this.lastActive = index;
55230 if(!preventViewNotify){
55231 this.grid.getView().onRowSelect(index);
55233 this.fireEvent("rowselect", this, index, r);
55234 this.fireEvent("selectionchange", this);
55240 * @param {Number} row The index of the row to deselect
55242 deselectRow : function(index, preventViewNotify){
55243 if(this.locked) return;
55244 if(this.last == index){
55247 if(this.lastActive == index){
55248 this.lastActive = false;
55250 var r = this.grid.dataSource.getAt(index);
55251 this.selections.remove(r);
55252 if(!preventViewNotify){
55253 this.grid.getView().onRowDeselect(index);
55255 this.fireEvent("rowdeselect", this, index);
55256 this.fireEvent("selectionchange", this);
55260 restoreLast : function(){
55262 this.last = this._last;
55267 acceptsNav : function(row, col, cm){
55268 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55272 onEditorKey : function(field, e){
55273 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55278 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55280 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55282 }else if(k == e.ENTER && !e.ctrlKey){
55286 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55288 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55290 }else if(k == e.ESC){
55294 g.startEditing(newCell[0], newCell[1]);
55299 * Ext JS Library 1.1.1
55300 * Copyright(c) 2006-2007, Ext JS, LLC.
55302 * Originally Released Under LGPL - original licence link has changed is not relivant.
55305 * <script type="text/javascript">
55308 * @class Roo.grid.CellSelectionModel
55309 * @extends Roo.grid.AbstractSelectionModel
55310 * This class provides the basic implementation for cell selection in a grid.
55312 * @param {Object} config The object containing the configuration of this model.
55313 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55315 Roo.grid.CellSelectionModel = function(config){
55316 Roo.apply(this, config);
55318 this.selection = null;
55322 * @event beforerowselect
55323 * Fires before a cell is selected.
55324 * @param {SelectionModel} this
55325 * @param {Number} rowIndex The selected row index
55326 * @param {Number} colIndex The selected cell index
55328 "beforecellselect" : true,
55330 * @event cellselect
55331 * Fires when a cell is selected.
55332 * @param {SelectionModel} this
55333 * @param {Number} rowIndex The selected row index
55334 * @param {Number} colIndex The selected cell index
55336 "cellselect" : true,
55338 * @event selectionchange
55339 * Fires when the active selection changes.
55340 * @param {SelectionModel} this
55341 * @param {Object} selection null for no selection or an object (o) with two properties
55343 <li>o.record: the record object for the row the selection is in</li>
55344 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55347 "selectionchange" : true,
55350 * Fires when the tab (or enter) was pressed on the last editable cell
55351 * You can use this to trigger add new row.
55352 * @param {SelectionModel} this
55356 * @event beforeeditnext
55357 * Fires before the next editable sell is made active
55358 * You can use this to skip to another cell or fire the tabend
55359 * if you set cell to false
55360 * @param {Object} eventdata object : { cell : [ row, col ] }
55362 "beforeeditnext" : true
55364 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55367 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55369 enter_is_tab: false,
55372 initEvents : function(){
55373 this.grid.on("mousedown", this.handleMouseDown, this);
55374 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55375 var view = this.grid.view;
55376 view.on("refresh", this.onViewChange, this);
55377 view.on("rowupdated", this.onRowUpdated, this);
55378 view.on("beforerowremoved", this.clearSelections, this);
55379 view.on("beforerowsinserted", this.clearSelections, this);
55380 if(this.grid.isEditor){
55381 this.grid.on("beforeedit", this.beforeEdit, this);
55386 beforeEdit : function(e){
55387 this.select(e.row, e.column, false, true, e.record);
55391 onRowUpdated : function(v, index, r){
55392 if(this.selection && this.selection.record == r){
55393 v.onCellSelect(index, this.selection.cell[1]);
55398 onViewChange : function(){
55399 this.clearSelections(true);
55403 * Returns the currently selected cell,.
55404 * @return {Array} The selected cell (row, column) or null if none selected.
55406 getSelectedCell : function(){
55407 return this.selection ? this.selection.cell : null;
55411 * Clears all selections.
55412 * @param {Boolean} true to prevent the gridview from being notified about the change.
55414 clearSelections : function(preventNotify){
55415 var s = this.selection;
55417 if(preventNotify !== true){
55418 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55420 this.selection = null;
55421 this.fireEvent("selectionchange", this, null);
55426 * Returns true if there is a selection.
55427 * @return {Boolean}
55429 hasSelection : function(){
55430 return this.selection ? true : false;
55434 handleMouseDown : function(e, t){
55435 var v = this.grid.getView();
55436 if(this.isLocked()){
55439 var row = v.findRowIndex(t);
55440 var cell = v.findCellIndex(t);
55441 if(row !== false && cell !== false){
55442 this.select(row, cell);
55448 * @param {Number} rowIndex
55449 * @param {Number} collIndex
55451 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55452 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55453 this.clearSelections();
55454 r = r || this.grid.dataSource.getAt(rowIndex);
55457 cell : [rowIndex, colIndex]
55459 if(!preventViewNotify){
55460 var v = this.grid.getView();
55461 v.onCellSelect(rowIndex, colIndex);
55462 if(preventFocus !== true){
55463 v.focusCell(rowIndex, colIndex);
55466 this.fireEvent("cellselect", this, rowIndex, colIndex);
55467 this.fireEvent("selectionchange", this, this.selection);
55472 isSelectable : function(rowIndex, colIndex, cm){
55473 return !cm.isHidden(colIndex);
55477 handleKeyDown : function(e){
55478 //Roo.log('Cell Sel Model handleKeyDown');
55479 if(!e.isNavKeyPress()){
55482 var g = this.grid, s = this.selection;
55485 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55487 this.select(cell[0], cell[1]);
55492 var walk = function(row, col, step){
55493 return g.walkCells(row, col, step, sm.isSelectable, sm);
55495 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55502 // handled by onEditorKey
55503 if (g.isEditor && g.editing) {
55507 newCell = walk(r, c-1, -1);
55509 newCell = walk(r, c+1, 1);
55514 newCell = walk(r+1, c, 1);
55518 newCell = walk(r-1, c, -1);
55522 newCell = walk(r, c+1, 1);
55526 newCell = walk(r, c-1, -1);
55531 if(g.isEditor && !g.editing){
55532 g.startEditing(r, c);
55541 this.select(newCell[0], newCell[1]);
55547 acceptsNav : function(row, col, cm){
55548 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55552 * @param {Number} field (not used) - as it's normally used as a listener
55553 * @param {Number} e - event - fake it by using
55555 * var e = Roo.EventObjectImpl.prototype;
55556 * e.keyCode = e.TAB
55560 onEditorKey : function(field, e){
55562 var k = e.getKey(),
55565 ed = g.activeEditor,
55567 ///Roo.log('onEditorKey' + k);
55570 if (this.enter_is_tab && k == e.ENTER) {
55576 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55578 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55584 } else if(k == e.ENTER && !e.ctrlKey){
55587 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55589 } else if(k == e.ESC){
55594 var ecall = { cell : newCell, forward : forward };
55595 this.fireEvent('beforeeditnext', ecall );
55596 newCell = ecall.cell;
55597 forward = ecall.forward;
55601 //Roo.log('next cell after edit');
55602 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55603 } else if (forward) {
55604 // tabbed past last
55605 this.fireEvent.defer(100, this, ['tabend',this]);
55610 * Ext JS Library 1.1.1
55611 * Copyright(c) 2006-2007, Ext JS, LLC.
55613 * Originally Released Under LGPL - original licence link has changed is not relivant.
55616 * <script type="text/javascript">
55620 * @class Roo.grid.EditorGrid
55621 * @extends Roo.grid.Grid
55622 * Class for creating and editable grid.
55623 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55624 * The container MUST have some type of size defined for the grid to fill. The container will be
55625 * automatically set to position relative if it isn't already.
55626 * @param {Object} dataSource The data model to bind to
55627 * @param {Object} colModel The column model with info about this grid's columns
55629 Roo.grid.EditorGrid = function(container, config){
55630 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55631 this.getGridEl().addClass("xedit-grid");
55633 if(!this.selModel){
55634 this.selModel = new Roo.grid.CellSelectionModel();
55637 this.activeEditor = null;
55641 * @event beforeedit
55642 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55643 * <ul style="padding:5px;padding-left:16px;">
55644 * <li>grid - This grid</li>
55645 * <li>record - The record being edited</li>
55646 * <li>field - The field name being edited</li>
55647 * <li>value - The value for the field being edited.</li>
55648 * <li>row - The grid row index</li>
55649 * <li>column - The grid column index</li>
55650 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55652 * @param {Object} e An edit event (see above for description)
55654 "beforeedit" : true,
55657 * Fires after a cell is edited. <br />
55658 * <ul style="padding:5px;padding-left:16px;">
55659 * <li>grid - This grid</li>
55660 * <li>record - The record being edited</li>
55661 * <li>field - The field name being edited</li>
55662 * <li>value - The value being set</li>
55663 * <li>originalValue - The original value for the field, before the edit.</li>
55664 * <li>row - The grid row index</li>
55665 * <li>column - The grid column index</li>
55667 * @param {Object} e An edit event (see above for description)
55669 "afteredit" : true,
55671 * @event validateedit
55672 * Fires after a cell is edited, but before the value is set in the record.
55673 * You can use this to modify the value being set in the field, Return false
55674 * to cancel the change. The edit event object has the following properties <br />
55675 * <ul style="padding:5px;padding-left:16px;">
55676 * <li>editor - This editor</li>
55677 * <li>grid - This grid</li>
55678 * <li>record - The record being edited</li>
55679 * <li>field - The field name being edited</li>
55680 * <li>value - The value being set</li>
55681 * <li>originalValue - The original value for the field, before the edit.</li>
55682 * <li>row - The grid row index</li>
55683 * <li>column - The grid column index</li>
55684 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55686 * @param {Object} e An edit event (see above for description)
55688 "validateedit" : true
55690 this.on("bodyscroll", this.stopEditing, this);
55691 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55694 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55696 * @cfg {Number} clicksToEdit
55697 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55704 trackMouseOver: false, // causes very odd FF errors
55706 onCellDblClick : function(g, row, col){
55707 this.startEditing(row, col);
55710 onEditComplete : function(ed, value, startValue){
55711 this.editing = false;
55712 this.activeEditor = null;
55713 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
55715 var field = this.colModel.getDataIndex(ed.col);
55720 originalValue: startValue,
55727 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
55730 if(String(value) !== String(startValue)){
55732 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
55733 r.set(field, e.value);
55734 // if we are dealing with a combo box..
55735 // then we also set the 'name' colum to be the displayField
55736 if (ed.field.displayField && ed.field.name) {
55737 r.set(ed.field.name, ed.field.el.dom.value);
55740 delete e.cancel; //?? why!!!
55741 this.fireEvent("afteredit", e);
55744 this.fireEvent("afteredit", e); // always fire it!
55746 this.view.focusCell(ed.row, ed.col);
55750 * Starts editing the specified for the specified row/column
55751 * @param {Number} rowIndex
55752 * @param {Number} colIndex
55754 startEditing : function(row, col){
55755 this.stopEditing();
55756 if(this.colModel.isCellEditable(col, row)){
55757 this.view.ensureVisible(row, col, true);
55759 var r = this.dataSource.getAt(row);
55760 var field = this.colModel.getDataIndex(col);
55761 var cell = Roo.get(this.view.getCell(row,col));
55766 value: r.data[field],
55771 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
55772 this.editing = true;
55773 var ed = this.colModel.getCellEditor(col, row);
55779 ed.render(ed.parentEl || document.body);
55785 (function(){ // complex but required for focus issues in safari, ie and opera
55789 ed.on("complete", this.onEditComplete, this, {single: true});
55790 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
55791 this.activeEditor = ed;
55792 var v = r.data[field];
55793 ed.startEdit(this.view.getCell(row, col), v);
55794 // combo's with 'displayField and name set
55795 if (ed.field.displayField && ed.field.name) {
55796 ed.field.el.dom.value = r.data[ed.field.name];
55800 }).defer(50, this);
55806 * Stops any active editing
55808 stopEditing : function(){
55809 if(this.activeEditor){
55810 this.activeEditor.completeEdit();
55812 this.activeEditor = null;
55816 * Called to get grid's drag proxy text, by default returns this.ddText.
55819 getDragDropText : function(){
55820 var count = this.selModel.getSelectedCell() ? 1 : 0;
55821 return String.format(this.ddText, count, count == 1 ? '' : 's');
55826 * Ext JS Library 1.1.1
55827 * Copyright(c) 2006-2007, Ext JS, LLC.
55829 * Originally Released Under LGPL - original licence link has changed is not relivant.
55832 * <script type="text/javascript">
55835 // private - not really -- you end up using it !
55836 // This is a support class used internally by the Grid components
55839 * @class Roo.grid.GridEditor
55840 * @extends Roo.Editor
55841 * Class for creating and editable grid elements.
55842 * @param {Object} config any settings (must include field)
55844 Roo.grid.GridEditor = function(field, config){
55845 if (!config && field.field) {
55847 field = Roo.factory(config.field, Roo.form);
55849 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
55850 field.monitorTab = false;
55853 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
55856 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
55859 alignment: "tl-tl",
55862 cls: "x-small-editor x-grid-editor",
55867 * Ext JS Library 1.1.1
55868 * Copyright(c) 2006-2007, Ext JS, LLC.
55870 * Originally Released Under LGPL - original licence link has changed is not relivant.
55873 * <script type="text/javascript">
55878 Roo.grid.PropertyRecord = Roo.data.Record.create([
55879 {name:'name',type:'string'}, 'value'
55883 Roo.grid.PropertyStore = function(grid, source){
55885 this.store = new Roo.data.Store({
55886 recordType : Roo.grid.PropertyRecord
55888 this.store.on('update', this.onUpdate, this);
55890 this.setSource(source);
55892 Roo.grid.PropertyStore.superclass.constructor.call(this);
55897 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
55898 setSource : function(o){
55900 this.store.removeAll();
55903 if(this.isEditableValue(o[k])){
55904 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
55907 this.store.loadRecords({records: data}, {}, true);
55910 onUpdate : function(ds, record, type){
55911 if(type == Roo.data.Record.EDIT){
55912 var v = record.data['value'];
55913 var oldValue = record.modified['value'];
55914 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
55915 this.source[record.id] = v;
55917 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
55924 getProperty : function(row){
55925 return this.store.getAt(row);
55928 isEditableValue: function(val){
55929 if(val && val instanceof Date){
55931 }else if(typeof val == 'object' || typeof val == 'function'){
55937 setValue : function(prop, value){
55938 this.source[prop] = value;
55939 this.store.getById(prop).set('value', value);
55942 getSource : function(){
55943 return this.source;
55947 Roo.grid.PropertyColumnModel = function(grid, store){
55950 g.PropertyColumnModel.superclass.constructor.call(this, [
55951 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
55952 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
55954 this.store = store;
55955 this.bselect = Roo.DomHelper.append(document.body, {
55956 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
55957 {tag: 'option', value: 'true', html: 'true'},
55958 {tag: 'option', value: 'false', html: 'false'}
55961 Roo.id(this.bselect);
55964 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
55965 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
55966 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
55967 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
55968 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
55970 this.renderCellDelegate = this.renderCell.createDelegate(this);
55971 this.renderPropDelegate = this.renderProp.createDelegate(this);
55974 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
55978 valueText : 'Value',
55980 dateFormat : 'm/j/Y',
55983 renderDate : function(dateVal){
55984 return dateVal.dateFormat(this.dateFormat);
55987 renderBool : function(bVal){
55988 return bVal ? 'true' : 'false';
55991 isCellEditable : function(colIndex, rowIndex){
55992 return colIndex == 1;
55995 getRenderer : function(col){
55997 this.renderCellDelegate : this.renderPropDelegate;
56000 renderProp : function(v){
56001 return this.getPropertyName(v);
56004 renderCell : function(val){
56006 if(val instanceof Date){
56007 rv = this.renderDate(val);
56008 }else if(typeof val == 'boolean'){
56009 rv = this.renderBool(val);
56011 return Roo.util.Format.htmlEncode(rv);
56014 getPropertyName : function(name){
56015 var pn = this.grid.propertyNames;
56016 return pn && pn[name] ? pn[name] : name;
56019 getCellEditor : function(colIndex, rowIndex){
56020 var p = this.store.getProperty(rowIndex);
56021 var n = p.data['name'], val = p.data['value'];
56023 if(typeof(this.grid.customEditors[n]) == 'string'){
56024 return this.editors[this.grid.customEditors[n]];
56026 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56027 return this.grid.customEditors[n];
56029 if(val instanceof Date){
56030 return this.editors['date'];
56031 }else if(typeof val == 'number'){
56032 return this.editors['number'];
56033 }else if(typeof val == 'boolean'){
56034 return this.editors['boolean'];
56036 return this.editors['string'];
56042 * @class Roo.grid.PropertyGrid
56043 * @extends Roo.grid.EditorGrid
56044 * This class represents the interface of a component based property grid control.
56045 * <br><br>Usage:<pre><code>
56046 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56054 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56055 * The container MUST have some type of size defined for the grid to fill. The container will be
56056 * automatically set to position relative if it isn't already.
56057 * @param {Object} config A config object that sets properties on this grid.
56059 Roo.grid.PropertyGrid = function(container, config){
56060 config = config || {};
56061 var store = new Roo.grid.PropertyStore(this);
56062 this.store = store;
56063 var cm = new Roo.grid.PropertyColumnModel(this, store);
56064 store.store.sort('name', 'ASC');
56065 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56068 enableColLock:false,
56069 enableColumnMove:false,
56071 trackMouseOver: false,
56074 this.getGridEl().addClass('x-props-grid');
56075 this.lastEditRow = null;
56076 this.on('columnresize', this.onColumnResize, this);
56079 * @event beforepropertychange
56080 * Fires before a property changes (return false to stop?)
56081 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56082 * @param {String} id Record Id
56083 * @param {String} newval New Value
56084 * @param {String} oldval Old Value
56086 "beforepropertychange": true,
56088 * @event propertychange
56089 * Fires after a property changes
56090 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56091 * @param {String} id Record Id
56092 * @param {String} newval New Value
56093 * @param {String} oldval Old Value
56095 "propertychange": true
56097 this.customEditors = this.customEditors || {};
56099 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56102 * @cfg {Object} customEditors map of colnames=> custom editors.
56103 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56104 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56105 * false disables editing of the field.
56109 * @cfg {Object} propertyNames map of property Names to their displayed value
56112 render : function(){
56113 Roo.grid.PropertyGrid.superclass.render.call(this);
56114 this.autoSize.defer(100, this);
56117 autoSize : function(){
56118 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56120 this.view.fitColumns();
56124 onColumnResize : function(){
56125 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56129 * Sets the data for the Grid
56130 * accepts a Key => Value object of all the elements avaiable.
56131 * @param {Object} data to appear in grid.
56133 setSource : function(source){
56134 this.store.setSource(source);
56138 * Gets all the data from the grid.
56139 * @return {Object} data data stored in grid
56141 getSource : function(){
56142 return this.store.getSource();
56151 * @class Roo.grid.Calendar
56152 * @extends Roo.util.Grid
56153 * This class extends the Grid to provide a calendar widget
56154 * <br><br>Usage:<pre><code>
56155 var grid = new Roo.grid.Calendar("my-container-id", {
56158 selModel: mySelectionModel,
56159 autoSizeColumns: true,
56160 monitorWindowResize: false,
56161 trackMouseOver: true
56162 eventstore : real data store..
56168 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56169 * The container MUST have some type of size defined for the grid to fill. The container will be
56170 * automatically set to position relative if it isn't already.
56171 * @param {Object} config A config object that sets properties on this grid.
56173 Roo.grid.Calendar = function(container, config){
56174 // initialize the container
56175 this.container = Roo.get(container);
56176 this.container.update("");
56177 this.container.setStyle("overflow", "hidden");
56178 this.container.addClass('x-grid-container');
56180 this.id = this.container.id;
56182 Roo.apply(this, config);
56183 // check and correct shorthanded configs
56187 for (var r = 0;r < 6;r++) {
56190 for (var c =0;c < 7;c++) {
56194 if (this.eventStore) {
56195 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56196 this.eventStore.on('load',this.onLoad, this);
56197 this.eventStore.on('beforeload',this.clearEvents, this);
56201 this.dataSource = new Roo.data.Store({
56202 proxy: new Roo.data.MemoryProxy(rows),
56203 reader: new Roo.data.ArrayReader({}, [
56204 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56207 this.dataSource.load();
56208 this.ds = this.dataSource;
56209 this.ds.xmodule = this.xmodule || false;
56212 var cellRender = function(v,x,r)
56214 return String.format(
56215 '<div class="fc-day fc-widget-content"><div>' +
56216 '<div class="fc-event-container"></div>' +
56217 '<div class="fc-day-number">{0}</div>'+
56219 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56220 '</div></div>', v);
56225 this.colModel = new Roo.grid.ColumnModel( [
56227 xtype: 'ColumnModel',
56229 dataIndex : 'weekday0',
56231 renderer : cellRender
56234 xtype: 'ColumnModel',
56236 dataIndex : 'weekday1',
56238 renderer : cellRender
56241 xtype: 'ColumnModel',
56243 dataIndex : 'weekday2',
56244 header : 'Tuesday',
56245 renderer : cellRender
56248 xtype: 'ColumnModel',
56250 dataIndex : 'weekday3',
56251 header : 'Wednesday',
56252 renderer : cellRender
56255 xtype: 'ColumnModel',
56257 dataIndex : 'weekday4',
56258 header : 'Thursday',
56259 renderer : cellRender
56262 xtype: 'ColumnModel',
56264 dataIndex : 'weekday5',
56266 renderer : cellRender
56269 xtype: 'ColumnModel',
56271 dataIndex : 'weekday6',
56272 header : 'Saturday',
56273 renderer : cellRender
56276 this.cm = this.colModel;
56277 this.cm.xmodule = this.xmodule || false;
56281 //this.selModel = new Roo.grid.CellSelectionModel();
56282 //this.sm = this.selModel;
56283 //this.selModel.init(this);
56287 this.container.setWidth(this.width);
56291 this.container.setHeight(this.height);
56298 * The raw click event for the entire grid.
56299 * @param {Roo.EventObject} e
56304 * The raw dblclick event for the entire grid.
56305 * @param {Roo.EventObject} e
56309 * @event contextmenu
56310 * The raw contextmenu event for the entire grid.
56311 * @param {Roo.EventObject} e
56313 "contextmenu" : true,
56316 * The raw mousedown event for the entire grid.
56317 * @param {Roo.EventObject} e
56319 "mousedown" : true,
56322 * The raw mouseup event for the entire grid.
56323 * @param {Roo.EventObject} e
56328 * The raw mouseover event for the entire grid.
56329 * @param {Roo.EventObject} e
56331 "mouseover" : true,
56334 * The raw mouseout event for the entire grid.
56335 * @param {Roo.EventObject} e
56340 * The raw keypress event for the entire grid.
56341 * @param {Roo.EventObject} e
56346 * The raw keydown event for the entire grid.
56347 * @param {Roo.EventObject} e
56355 * Fires when a cell is clicked
56356 * @param {Grid} this
56357 * @param {Number} rowIndex
56358 * @param {Number} columnIndex
56359 * @param {Roo.EventObject} e
56361 "cellclick" : true,
56363 * @event celldblclick
56364 * Fires when a cell is double clicked
56365 * @param {Grid} this
56366 * @param {Number} rowIndex
56367 * @param {Number} columnIndex
56368 * @param {Roo.EventObject} e
56370 "celldblclick" : true,
56373 * Fires when a row is clicked
56374 * @param {Grid} this
56375 * @param {Number} rowIndex
56376 * @param {Roo.EventObject} e
56380 * @event rowdblclick
56381 * Fires when a row is double clicked
56382 * @param {Grid} this
56383 * @param {Number} rowIndex
56384 * @param {Roo.EventObject} e
56386 "rowdblclick" : true,
56388 * @event headerclick
56389 * Fires when a header is clicked
56390 * @param {Grid} this
56391 * @param {Number} columnIndex
56392 * @param {Roo.EventObject} e
56394 "headerclick" : true,
56396 * @event headerdblclick
56397 * Fires when a header cell is double clicked
56398 * @param {Grid} this
56399 * @param {Number} columnIndex
56400 * @param {Roo.EventObject} e
56402 "headerdblclick" : true,
56404 * @event rowcontextmenu
56405 * Fires when a row is right clicked
56406 * @param {Grid} this
56407 * @param {Number} rowIndex
56408 * @param {Roo.EventObject} e
56410 "rowcontextmenu" : true,
56412 * @event cellcontextmenu
56413 * Fires when a cell is right clicked
56414 * @param {Grid} this
56415 * @param {Number} rowIndex
56416 * @param {Number} cellIndex
56417 * @param {Roo.EventObject} e
56419 "cellcontextmenu" : true,
56421 * @event headercontextmenu
56422 * Fires when a header is right clicked
56423 * @param {Grid} this
56424 * @param {Number} columnIndex
56425 * @param {Roo.EventObject} e
56427 "headercontextmenu" : true,
56429 * @event bodyscroll
56430 * Fires when the body element is scrolled
56431 * @param {Number} scrollLeft
56432 * @param {Number} scrollTop
56434 "bodyscroll" : true,
56436 * @event columnresize
56437 * Fires when the user resizes a column
56438 * @param {Number} columnIndex
56439 * @param {Number} newSize
56441 "columnresize" : true,
56443 * @event columnmove
56444 * Fires when the user moves a column
56445 * @param {Number} oldIndex
56446 * @param {Number} newIndex
56448 "columnmove" : true,
56451 * Fires when row(s) start being dragged
56452 * @param {Grid} this
56453 * @param {Roo.GridDD} dd The drag drop object
56454 * @param {event} e The raw browser event
56456 "startdrag" : true,
56459 * Fires when a drag operation is complete
56460 * @param {Grid} this
56461 * @param {Roo.GridDD} dd The drag drop object
56462 * @param {event} e The raw browser event
56467 * Fires when dragged row(s) are dropped on a valid DD target
56468 * @param {Grid} this
56469 * @param {Roo.GridDD} dd The drag drop object
56470 * @param {String} targetId The target drag drop object
56471 * @param {event} e The raw browser event
56476 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56477 * @param {Grid} this
56478 * @param {Roo.GridDD} dd The drag drop object
56479 * @param {String} targetId The target drag drop object
56480 * @param {event} e The raw browser event
56485 * Fires when the dragged row(s) first cross another DD target while being dragged
56486 * @param {Grid} this
56487 * @param {Roo.GridDD} dd The drag drop object
56488 * @param {String} targetId The target drag drop object
56489 * @param {event} e The raw browser event
56491 "dragenter" : true,
56494 * Fires when the dragged row(s) leave another DD target while being dragged
56495 * @param {Grid} this
56496 * @param {Roo.GridDD} dd The drag drop object
56497 * @param {String} targetId The target drag drop object
56498 * @param {event} e The raw browser event
56503 * Fires when a row is rendered, so you can change add a style to it.
56504 * @param {GridView} gridview The grid view
56505 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56511 * Fires when the grid is rendered
56512 * @param {Grid} grid
56517 * Fires when a date is selected
56518 * @param {DatePicker} this
56519 * @param {Date} date The selected date
56523 * @event monthchange
56524 * Fires when the displayed month changes
56525 * @param {DatePicker} this
56526 * @param {Date} date The selected month
56528 'monthchange': true,
56530 * @event evententer
56531 * Fires when mouse over an event
56532 * @param {Calendar} this
56533 * @param {event} Event
56535 'evententer': true,
56537 * @event eventleave
56538 * Fires when the mouse leaves an
56539 * @param {Calendar} this
56542 'eventleave': true,
56544 * @event eventclick
56545 * Fires when the mouse click an
56546 * @param {Calendar} this
56549 'eventclick': true,
56551 * @event eventrender
56552 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56553 * @param {Calendar} this
56554 * @param {data} data to be modified
56556 'eventrender': true
56560 Roo.grid.Grid.superclass.constructor.call(this);
56561 this.on('render', function() {
56562 this.view.el.addClass('x-grid-cal');
56564 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56568 if (!Roo.grid.Calendar.style) {
56569 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56572 '.x-grid-cal .x-grid-col' : {
56573 height: 'auto !important',
56574 'vertical-align': 'top'
56576 '.x-grid-cal .fc-event-hori' : {
56587 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56589 * @cfg {Store} eventStore The store that loads events.
56594 activeDate : false,
56597 monitorWindowResize : false,
56600 resizeColumns : function() {
56601 var col = (this.view.el.getWidth() / 7) - 3;
56602 // loop through cols, and setWidth
56603 for(var i =0 ; i < 7 ; i++){
56604 this.cm.setColumnWidth(i, col);
56607 setDate :function(date) {
56609 Roo.log('setDate?');
56611 this.resizeColumns();
56612 var vd = this.activeDate;
56613 this.activeDate = date;
56614 // if(vd && this.el){
56615 // var t = date.getTime();
56616 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56617 // Roo.log('using add remove');
56619 // this.fireEvent('monthchange', this, date);
56621 // this.cells.removeClass("fc-state-highlight");
56622 // this.cells.each(function(c){
56623 // if(c.dateValue == t){
56624 // c.addClass("fc-state-highlight");
56625 // setTimeout(function(){
56626 // try{c.dom.firstChild.focus();}catch(e){}
56636 var days = date.getDaysInMonth();
56638 var firstOfMonth = date.getFirstDateOfMonth();
56639 var startingPos = firstOfMonth.getDay()-this.startDay;
56641 if(startingPos < this.startDay){
56645 var pm = date.add(Date.MONTH, -1);
56646 var prevStart = pm.getDaysInMonth()-startingPos;
56650 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56652 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
56653 //this.cells.addClassOnOver('fc-state-hover');
56655 var cells = this.cells.elements;
56656 var textEls = this.textNodes;
56658 //Roo.each(cells, function(cell){
56659 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
56662 days += startingPos;
56664 // convert everything to numbers so it's fast
56665 var day = 86400000;
56666 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
56669 //Roo.log(prevStart);
56671 var today = new Date().clearTime().getTime();
56672 var sel = date.clearTime().getTime();
56673 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
56674 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
56675 var ddMatch = this.disabledDatesRE;
56676 var ddText = this.disabledDatesText;
56677 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
56678 var ddaysText = this.disabledDaysText;
56679 var format = this.format;
56681 var setCellClass = function(cal, cell){
56683 //Roo.log('set Cell Class');
56685 var t = d.getTime();
56690 cell.dateValue = t;
56692 cell.className += " fc-today";
56693 cell.className += " fc-state-highlight";
56694 cell.title = cal.todayText;
56697 // disable highlight in other month..
56698 cell.className += " fc-state-highlight";
56703 //cell.className = " fc-state-disabled";
56704 cell.title = cal.minText;
56708 //cell.className = " fc-state-disabled";
56709 cell.title = cal.maxText;
56713 if(ddays.indexOf(d.getDay()) != -1){
56714 // cell.title = ddaysText;
56715 // cell.className = " fc-state-disabled";
56718 if(ddMatch && format){
56719 var fvalue = d.dateFormat(format);
56720 if(ddMatch.test(fvalue)){
56721 cell.title = ddText.replace("%0", fvalue);
56722 cell.className = " fc-state-disabled";
56726 if (!cell.initialClassName) {
56727 cell.initialClassName = cell.dom.className;
56730 cell.dom.className = cell.initialClassName + ' ' + cell.className;
56735 for(; i < startingPos; i++) {
56736 cells[i].dayName = (++prevStart);
56737 Roo.log(textEls[i]);
56738 d.setDate(d.getDate()+1);
56740 //cells[i].className = "fc-past fc-other-month";
56741 setCellClass(this, cells[i]);
56746 for(; i < days; i++){
56747 intDay = i - startingPos + 1;
56748 cells[i].dayName = (intDay);
56749 d.setDate(d.getDate()+1);
56751 cells[i].className = ''; // "x-date-active";
56752 setCellClass(this, cells[i]);
56756 for(; i < 42; i++) {
56757 //textEls[i].innerHTML = (++extraDays);
56759 d.setDate(d.getDate()+1);
56760 cells[i].dayName = (++extraDays);
56761 cells[i].className = "fc-future fc-other-month";
56762 setCellClass(this, cells[i]);
56765 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
56767 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
56769 // this will cause all the cells to mis
56772 for (var r = 0;r < 6;r++) {
56773 for (var c =0;c < 7;c++) {
56774 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
56778 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56779 for(i=0;i<cells.length;i++) {
56781 this.cells.elements[i].dayName = cells[i].dayName ;
56782 this.cells.elements[i].className = cells[i].className;
56783 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
56784 this.cells.elements[i].title = cells[i].title ;
56785 this.cells.elements[i].dateValue = cells[i].dateValue ;
56791 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
56792 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
56794 ////if(totalRows != 6){
56795 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
56796 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
56799 this.fireEvent('monthchange', this, date);
56804 * Returns the grid's SelectionModel.
56805 * @return {SelectionModel}
56807 getSelectionModel : function(){
56808 if(!this.selModel){
56809 this.selModel = new Roo.grid.CellSelectionModel();
56811 return this.selModel;
56815 this.eventStore.load()
56821 findCell : function(dt) {
56822 dt = dt.clearTime().getTime();
56824 this.cells.each(function(c){
56825 //Roo.log("check " +c.dateValue + '?=' + dt);
56826 if(c.dateValue == dt){
56836 findCells : function(rec) {
56837 var s = rec.data.start_dt.clone().clearTime().getTime();
56839 var e= rec.data.end_dt.clone().clearTime().getTime();
56842 this.cells.each(function(c){
56843 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
56845 if(c.dateValue > e){
56848 if(c.dateValue < s){
56857 findBestRow: function(cells)
56861 for (var i =0 ; i < cells.length;i++) {
56862 ret = Math.max(cells[i].rows || 0,ret);
56869 addItem : function(rec)
56871 // look for vertical location slot in
56872 var cells = this.findCells(rec);
56874 rec.row = this.findBestRow(cells);
56876 // work out the location.
56880 for(var i =0; i < cells.length; i++) {
56888 if (crow.start.getY() == cells[i].getY()) {
56890 crow.end = cells[i];
56906 for (var i = 0; i < cells.length;i++) {
56907 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
56914 clearEvents: function() {
56916 if (!this.eventStore.getCount()) {
56919 // reset number of rows in cells.
56920 Roo.each(this.cells.elements, function(c){
56924 this.eventStore.each(function(e) {
56925 this.clearEvent(e);
56930 clearEvent : function(ev)
56933 Roo.each(ev.els, function(el) {
56934 el.un('mouseenter' ,this.onEventEnter, this);
56935 el.un('mouseleave' ,this.onEventLeave, this);
56943 renderEvent : function(ev,ctr) {
56945 ctr = this.view.el.select('.fc-event-container',true).first();
56949 this.clearEvent(ev);
56955 var cells = ev.cells;
56956 var rows = ev.rows;
56957 this.fireEvent('eventrender', this, ev);
56959 for(var i =0; i < rows.length; i++) {
56963 cls += ' fc-event-start';
56965 if ((i+1) == rows.length) {
56966 cls += ' fc-event-end';
56969 //Roo.log(ev.data);
56970 // how many rows should it span..
56971 var cg = this.eventTmpl.append(ctr,Roo.apply({
56974 }, ev.data) , true);
56977 cg.on('mouseenter' ,this.onEventEnter, this, ev);
56978 cg.on('mouseleave' ,this.onEventLeave, this, ev);
56979 cg.on('click', this.onEventClick, this, ev);
56983 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
56984 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
56987 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
56988 cg.setWidth(ebox.right - sbox.x -2);
56992 renderEvents: function()
56994 // first make sure there is enough space..
56996 if (!this.eventTmpl) {
56997 this.eventTmpl = new Roo.Template(
56998 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
56999 '<div class="fc-event-inner">' +
57000 '<span class="fc-event-time">{time}</span>' +
57001 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57003 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57011 this.cells.each(function(c) {
57012 //Roo.log(c.select('.fc-day-content div',true).first());
57013 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57016 var ctr = this.view.el.select('.fc-event-container',true).first();
57019 this.eventStore.each(function(ev){
57021 this.renderEvent(ev);
57025 this.view.layout();
57029 onEventEnter: function (e, el,event,d) {
57030 this.fireEvent('evententer', this, el, event);
57033 onEventLeave: function (e, el,event,d) {
57034 this.fireEvent('eventleave', this, el, event);
57037 onEventClick: function (e, el,event,d) {
57038 this.fireEvent('eventclick', this, el, event);
57041 onMonthChange: function () {
57045 onLoad: function () {
57047 //Roo.log('calendar onload');
57049 if(this.eventStore.getCount() > 0){
57053 this.eventStore.each(function(d){
57058 if (typeof(add.end_dt) == 'undefined') {
57059 Roo.log("Missing End time in calendar data: ");
57063 if (typeof(add.start_dt) == 'undefined') {
57064 Roo.log("Missing Start time in calendar data: ");
57068 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57069 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57070 add.id = add.id || d.id;
57071 add.title = add.title || '??';
57079 this.renderEvents();
57089 render : function ()
57093 if (!this.view.el.hasClass('course-timesheet')) {
57094 this.view.el.addClass('course-timesheet');
57096 if (this.tsStyle) {
57101 Roo.log(_this.grid.view.el.getWidth());
57104 this.tsStyle = Roo.util.CSS.createStyleSheet({
57105 '.course-timesheet .x-grid-row' : {
57108 '.x-grid-row td' : {
57109 'vertical-align' : 0
57111 '.course-edit-link' : {
57113 'text-overflow' : 'ellipsis',
57114 'overflow' : 'hidden',
57115 'white-space' : 'nowrap',
57116 'cursor' : 'pointer'
57121 '.de-act-sup-link' : {
57122 'color' : 'purple',
57123 'text-decoration' : 'line-through'
57127 'text-decoration' : 'line-through'
57129 '.course-timesheet .course-highlight' : {
57130 'border-top-style': 'dashed !important',
57131 'border-bottom-bottom': 'dashed !important'
57133 '.course-timesheet .course-item' : {
57134 'font-family' : 'tahoma, arial, helvetica',
57135 'font-size' : '11px',
57136 'overflow' : 'hidden',
57137 'padding-left' : '10px',
57138 'padding-right' : '10px',
57139 'padding-top' : '10px'
57147 monitorWindowResize : false,
57148 cellrenderer : function(v,x,r)
57153 xtype: 'CellSelectionModel',
57160 beforeload : function (_self, options)
57162 options.params = options.params || {};
57163 options.params._month = _this.monthField.getValue();
57164 options.params.limit = 9999;
57165 options.params['sort'] = 'when_dt';
57166 options.params['dir'] = 'ASC';
57167 this.proxy.loadResponse = this.loadResponse;
57169 //this.addColumns();
57171 load : function (_self, records, options)
57173 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57174 // if you click on the translation.. you can edit it...
57175 var el = Roo.get(this);
57176 var id = el.dom.getAttribute('data-id');
57177 var d = el.dom.getAttribute('data-date');
57178 var t = el.dom.getAttribute('data-time');
57179 //var id = this.child('span').dom.textContent;
57182 Pman.Dialog.CourseCalendar.show({
57186 productitem_active : id ? 1 : 0
57188 _this.grid.ds.load({});
57193 _this.panel.fireEvent('resize', [ '', '' ]);
57196 loadResponse : function(o, success, response){
57197 // this is overridden on before load..
57199 Roo.log("our code?");
57200 //Roo.log(success);
57201 //Roo.log(response)
57202 delete this.activeRequest;
57204 this.fireEvent("loadexception", this, o, response);
57205 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57210 result = o.reader.read(response);
57212 Roo.log("load exception?");
57213 this.fireEvent("loadexception", this, o, response, e);
57214 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57217 Roo.log("ready...");
57218 // loop through result.records;
57219 // and set this.tdate[date] = [] << array of records..
57221 Roo.each(result.records, function(r){
57223 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57224 _this.tdata[r.data.when_dt.format('j')] = [];
57226 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57229 //Roo.log(_this.tdata);
57231 result.records = [];
57232 result.totalRecords = 6;
57234 // let's generate some duumy records for the rows.
57235 //var st = _this.dateField.getValue();
57237 // work out monday..
57238 //st = st.add(Date.DAY, -1 * st.format('w'));
57240 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57242 var firstOfMonth = date.getFirstDayOfMonth();
57243 var days = date.getDaysInMonth();
57245 var firstAdded = false;
57246 for (var i = 0; i < result.totalRecords ; i++) {
57247 //var d= st.add(Date.DAY, i);
57250 for(var w = 0 ; w < 7 ; w++){
57251 if(!firstAdded && firstOfMonth != w){
57258 var dd = (d > 0 && d < 10) ? "0"+d : d;
57259 row['weekday'+w] = String.format(
57260 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57261 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57263 date.format('Y-m-')+dd
57266 if(typeof(_this.tdata[d]) != 'undefined'){
57267 Roo.each(_this.tdata[d], function(r){
57271 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57272 if(r.parent_id*1>0){
57273 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57276 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57277 deactive = 'de-act-link';
57280 row['weekday'+w] += String.format(
57281 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57283 r.product_id_name, //1
57284 r.when_dt.format('h:ia'), //2
57294 // only do this if something added..
57296 result.records.push(_this.grid.dataSource.reader.newRow(row));
57300 // push it twice. (second one with an hour..
57304 this.fireEvent("load", this, o, o.request.arg);
57305 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57307 sortInfo : {field: 'when_dt', direction : 'ASC' },
57309 xtype: 'HttpProxy',
57312 url : baseURL + '/Roo/Shop_course.php'
57315 xtype: 'JsonReader',
57332 'name': 'parent_id',
57336 'name': 'product_id',
57340 'name': 'productitem_id',
57358 click : function (_self, e)
57360 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57361 sd.setMonth(sd.getMonth()-1);
57362 _this.monthField.setValue(sd.format('Y-m-d'));
57363 _this.grid.ds.load({});
57369 xtype: 'Separator',
57373 xtype: 'MonthField',
57376 render : function (_self)
57378 _this.monthField = _self;
57379 // _this.monthField.set today
57381 select : function (combo, date)
57383 _this.grid.ds.load({});
57386 value : (function() { return new Date(); })()
57389 xtype: 'Separator',
57395 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57405 click : function (_self, e)
57407 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57408 sd.setMonth(sd.getMonth()+1);
57409 _this.monthField.setValue(sd.format('Y-m-d'));
57410 _this.grid.ds.load({});
57423 * Ext JS Library 1.1.1
57424 * Copyright(c) 2006-2007, Ext JS, LLC.
57426 * Originally Released Under LGPL - original licence link has changed is not relivant.
57429 * <script type="text/javascript">
57433 * @class Roo.LoadMask
57434 * A simple utility class for generically masking elements while loading data. If the element being masked has
57435 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57436 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57437 * element's UpdateManager load indicator and will be destroyed after the initial load.
57439 * Create a new LoadMask
57440 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57441 * @param {Object} config The config object
57443 Roo.LoadMask = function(el, config){
57444 this.el = Roo.get(el);
57445 Roo.apply(this, config);
57447 this.store.on('beforeload', this.onBeforeLoad, this);
57448 this.store.on('load', this.onLoad, this);
57449 this.store.on('loadexception', this.onLoadException, this);
57450 this.removeMask = false;
57452 var um = this.el.getUpdateManager();
57453 um.showLoadIndicator = false; // disable the default indicator
57454 um.on('beforeupdate', this.onBeforeLoad, this);
57455 um.on('update', this.onLoad, this);
57456 um.on('failure', this.onLoad, this);
57457 this.removeMask = true;
57461 Roo.LoadMask.prototype = {
57463 * @cfg {Boolean} removeMask
57464 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57465 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57468 * @cfg {String} msg
57469 * The text to display in a centered loading message box (defaults to 'Loading...')
57471 msg : 'Loading...',
57473 * @cfg {String} msgCls
57474 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57476 msgCls : 'x-mask-loading',
57479 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57485 * Disables the mask to prevent it from being displayed
57487 disable : function(){
57488 this.disabled = true;
57492 * Enables the mask so that it can be displayed
57494 enable : function(){
57495 this.disabled = false;
57498 onLoadException : function()
57500 Roo.log(arguments);
57502 if (typeof(arguments[3]) != 'undefined') {
57503 Roo.MessageBox.alert("Error loading",arguments[3]);
57507 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57508 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57517 this.el.unmask(this.removeMask);
57520 onLoad : function()
57522 this.el.unmask(this.removeMask);
57526 onBeforeLoad : function(){
57527 if(!this.disabled){
57528 this.el.mask(this.msg, this.msgCls);
57533 destroy : function(){
57535 this.store.un('beforeload', this.onBeforeLoad, this);
57536 this.store.un('load', this.onLoad, this);
57537 this.store.un('loadexception', this.onLoadException, this);
57539 var um = this.el.getUpdateManager();
57540 um.un('beforeupdate', this.onBeforeLoad, this);
57541 um.un('update', this.onLoad, this);
57542 um.un('failure', this.onLoad, this);
57547 * Ext JS Library 1.1.1
57548 * Copyright(c) 2006-2007, Ext JS, LLC.
57550 * Originally Released Under LGPL - original licence link has changed is not relivant.
57553 * <script type="text/javascript">
57558 * @class Roo.XTemplate
57559 * @extends Roo.Template
57560 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57562 var t = new Roo.XTemplate(
57563 '<select name="{name}">',
57564 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57568 // then append, applying the master template values
57571 * Supported features:
57576 {a_variable} - output encoded.
57577 {a_variable.format:("Y-m-d")} - call a method on the variable
57578 {a_variable:raw} - unencoded output
57579 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57580 {a_variable:this.method_on_template(...)} - call a method on the template object.
57585 <tpl for="a_variable or condition.."></tpl>
57586 <tpl if="a_variable or condition"></tpl>
57587 <tpl exec="some javascript"></tpl>
57588 <tpl name="named_template"></tpl> (experimental)
57590 <tpl for="."></tpl> - just iterate the property..
57591 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57595 Roo.XTemplate = function()
57597 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57604 Roo.extend(Roo.XTemplate, Roo.Template, {
57607 * The various sub templates
57612 * basic tag replacing syntax
57615 * // you can fake an object call by doing this
57619 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57622 * compile the template
57624 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57627 compile: function()
57631 s = ['<tpl>', s, '</tpl>'].join('');
57633 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57634 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57635 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57636 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57637 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57642 while(true == !!(m = s.match(re))){
57643 var forMatch = m[0].match(nameRe),
57644 ifMatch = m[0].match(ifRe),
57645 execMatch = m[0].match(execRe),
57646 namedMatch = m[0].match(namedRe),
57651 name = forMatch && forMatch[1] ? forMatch[1] : '';
57654 // if - puts fn into test..
57655 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
57657 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
57662 // exec - calls a function... returns empty if true is returned.
57663 exp = execMatch && execMatch[1] ? execMatch[1] : null;
57665 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
57673 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
57674 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
57675 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
57678 var uid = namedMatch ? namedMatch[1] : id;
57682 id: namedMatch ? namedMatch[1] : id,
57689 s = s.replace(m[0], '');
57691 s = s.replace(m[0], '{xtpl'+ id + '}');
57696 for(var i = tpls.length-1; i >= 0; --i){
57697 this.compileTpl(tpls[i]);
57698 this.tpls[tpls[i].id] = tpls[i];
57700 this.master = tpls[tpls.length-1];
57704 * same as applyTemplate, except it's done to one of the subTemplates
57705 * when using named templates, you can do:
57707 * var str = pl.applySubTemplate('your-name', values);
57710 * @param {Number} id of the template
57711 * @param {Object} values to apply to template
57712 * @param {Object} parent (normaly the instance of this object)
57714 applySubTemplate : function(id, values, parent)
57718 var t = this.tpls[id];
57722 if(t.test && !t.test.call(this, values, parent)){
57726 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
57727 Roo.log(e.toString());
57733 if(t.exec && t.exec.call(this, values, parent)){
57737 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
57738 Roo.log(e.toString());
57743 var vs = t.target ? t.target.call(this, values, parent) : values;
57744 parent = t.target ? values : parent;
57745 if(t.target && vs instanceof Array){
57747 for(var i = 0, len = vs.length; i < len; i++){
57748 buf[buf.length] = t.compiled.call(this, vs[i], parent);
57750 return buf.join('');
57752 return t.compiled.call(this, vs, parent);
57754 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
57755 Roo.log(e.toString());
57756 Roo.log(t.compiled);
57761 compileTpl : function(tpl)
57763 var fm = Roo.util.Format;
57764 var useF = this.disableFormats !== true;
57765 var sep = Roo.isGecko ? "+" : ",";
57766 var undef = function(str) {
57767 Roo.log("Property not found :" + str);
57771 var fn = function(m, name, format, args)
57773 //Roo.log(arguments);
57774 args = args ? args.replace(/\\'/g,"'") : args;
57775 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
57776 if (typeof(format) == 'undefined') {
57777 format= 'htmlEncode';
57779 if (format == 'raw' ) {
57783 if(name.substr(0, 4) == 'xtpl'){
57784 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
57787 // build an array of options to determine if value is undefined..
57789 // basically get 'xxxx.yyyy' then do
57790 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
57791 // (function () { Roo.log("Property not found"); return ''; })() :
57796 Roo.each(name.split('.'), function(st) {
57797 lookfor += (lookfor.length ? '.': '') + st;
57798 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
57801 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
57804 if(format && useF){
57806 args = args ? ',' + args : "";
57808 if(format.substr(0, 5) != "this."){
57809 format = "fm." + format + '(';
57811 format = 'this.call("'+ format.substr(5) + '", ';
57815 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
57819 // called with xxyx.yuu:(test,test)
57821 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
57823 // raw.. - :raw modifier..
57824 return "'"+ sep + udef_st + name + ")"+sep+"'";
57828 // branched to use + in gecko and [].join() in others
57830 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
57831 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
57834 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
57835 body.push(tpl.body.replace(/(\r\n|\n)/g,
57836 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
57837 body.push("'].join('');};};");
57838 body = body.join('');
57841 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
57843 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
57849 applyTemplate : function(values){
57850 return this.master.compiled.call(this, values, {});
57851 //var s = this.subs;
57854 apply : function(){
57855 return this.applyTemplate.apply(this, arguments);
57860 Roo.XTemplate.from = function(el){
57861 el = Roo.getDom(el);
57862 return new Roo.XTemplate(el.value || el.innerHTML);