4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isTouch = (function() {
68 document.createEvent("TouchEvent");
75 // remove css image flicker
78 document.execCommand("BackgroundImageCache", false, true);
84 * True if the browser is in strict mode
89 * True if the page is running over SSL
94 * True when the document is fully initialized and ready for action
99 * Turn on debugging output (currently only the factory uses this)
106 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
109 enableGarbageCollector : true,
112 * True to automatically purge event listeners after uncaching an element (defaults to false).
113 * Note: this only happens if enableGarbageCollector is true.
116 enableListenerCollection:false,
119 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
120 * the IE insecure content warning (defaults to javascript:false).
123 SSL_SECURE_URL : "javascript:false",
126 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
127 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
130 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
132 emptyFn : function(){},
135 * Copies all the properties of config to obj if they don't already exist.
136 * @param {Object} obj The receiver of the properties
137 * @param {Object} config The source of the properties
138 * @return {Object} returns obj
140 applyIf : function(o, c){
143 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
150 * Applies event listeners to elements by selectors when the document is ready.
151 * The event name is specified with an @ suffix.
154 // add a listener for click on all anchors in element with id foo
155 '#foo a@click' : function(e, t){
159 // add the same listener to multiple selectors (separated by comma BEFORE the @)
160 '#foo a, #bar span.some-class@mouseover' : function(){
165 * @param {Object} obj The list of behaviors to apply
167 addBehaviors : function(o){
169 Roo.onReady(function(){
174 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
176 var parts = b.split('@');
177 if(parts[1]){ // for Object prototype breakers
180 cache[s] = Roo.select(s);
182 cache[s].on(parts[1], o[b]);
189 * Generates unique ids. If the element already has an id, it is unchanged
190 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
191 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
192 * @return {String} The generated Id.
194 id : function(el, prefix){
195 prefix = prefix || "roo-gen";
197 var id = prefix + (++idSeed);
198 return el ? (el.id ? el.id : (el.id = id)) : id;
203 * Extends one class with another class and optionally overrides members with the passed literal. This class
204 * also adds the function "override()" to the class that can be used to override
205 * members on an instance.
206 * @param {Object} subclass The class inheriting the functionality
207 * @param {Object} superclass The class being extended
208 * @param {Object} overrides (optional) A literal with members
213 var io = function(o){
218 return function(sb, sp, overrides){
219 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
222 sb = function(){sp.apply(this, arguments);};
224 var F = function(){}, sbp, spp = sp.prototype;
226 sbp = sb.prototype = new F();
230 if(spp.constructor == Object.prototype.constructor){
235 sb.override = function(o){
239 Roo.override(sb, overrides);
245 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
247 Roo.override(MyClass, {
248 newMethod1: function(){
251 newMethod2: function(foo){
256 * @param {Object} origclass The class to override
257 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
258 * containing one or more methods.
261 override : function(origclass, overrides){
263 var p = origclass.prototype;
264 for(var method in overrides){
265 p[method] = overrides[method];
270 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
272 Roo.namespace('Company', 'Company.data');
273 Company.Widget = function() { ... }
274 Company.data.CustomStore = function(config) { ... }
276 * @param {String} namespace1
277 * @param {String} namespace2
278 * @param {String} etc
281 namespace : function(){
282 var a=arguments, o=null, i, j, d, rt;
283 for (i=0; i<a.length; ++i) {
287 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
288 for (j=1; j<d.length; ++j) {
289 o[d[j]]=o[d[j]] || {};
295 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
297 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
298 Roo.factory(conf, Roo.data);
300 * @param {String} classname
301 * @param {String} namespace (optional)
305 factory : function(c, ns)
307 // no xtype, no ns or c.xns - or forced off by c.xns
308 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
311 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
312 if (c.constructor == ns[c.xtype]) {// already created...
316 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
317 var ret = new ns[c.xtype](c);
321 c.xns = false; // prevent recursion..
325 * Logs to console if it can.
327 * @param {String|Object} string
332 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
339 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
343 urlEncode : function(o){
349 var ov = o[key], k = Roo.encodeURIComponent(key);
350 var type = typeof ov;
351 if(type == 'undefined'){
353 }else if(type != "function" && type != "object"){
354 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
355 }else if(ov instanceof Array){
357 for(var i = 0, len = ov.length; i < len; i++) {
358 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369 * Safe version of encodeURIComponent
370 * @param {String} data
374 encodeURIComponent : function (data)
377 return encodeURIComponent(data);
378 } catch(e) {} // should be an uri encode error.
380 if (data == '' || data == null){
383 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
384 function nibble_to_hex(nibble){
385 var chars = '0123456789ABCDEF';
386 return chars.charAt(nibble);
388 data = data.toString();
390 for(var i=0; i<data.length; i++){
391 var c = data.charCodeAt(i);
392 var bs = new Array();
395 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
396 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
397 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
398 bs[3] = 0x80 | (c & 0x3F);
399 }else if (c > 0x800){
401 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
402 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
403 bs[2] = 0x80 | (c & 0x3F);
406 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
407 bs[1] = 0x80 | (c & 0x3F);
412 for(var j=0; j<bs.length; j++){
414 var hex = nibble_to_hex((b & 0xF0) >>> 4)
415 + nibble_to_hex(b &0x0F);
424 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
425 * @param {String} string
426 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
427 * @return {Object} A literal with members
429 urlDecode : function(string, overwrite){
430 if(!string || !string.length){
434 var pairs = string.split('&');
435 var pair, name, value;
436 for(var i = 0, len = pairs.length; i < len; i++){
437 pair = pairs[i].split('=');
438 name = decodeURIComponent(pair[0]);
439 value = decodeURIComponent(pair[1]);
440 if(overwrite !== true){
441 if(typeof obj[name] == "undefined"){
443 }else if(typeof obj[name] == "string"){
444 obj[name] = [obj[name]];
445 obj[name].push(value);
447 obj[name].push(value);
457 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
458 * passed array is not really an array, your function is called once with it.
459 * The supplied function is called with (Object item, Number index, Array allItems).
460 * @param {Array/NodeList/Mixed} array
461 * @param {Function} fn
462 * @param {Object} scope
464 each : function(array, fn, scope){
465 if(typeof array.length == "undefined" || typeof array == "string"){
468 for(var i = 0, len = array.length; i < len; i++){
469 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
474 combine : function(){
475 var as = arguments, l = as.length, r = [];
476 for(var i = 0; i < l; i++){
478 if(a instanceof Array){
480 }else if(a.length !== undefined && !a.substr){
481 r = r.concat(Array.prototype.slice.call(a, 0));
490 * Escapes the passed string for use in a regular expression
491 * @param {String} str
494 escapeRe : function(s) {
495 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
499 callback : function(cb, scope, args, delay){
500 if(typeof cb == "function"){
502 cb.defer(delay, scope, args || []);
504 cb.apply(scope, args || []);
510 * Return the dom node for the passed string (id), dom node, or Roo.Element
511 * @param {String/HTMLElement/Roo.Element} el
512 * @return HTMLElement
514 getDom : function(el){
518 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
522 * Shorthand for {@link Roo.ComponentMgr#get}
524 * @return Roo.Component
526 getCmp : function(id){
527 return Roo.ComponentMgr.get(id);
530 num : function(v, defaultValue){
531 if(typeof v != 'number'){
537 destroy : function(){
538 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
542 as.removeAllListeners();
546 if(typeof as.purgeListeners == 'function'){
549 if(typeof as.destroy == 'function'){
556 // inpired by a similar function in mootools library
558 * Returns the type of object that is passed in. If the object passed in is null or undefined it
559 * return false otherwise it returns one of the following values:<ul>
560 * <li><b>string</b>: If the object passed is a string</li>
561 * <li><b>number</b>: If the object passed is a number</li>
562 * <li><b>boolean</b>: If the object passed is a boolean value</li>
563 * <li><b>function</b>: If the object passed is a function reference</li>
564 * <li><b>object</b>: If the object passed is an object</li>
565 * <li><b>array</b>: If the object passed is an array</li>
566 * <li><b>regexp</b>: If the object passed is a regular expression</li>
567 * <li><b>element</b>: If the object passed is a DOM Element</li>
568 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
569 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
570 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
571 * @param {Mixed} object
575 if(o === undefined || o === null){
582 if(t == 'object' && o.nodeName) {
584 case 1: return 'element';
585 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
588 if(t == 'object' || t == 'function') {
589 switch(o.constructor) {
590 case Array: return 'array';
591 case RegExp: return 'regexp';
593 if(typeof o.length == 'number' && typeof o.item == 'function') {
601 * Returns true if the passed value is null, undefined or an empty string (optional).
602 * @param {Mixed} value The value to test
603 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
606 isEmpty : function(v, allowBlank){
607 return v === null || v === undefined || (!allowBlank ? v === '' : false);
615 isFirefox : isFirefox,
625 isBorderBox : isBorderBox,
627 isWindows : isWindows,
636 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
637 * you may want to set this to true.
640 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
645 * Selects a single element as a Roo Element
646 * This is about as close as you can get to jQuery's $('do crazy stuff')
647 * @param {String} selector The selector/xpath query
648 * @param {Node} root (optional) The start of the query (defaults to document).
649 * @return {Roo.Element}
651 selectNode : function(selector, root)
653 var node = Roo.DomQuery.selectNode(selector,root);
654 return node ? Roo.get(node) : new Roo.Element(false);
662 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
663 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
666 "Roo.bootstrap.dash");
669 * Ext JS Library 1.1.1
670 * Copyright(c) 2006-2007, Ext JS, LLC.
672 * Originally Released Under LGPL - original licence link has changed is not relivant.
675 * <script type="text/javascript">
679 // wrappedn so fnCleanup is not in global scope...
681 function fnCleanUp() {
682 var p = Function.prototype;
683 delete p.createSequence;
685 delete p.createDelegate;
686 delete p.createCallback;
687 delete p.createInterceptor;
689 window.detachEvent("onunload", fnCleanUp);
691 window.attachEvent("onunload", fnCleanUp);
698 * These functions are available on every Function object (any JavaScript function).
700 Roo.apply(Function.prototype, {
702 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
703 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
704 * Will create a function that is bound to those 2 args.
705 * @return {Function} The new function
707 createCallback : function(/*args...*/){
708 // make args available, in function below
709 var args = arguments;
712 return method.apply(window, args);
717 * Creates a delegate (callback) that sets the scope to obj.
718 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
719 * Will create a function that is automatically scoped to this.
720 * @param {Object} obj (optional) The object for which the scope is set
721 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
722 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
723 * if a number the args are inserted at the specified position
724 * @return {Function} The new function
726 createDelegate : function(obj, args, appendArgs){
729 var callArgs = args || arguments;
730 if(appendArgs === true){
731 callArgs = Array.prototype.slice.call(arguments, 0);
732 callArgs = callArgs.concat(args);
733 }else if(typeof appendArgs == "number"){
734 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
735 var applyArgs = [appendArgs, 0].concat(args); // create method call params
736 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
738 return method.apply(obj || window, callArgs);
743 * Calls this function after the number of millseconds specified.
744 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
745 * @param {Object} obj (optional) The object for which the scope is set
746 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
747 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
748 * if a number the args are inserted at the specified position
749 * @return {Number} The timeout id that can be used with clearTimeout
751 defer : function(millis, obj, args, appendArgs){
752 var fn = this.createDelegate(obj, args, appendArgs);
754 return setTimeout(fn, millis);
760 * Create a combined function call sequence of the original function + the passed function.
761 * The resulting function returns the results of the original function.
762 * The passed fcn is called with the parameters of the original function
763 * @param {Function} fcn The function to sequence
764 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
765 * @return {Function} The new function
767 createSequence : function(fcn, scope){
768 if(typeof fcn != "function"){
773 var retval = method.apply(this || window, arguments);
774 fcn.apply(scope || this || window, arguments);
780 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
781 * The resulting function returns the results of the original function.
782 * The passed fcn is called with the parameters of the original function.
784 * @param {Function} fcn The function to call before the original
785 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
786 * @return {Function} The new function
788 createInterceptor : function(fcn, scope){
789 if(typeof fcn != "function"){
796 if(fcn.apply(scope || this || window, arguments) === false){
799 return method.apply(this || window, arguments);
805 * Ext JS Library 1.1.1
806 * Copyright(c) 2006-2007, Ext JS, LLC.
808 * Originally Released Under LGPL - original licence link has changed is not relivant.
811 * <script type="text/javascript">
814 Roo.applyIf(String, {
819 * Escapes the passed string for ' and \
820 * @param {String} string The string to escape
821 * @return {String} The escaped string
824 escape : function(string) {
825 return string.replace(/('|\\)/g, "\\$1");
829 * Pads the left side of a string with a specified character. This is especially useful
830 * for normalizing number and date strings. Example usage:
832 var s = String.leftPad('123', 5, '0');
833 // s now contains the string: '00123'
835 * @param {String} string The original string
836 * @param {Number} size The total length of the output string
837 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
838 * @return {String} The padded string
841 leftPad : function (val, size, ch) {
842 var result = new String(val);
843 if(ch === null || ch === undefined || ch === '') {
846 while (result.length < size) {
847 result = ch + result;
853 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
854 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
856 var cls = 'my-class', text = 'Some text';
857 var s = String.format('<div class="{0}">{1}</div>', cls, text);
858 // s now contains the string: '<div class="my-class">Some text</div>'
860 * @param {String} string The tokenized string to be formatted
861 * @param {String} value1 The value to replace token {0}
862 * @param {String} value2 Etc...
863 * @return {String} The formatted string
866 format : function(format){
867 var args = Array.prototype.slice.call(arguments, 1);
868 return format.replace(/\{(\d+)\}/g, function(m, i){
869 return Roo.util.Format.htmlEncode(args[i]);
875 * Utility function that allows you to easily switch a string between two alternating values. The passed value
876 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
877 * they are already different, the first value passed in is returned. Note that this method returns the new value
878 * but does not change the current string.
880 // alternate sort directions
881 sort = sort.toggle('ASC', 'DESC');
883 // instead of conditional logic:
884 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
886 * @param {String} value The value to compare to the current string
887 * @param {String} other The new value to use if the string already equals the first value passed in
888 * @return {String} The new value
891 String.prototype.toggle = function(value, other){
892 return this == value ? other : value;
895 * Ext JS Library 1.1.1
896 * Copyright(c) 2006-2007, Ext JS, LLC.
898 * Originally Released Under LGPL - original licence link has changed is not relivant.
901 * <script type="text/javascript">
907 Roo.applyIf(Number.prototype, {
909 * Checks whether or not the current number is within a desired range. If the number is already within the
910 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
911 * exceeded. Note that this method returns the constrained value but does not change the current number.
912 * @param {Number} min The minimum number in the range
913 * @param {Number} max The maximum number in the range
914 * @return {Number} The constrained value if outside the range, otherwise the current value
916 constrain : function(min, max){
917 return Math.min(Math.max(this, min), max);
921 * Ext JS Library 1.1.1
922 * Copyright(c) 2006-2007, Ext JS, LLC.
924 * Originally Released Under LGPL - original licence link has changed is not relivant.
927 * <script type="text/javascript">
932 Roo.applyIf(Array.prototype, {
935 * Checks whether or not the specified object exists in the array.
936 * @param {Object} o The object to check for
937 * @return {Number} The index of o in the array (or -1 if it is not found)
939 indexOf : function(o){
940 for (var i = 0, len = this.length; i < len; i++){
941 if(this[i] == o) return i;
947 * Removes the specified object from the array. If the object is not found nothing happens.
948 * @param {Object} o The object to remove
950 remove : function(o){
951 var index = this.indexOf(o);
953 this.splice(index, 1);
957 * Map (JS 1.6 compatibility)
958 * @param {Function} function to call
962 var len = this.length >>> 0;
963 if (typeof fun != "function")
964 throw new TypeError();
966 var res = new Array(len);
967 var thisp = arguments[1];
968 for (var i = 0; i < len; i++)
971 res[i] = fun.call(thisp, this[i], i, this);
982 * Ext JS Library 1.1.1
983 * Copyright(c) 2006-2007, Ext JS, LLC.
985 * Originally Released Under LGPL - original licence link has changed is not relivant.
988 * <script type="text/javascript">
994 * The date parsing and format syntax is a subset of
995 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
996 * supported will provide results equivalent to their PHP versions.
998 * Following is the list of all currently supported formats:
1001 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1003 Format Output Description
1004 ------ ---------- --------------------------------------------------------------
1005 d 10 Day of the month, 2 digits with leading zeros
1006 D Wed A textual representation of a day, three letters
1007 j 10 Day of the month without leading zeros
1008 l Wednesday A full textual representation of the day of the week
1009 S th English ordinal day of month suffix, 2 chars (use with j)
1010 w 3 Numeric representation of the day of the week
1011 z 9 The julian date, or day of the year (0-365)
1012 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1013 F January A full textual representation of the month
1014 m 01 Numeric representation of a month, with leading zeros
1015 M Jan Month name abbreviation, three letters
1016 n 1 Numeric representation of a month, without leading zeros
1017 t 31 Number of days in the given month
1018 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1019 Y 2007 A full numeric representation of a year, 4 digits
1020 y 07 A two digit representation of a year
1021 a pm Lowercase Ante meridiem and Post meridiem
1022 A PM Uppercase Ante meridiem and Post meridiem
1023 g 3 12-hour format of an hour without leading zeros
1024 G 15 24-hour format of an hour without leading zeros
1025 h 03 12-hour format of an hour with leading zeros
1026 H 15 24-hour format of an hour with leading zeros
1027 i 05 Minutes with leading zeros
1028 s 01 Seconds, with leading zeros
1029 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1030 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1031 T CST Timezone setting of the machine running the code
1032 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1035 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1037 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1038 document.write(dt.format('Y-m-d')); //2007-01-10
1039 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1040 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1043 * Here are some standard date/time patterns that you might find helpful. They
1044 * are not part of the source of Date.js, but to use them you can simply copy this
1045 * block of code into any script that is included after Date.js and they will also become
1046 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1049 ISO8601Long:"Y-m-d H:i:s",
1050 ISO8601Short:"Y-m-d",
1052 LongDate: "l, F d, Y",
1053 FullDateTime: "l, F d, Y g:i:s A",
1056 LongTime: "g:i:s A",
1057 SortableDateTime: "Y-m-d\\TH:i:s",
1058 UniversalSortableDateTime: "Y-m-d H:i:sO",
1065 var dt = new Date();
1066 document.write(dt.format(Date.patterns.ShortDate));
1071 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1072 * They generate precompiled functions from date formats instead of parsing and
1073 * processing the pattern every time you format a date. These functions are available
1074 * on every Date object (any javascript function).
1076 * The original article and download are here:
1077 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1084 Returns the number of milliseconds between this date and date
1085 @param {Date} date (optional) Defaults to now
1086 @return {Number} The diff in milliseconds
1087 @member Date getElapsed
1089 Date.prototype.getElapsed = function(date) {
1090 return Math.abs((date || new Date()).getTime()-this.getTime());
1092 // was in date file..
1096 Date.parseFunctions = {count:0};
1098 Date.parseRegexes = [];
1100 Date.formatFunctions = {count:0};
1103 Date.prototype.dateFormat = function(format) {
1104 if (Date.formatFunctions[format] == null) {
1105 Date.createNewFormat(format);
1107 var func = Date.formatFunctions[format];
1108 return this[func]();
1113 * Formats a date given the supplied format string
1114 * @param {String} format The format string
1115 * @return {String} The formatted date
1118 Date.prototype.format = Date.prototype.dateFormat;
1121 Date.createNewFormat = function(format) {
1122 var funcName = "format" + Date.formatFunctions.count++;
1123 Date.formatFunctions[format] = funcName;
1124 var code = "Date.prototype." + funcName + " = function(){return ";
1125 var special = false;
1127 for (var i = 0; i < format.length; ++i) {
1128 ch = format.charAt(i);
1129 if (!special && ch == "\\") {
1134 code += "'" + String.escape(ch) + "' + ";
1137 code += Date.getFormatCode(ch);
1140 /** eval:var:zzzzzzzzzzzzz */
1141 eval(code.substring(0, code.length - 3) + ";}");
1145 Date.getFormatCode = function(character) {
1146 switch (character) {
1148 return "String.leftPad(this.getDate(), 2, '0') + ";
1150 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1152 return "this.getDate() + ";
1154 return "Date.dayNames[this.getDay()] + ";
1156 return "this.getSuffix() + ";
1158 return "this.getDay() + ";
1160 return "this.getDayOfYear() + ";
1162 return "this.getWeekOfYear() + ";
1164 return "Date.monthNames[this.getMonth()] + ";
1166 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1168 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1170 return "(this.getMonth() + 1) + ";
1172 return "this.getDaysInMonth() + ";
1174 return "(this.isLeapYear() ? 1 : 0) + ";
1176 return "this.getFullYear() + ";
1178 return "('' + this.getFullYear()).substring(2, 4) + ";
1180 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1182 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1184 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1186 return "this.getHours() + ";
1188 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1190 return "String.leftPad(this.getHours(), 2, '0') + ";
1192 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1194 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1196 return "this.getGMTOffset() + ";
1198 return "this.getGMTColonOffset() + ";
1200 return "this.getTimezone() + ";
1202 return "(this.getTimezoneOffset() * -60) + ";
1204 return "'" + String.escape(character) + "' + ";
1209 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1210 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1211 * the date format that is not specified will default to the current date value for that part. Time parts can also
1212 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1213 * string or the parse operation will fail.
1216 //dt = Fri May 25 2007 (current date)
1217 var dt = new Date();
1219 //dt = Thu May 25 2006 (today's month/day in 2006)
1220 dt = Date.parseDate("2006", "Y");
1222 //dt = Sun Jan 15 2006 (all date parts specified)
1223 dt = Date.parseDate("2006-1-15", "Y-m-d");
1225 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1226 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1228 * @param {String} input The unparsed date as a string
1229 * @param {String} format The format the date is in
1230 * @return {Date} The parsed date
1233 Date.parseDate = function(input, format) {
1234 if (Date.parseFunctions[format] == null) {
1235 Date.createParser(format);
1237 var func = Date.parseFunctions[format];
1238 return Date[func](input);
1244 Date.createParser = function(format) {
1245 var funcName = "parse" + Date.parseFunctions.count++;
1246 var regexNum = Date.parseRegexes.length;
1247 var currentGroup = 1;
1248 Date.parseFunctions[format] = funcName;
1250 var code = "Date." + funcName + " = function(input){\n"
1251 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1252 + "var d = new Date();\n"
1253 + "y = d.getFullYear();\n"
1254 + "m = d.getMonth();\n"
1255 + "d = d.getDate();\n"
1256 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1257 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1258 + "if (results && results.length > 0) {";
1261 var special = false;
1263 for (var i = 0; i < format.length; ++i) {
1264 ch = format.charAt(i);
1265 if (!special && ch == "\\") {
1270 regex += String.escape(ch);
1273 var obj = Date.formatCodeToRegex(ch, currentGroup);
1274 currentGroup += obj.g;
1276 if (obj.g && obj.c) {
1282 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1283 + "{v = new Date(y, m, d, h, i, s);}\n"
1284 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1285 + "{v = new Date(y, m, d, h, i);}\n"
1286 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1287 + "{v = new Date(y, m, d, h);}\n"
1288 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1289 + "{v = new Date(y, m, d);}\n"
1290 + "else if (y >= 0 && m >= 0)\n"
1291 + "{v = new Date(y, m);}\n"
1292 + "else if (y >= 0)\n"
1293 + "{v = new Date(y);}\n"
1294 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1295 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1296 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1299 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1300 /** eval:var:zzzzzzzzzzzzz */
1305 Date.formatCodeToRegex = function(character, currentGroup) {
1306 switch (character) {
1310 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1313 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1314 s:"(\\d{1,2})"}; // day of month without leading zeroes
1317 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1318 s:"(\\d{2})"}; // day of month with leading zeroes
1322 s:"(?:" + Date.dayNames.join("|") + ")"};
1326 s:"(?:st|nd|rd|th)"};
1341 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1342 s:"(" + Date.monthNames.join("|") + ")"};
1345 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1346 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1349 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1350 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1353 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1354 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1365 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1369 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1370 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1374 c:"if (results[" + currentGroup + "] == 'am') {\n"
1375 + "if (h == 12) { h = 0; }\n"
1376 + "} else { if (h < 12) { h += 12; }}",
1380 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1381 + "if (h == 12) { h = 0; }\n"
1382 + "} else { if (h < 12) { h += 12; }}",
1387 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1388 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1392 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1393 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1396 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1400 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1405 "o = results[", currentGroup, "];\n",
1406 "var sn = o.substring(0,1);\n", // get + / - sign
1407 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1408 "var mn = o.substring(3,5) % 60;\n", // get minutes
1409 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1410 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1412 s:"([+\-]\\d{2,4})"};
1418 "o = results[", currentGroup, "];\n",
1419 "var sn = o.substring(0,1);\n",
1420 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1421 "var mn = o.substring(4,6) % 60;\n",
1422 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1423 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1429 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1432 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1433 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1434 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1438 s:String.escape(character)};
1443 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1444 * @return {String} The abbreviated timezone name (e.g. 'CST')
1446 Date.prototype.getTimezone = function() {
1447 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1451 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1452 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1454 Date.prototype.getGMTOffset = function() {
1455 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1456 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1457 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1461 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1462 * @return {String} 2-characters representing hours and 2-characters representing minutes
1463 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1465 Date.prototype.getGMTColonOffset = function() {
1466 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1467 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1473 * Get the numeric day number of the year, adjusted for leap year.
1474 * @return {Number} 0 through 364 (365 in leap years)
1476 Date.prototype.getDayOfYear = function() {
1478 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1479 for (var i = 0; i < this.getMonth(); ++i) {
1480 num += Date.daysInMonth[i];
1482 return num + this.getDate() - 1;
1486 * Get the string representation of the numeric week number of the year
1487 * (equivalent to the format specifier 'W').
1488 * @return {String} '00' through '52'
1490 Date.prototype.getWeekOfYear = function() {
1491 // Skip to Thursday of this week
1492 var now = this.getDayOfYear() + (4 - this.getDay());
1493 // Find the first Thursday of the year
1494 var jan1 = new Date(this.getFullYear(), 0, 1);
1495 var then = (7 - jan1.getDay() + 4);
1496 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1500 * Whether or not the current date is in a leap year.
1501 * @return {Boolean} True if the current date is in a leap year, else false
1503 Date.prototype.isLeapYear = function() {
1504 var year = this.getFullYear();
1505 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1509 * Get the first day of the current month, adjusted for leap year. The returned value
1510 * is the numeric day index within the week (0-6) which can be used in conjunction with
1511 * the {@link #monthNames} array to retrieve the textual day name.
1514 var dt = new Date('1/10/2007');
1515 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1517 * @return {Number} The day number (0-6)
1519 Date.prototype.getFirstDayOfMonth = function() {
1520 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1521 return (day < 0) ? (day + 7) : day;
1525 * Get the last day of the current month, adjusted for leap year. The returned value
1526 * is the numeric day index within the week (0-6) which can be used in conjunction with
1527 * the {@link #monthNames} array to retrieve the textual day name.
1530 var dt = new Date('1/10/2007');
1531 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1533 * @return {Number} The day number (0-6)
1535 Date.prototype.getLastDayOfMonth = function() {
1536 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1537 return (day < 0) ? (day + 7) : day;
1542 * Get the first date of this date's month
1545 Date.prototype.getFirstDateOfMonth = function() {
1546 return new Date(this.getFullYear(), this.getMonth(), 1);
1550 * Get the last date of this date's month
1553 Date.prototype.getLastDateOfMonth = function() {
1554 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1557 * Get the number of days in the current month, adjusted for leap year.
1558 * @return {Number} The number of days in the month
1560 Date.prototype.getDaysInMonth = function() {
1561 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1562 return Date.daysInMonth[this.getMonth()];
1566 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1567 * @return {String} 'st, 'nd', 'rd' or 'th'
1569 Date.prototype.getSuffix = function() {
1570 switch (this.getDate()) {
1587 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1590 * An array of textual month names.
1591 * Override these values for international dates, for example...
1592 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1611 * An array of textual day names.
1612 * Override these values for international dates, for example...
1613 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1629 Date.monthNumbers = {
1644 * Creates and returns a new Date instance with the exact same date value as the called instance.
1645 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1646 * variable will also be changed. When the intention is to create a new variable that will not
1647 * modify the original instance, you should create a clone.
1649 * Example of correctly cloning a date:
1652 var orig = new Date('10/1/2006');
1655 document.write(orig); //returns 'Thu Oct 05 2006'!
1658 var orig = new Date('10/1/2006');
1659 var copy = orig.clone();
1661 document.write(orig); //returns 'Thu Oct 01 2006'
1663 * @return {Date} The new Date instance
1665 Date.prototype.clone = function() {
1666 return new Date(this.getTime());
1670 * Clears any time information from this date
1671 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1672 @return {Date} this or the clone
1674 Date.prototype.clearTime = function(clone){
1676 return this.clone().clearTime();
1681 this.setMilliseconds(0);
1686 // safari setMonth is broken
1688 Date.brokenSetMonth = Date.prototype.setMonth;
1689 Date.prototype.setMonth = function(num){
1691 var n = Math.ceil(-num);
1692 var back_year = Math.ceil(n/12);
1693 var month = (n % 12) ? 12 - n % 12 : 0 ;
1694 this.setFullYear(this.getFullYear() - back_year);
1695 return Date.brokenSetMonth.call(this, month);
1697 return Date.brokenSetMonth.apply(this, arguments);
1702 /** Date interval constant
1706 /** Date interval constant
1710 /** Date interval constant
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1726 /** Date interval constant
1732 * Provides a convenient method of performing basic date arithmetic. This method
1733 * does not modify the Date instance being called - it creates and returns
1734 * a new Date instance containing the resulting date value.
1739 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1740 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1742 //Negative values will subtract correctly:
1743 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1744 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1746 //You can even chain several calls together in one line!
1747 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1748 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1751 * @param {String} interval A valid date interval enum value
1752 * @param {Number} value The amount to add to the current date
1753 * @return {Date} The new Date instance
1755 Date.prototype.add = function(interval, value){
1756 var d = this.clone();
1757 if (!interval || value === 0) return d;
1758 switch(interval.toLowerCase()){
1760 d.setMilliseconds(this.getMilliseconds() + value);
1763 d.setSeconds(this.getSeconds() + value);
1766 d.setMinutes(this.getMinutes() + value);
1769 d.setHours(this.getHours() + value);
1772 d.setDate(this.getDate() + value);
1775 var day = this.getDate();
1777 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1780 d.setMonth(this.getMonth() + value);
1783 d.setFullYear(this.getFullYear() + value);
1790 * Ext JS Library 1.1.1
1791 * Copyright(c) 2006-2007, Ext JS, LLC.
1793 * Originally Released Under LGPL - original licence link has changed is not relivant.
1796 * <script type="text/javascript">
1800 * @class Roo.lib.Dom
1803 * Dom utils (from YIU afaik)
1808 * Get the view width
1809 * @param {Boolean} full True will get the full document, otherwise it's the view width
1810 * @return {Number} The width
1813 getViewWidth : function(full) {
1814 return full ? this.getDocumentWidth() : this.getViewportWidth();
1817 * Get the view height
1818 * @param {Boolean} full True will get the full document, otherwise it's the view height
1819 * @return {Number} The height
1821 getViewHeight : function(full) {
1822 return full ? this.getDocumentHeight() : this.getViewportHeight();
1825 getDocumentHeight: function() {
1826 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1827 return Math.max(scrollHeight, this.getViewportHeight());
1830 getDocumentWidth: function() {
1831 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1832 return Math.max(scrollWidth, this.getViewportWidth());
1835 getViewportHeight: function() {
1836 var height = self.innerHeight;
1837 var mode = document.compatMode;
1839 if ((mode || Roo.isIE) && !Roo.isOpera) {
1840 height = (mode == "CSS1Compat") ?
1841 document.documentElement.clientHeight :
1842 document.body.clientHeight;
1848 getViewportWidth: function() {
1849 var width = self.innerWidth;
1850 var mode = document.compatMode;
1852 if (mode || Roo.isIE) {
1853 width = (mode == "CSS1Compat") ?
1854 document.documentElement.clientWidth :
1855 document.body.clientWidth;
1860 isAncestor : function(p, c) {
1867 if (p.contains && !Roo.isSafari) {
1868 return p.contains(c);
1869 } else if (p.compareDocumentPosition) {
1870 return !!(p.compareDocumentPosition(c) & 16);
1872 var parent = c.parentNode;
1877 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1880 parent = parent.parentNode;
1886 getRegion : function(el) {
1887 return Roo.lib.Region.getRegion(el);
1890 getY : function(el) {
1891 return this.getXY(el)[1];
1894 getX : function(el) {
1895 return this.getXY(el)[0];
1898 getXY : function(el) {
1899 var p, pe, b, scroll, bd = document.body;
1900 el = Roo.getDom(el);
1901 var fly = Roo.lib.AnimBase.fly;
1902 if (el.getBoundingClientRect) {
1903 b = el.getBoundingClientRect();
1904 scroll = fly(document).getScroll();
1905 return [b.left + scroll.left, b.top + scroll.top];
1911 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1918 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1925 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1926 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1933 if (p != el && pe.getStyle('overflow') != 'visible') {
1941 if (Roo.isSafari && hasAbsolute) {
1946 if (Roo.isGecko && !hasAbsolute) {
1948 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1949 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1953 while (p && p != bd) {
1954 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1966 setXY : function(el, xy) {
1967 el = Roo.fly(el, '_setXY');
1969 var pts = el.translatePoints(xy);
1970 if (xy[0] !== false) {
1971 el.dom.style.left = pts.left + "px";
1973 if (xy[1] !== false) {
1974 el.dom.style.top = pts.top + "px";
1978 setX : function(el, x) {
1979 this.setXY(el, [x, false]);
1982 setY : function(el, y) {
1983 this.setXY(el, [false, y]);
1987 * Portions of this file are based on pieces of Yahoo User Interface Library
1988 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1989 * YUI licensed under the BSD License:
1990 * http://developer.yahoo.net/yui/license.txt
1991 * <script type="text/javascript">
1995 Roo.lib.Event = function() {
1996 var loadComplete = false;
1998 var unloadListeners = [];
2000 var onAvailStack = [];
2002 var lastError = null;
2015 startInterval: function() {
2016 if (!this._interval) {
2018 var callback = function() {
2019 self._tryPreloadAttach();
2021 this._interval = setInterval(callback, this.POLL_INTERVAL);
2026 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2027 onAvailStack.push({ id: p_id,
2030 override: p_override,
2031 checkReady: false });
2033 retryCount = this.POLL_RETRYS;
2034 this.startInterval();
2038 addListener: function(el, eventName, fn) {
2039 el = Roo.getDom(el);
2044 if ("unload" == eventName) {
2045 unloadListeners[unloadListeners.length] =
2046 [el, eventName, fn];
2050 var wrappedFn = function(e) {
2051 return fn(Roo.lib.Event.getEvent(e));
2054 var li = [el, eventName, fn, wrappedFn];
2056 var index = listeners.length;
2057 listeners[index] = li;
2059 this.doAdd(el, eventName, wrappedFn, false);
2065 removeListener: function(el, eventName, fn) {
2068 el = Roo.getDom(el);
2071 return this.purgeElement(el, false, eventName);
2075 if ("unload" == eventName) {
2077 for (i = 0,len = unloadListeners.length; i < len; i++) {
2078 var li = unloadListeners[i];
2081 li[1] == eventName &&
2083 unloadListeners.splice(i, 1);
2091 var cacheItem = null;
2094 var index = arguments[3];
2096 if ("undefined" == typeof index) {
2097 index = this._getCacheIndex(el, eventName, fn);
2101 cacheItem = listeners[index];
2104 if (!el || !cacheItem) {
2108 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2110 delete listeners[index][this.WFN];
2111 delete listeners[index][this.FN];
2112 listeners.splice(index, 1);
2119 getTarget: function(ev, resolveTextNode) {
2120 ev = ev.browserEvent || ev;
2121 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2122 var t = ev.target || ev.srcElement;
2123 return this.resolveTextNode(t);
2127 resolveTextNode: function(node) {
2128 if (Roo.isSafari && node && 3 == node.nodeType) {
2129 return node.parentNode;
2136 getPageX: function(ev) {
2137 ev = ev.browserEvent || ev;
2138 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2140 if (!x && 0 !== x) {
2141 x = ev.clientX || 0;
2144 x += this.getScroll()[1];
2152 getPageY: function(ev) {
2153 ev = ev.browserEvent || ev;
2154 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2156 if (!y && 0 !== y) {
2157 y = ev.clientY || 0;
2160 y += this.getScroll()[0];
2169 getXY: function(ev) {
2170 ev = ev.browserEvent || ev;
2171 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2172 return [this.getPageX(ev), this.getPageY(ev)];
2176 getRelatedTarget: function(ev) {
2177 ev = ev.browserEvent || ev;
2178 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2179 var t = ev.relatedTarget;
2181 if (ev.type == "mouseout") {
2183 } else if (ev.type == "mouseover") {
2188 return this.resolveTextNode(t);
2192 getTime: function(ev) {
2193 ev = ev.browserEvent || ev;
2194 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2196 var t = new Date().getTime();
2200 this.lastError = ex;
2209 stopEvent: function(ev) {
2210 this.stopPropagation(ev);
2211 this.preventDefault(ev);
2215 stopPropagation: function(ev) {
2216 ev = ev.browserEvent || ev;
2217 if (ev.stopPropagation) {
2218 ev.stopPropagation();
2220 ev.cancelBubble = true;
2225 preventDefault: function(ev) {
2226 ev = ev.browserEvent || ev;
2227 if(ev.preventDefault) {
2228 ev.preventDefault();
2230 ev.returnValue = false;
2235 getEvent: function(e) {
2236 var ev = e || window.event;
2238 var c = this.getEvent.caller;
2240 ev = c.arguments[0];
2241 if (ev && Event == ev.constructor) {
2251 getCharCode: function(ev) {
2252 ev = ev.browserEvent || ev;
2253 return ev.charCode || ev.keyCode || 0;
2257 _getCacheIndex: function(el, eventName, fn) {
2258 for (var i = 0,len = listeners.length; i < len; ++i) {
2259 var li = listeners[i];
2261 li[this.FN] == fn &&
2262 li[this.EL] == el &&
2263 li[this.TYPE] == eventName) {
2275 getEl: function(id) {
2276 return document.getElementById(id);
2280 clearCache: function() {
2284 _load: function(e) {
2285 loadComplete = true;
2286 var EU = Roo.lib.Event;
2290 EU.doRemove(window, "load", EU._load);
2295 _tryPreloadAttach: function() {
2304 var tryAgain = !loadComplete;
2306 tryAgain = (retryCount > 0);
2311 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2312 var item = onAvailStack[i];
2314 var el = this.getEl(item.id);
2317 if (!item.checkReady ||
2320 (document && document.body)) {
2323 if (item.override) {
2324 if (item.override === true) {
2327 scope = item.override;
2330 item.fn.call(scope, item.obj);
2331 onAvailStack[i] = null;
2334 notAvail.push(item);
2339 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2343 this.startInterval();
2345 clearInterval(this._interval);
2346 this._interval = null;
2349 this.locked = false;
2356 purgeElement: function(el, recurse, eventName) {
2357 var elListeners = this.getListeners(el, eventName);
2359 for (var i = 0,len = elListeners.length; i < len; ++i) {
2360 var l = elListeners[i];
2361 this.removeListener(el, l.type, l.fn);
2365 if (recurse && el && el.childNodes) {
2366 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2367 this.purgeElement(el.childNodes[i], recurse, eventName);
2373 getListeners: function(el, eventName) {
2374 var results = [], searchLists;
2376 searchLists = [listeners, unloadListeners];
2377 } else if (eventName == "unload") {
2378 searchLists = [unloadListeners];
2380 searchLists = [listeners];
2383 for (var j = 0; j < searchLists.length; ++j) {
2384 var searchList = searchLists[j];
2385 if (searchList && searchList.length > 0) {
2386 for (var i = 0,len = searchList.length; i < len; ++i) {
2387 var l = searchList[i];
2388 if (l && l[this.EL] === el &&
2389 (!eventName || eventName === l[this.TYPE])) {
2394 adjust: l[this.ADJ_SCOPE],
2402 return (results.length) ? results : null;
2406 _unload: function(e) {
2408 var EU = Roo.lib.Event, i, j, l, len, index;
2410 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2411 l = unloadListeners[i];
2414 if (l[EU.ADJ_SCOPE]) {
2415 if (l[EU.ADJ_SCOPE] === true) {
2418 scope = l[EU.ADJ_SCOPE];
2421 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2422 unloadListeners[i] = null;
2428 unloadListeners = null;
2430 if (listeners && listeners.length > 0) {
2431 j = listeners.length;
2434 l = listeners[index];
2436 EU.removeListener(l[EU.EL], l[EU.TYPE],
2446 EU.doRemove(window, "unload", EU._unload);
2451 getScroll: function() {
2452 var dd = document.documentElement, db = document.body;
2453 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2454 return [dd.scrollTop, dd.scrollLeft];
2456 return [db.scrollTop, db.scrollLeft];
2463 doAdd: function () {
2464 if (window.addEventListener) {
2465 return function(el, eventName, fn, capture) {
2466 el.addEventListener(eventName, fn, (capture));
2468 } else if (window.attachEvent) {
2469 return function(el, eventName, fn, capture) {
2470 el.attachEvent("on" + eventName, fn);
2479 doRemove: function() {
2480 if (window.removeEventListener) {
2481 return function (el, eventName, fn, capture) {
2482 el.removeEventListener(eventName, fn, (capture));
2484 } else if (window.detachEvent) {
2485 return function (el, eventName, fn) {
2486 el.detachEvent("on" + eventName, fn);
2498 var E = Roo.lib.Event;
2499 E.on = E.addListener;
2500 E.un = E.removeListener;
2502 if (document && document.body) {
2505 E.doAdd(window, "load", E._load);
2507 E.doAdd(window, "unload", E._unload);
2508 E._tryPreloadAttach();
2512 * Portions of this file are based on pieces of Yahoo User Interface Library
2513 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2514 * YUI licensed under the BSD License:
2515 * http://developer.yahoo.net/yui/license.txt
2516 * <script type="text/javascript">
2522 * @class Roo.lib.Ajax
2529 request : function(method, uri, cb, data, options) {
2531 var hs = options.headers;
2534 if(hs.hasOwnProperty(h)){
2535 this.initHeader(h, hs[h], false);
2539 if(options.xmlData){
2540 this.initHeader('Content-Type', 'text/xml', false);
2542 data = options.xmlData;
2546 return this.asyncRequest(method, uri, cb, data);
2549 serializeForm : function(form) {
2550 if(typeof form == 'string') {
2551 form = (document.getElementById(form) || document.forms[form]);
2554 var el, name, val, disabled, data = '', hasSubmit = false;
2555 for (var i = 0; i < form.elements.length; i++) {
2556 el = form.elements[i];
2557 disabled = form.elements[i].disabled;
2558 name = form.elements[i].name;
2559 val = form.elements[i].value;
2561 if (!disabled && name){
2565 case 'select-multiple':
2566 for (var j = 0; j < el.options.length; j++) {
2567 if (el.options[j].selected) {
2569 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2572 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2580 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2593 if(hasSubmit == false) {
2594 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2599 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2604 data = data.substr(0, data.length - 1);
2612 useDefaultHeader:true,
2614 defaultPostHeader:'application/x-www-form-urlencoded',
2616 useDefaultXhrHeader:true,
2618 defaultXhrHeader:'XMLHttpRequest',
2620 hasDefaultHeaders:true,
2632 setProgId:function(id)
2634 this.activeX.unshift(id);
2637 setDefaultPostHeader:function(b)
2639 this.useDefaultHeader = b;
2642 setDefaultXhrHeader:function(b)
2644 this.useDefaultXhrHeader = b;
2647 setPollingInterval:function(i)
2649 if (typeof i == 'number' && isFinite(i)) {
2650 this.pollInterval = i;
2654 createXhrObject:function(transactionId)
2660 http = new XMLHttpRequest();
2662 obj = { conn:http, tId:transactionId };
2666 for (var i = 0; i < this.activeX.length; ++i) {
2670 http = new ActiveXObject(this.activeX[i]);
2672 obj = { conn:http, tId:transactionId };
2685 getConnectionObject:function()
2688 var tId = this.transactionId;
2692 o = this.createXhrObject(tId);
2694 this.transactionId++;
2705 asyncRequest:function(method, uri, callback, postData)
2707 var o = this.getConnectionObject();
2713 o.conn.open(method, uri, true);
2715 if (this.useDefaultXhrHeader) {
2716 if (!this.defaultHeaders['X-Requested-With']) {
2717 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2721 if(postData && this.useDefaultHeader){
2722 this.initHeader('Content-Type', this.defaultPostHeader);
2725 if (this.hasDefaultHeaders || this.hasHeaders) {
2729 this.handleReadyState(o, callback);
2730 o.conn.send(postData || null);
2736 handleReadyState:function(o, callback)
2740 if (callback && callback.timeout) {
2742 this.timeout[o.tId] = window.setTimeout(function() {
2743 oConn.abort(o, callback, true);
2744 }, callback.timeout);
2747 this.poll[o.tId] = window.setInterval(
2749 if (o.conn && o.conn.readyState == 4) {
2750 window.clearInterval(oConn.poll[o.tId]);
2751 delete oConn.poll[o.tId];
2753 if(callback && callback.timeout) {
2754 window.clearTimeout(oConn.timeout[o.tId]);
2755 delete oConn.timeout[o.tId];
2758 oConn.handleTransactionResponse(o, callback);
2761 , this.pollInterval);
2764 handleTransactionResponse:function(o, callback, isAbort)
2768 this.releaseObject(o);
2772 var httpStatus, responseObject;
2776 if (o.conn.status !== undefined && o.conn.status != 0) {
2777 httpStatus = o.conn.status;
2789 if (httpStatus >= 200 && httpStatus < 300) {
2790 responseObject = this.createResponseObject(o, callback.argument);
2791 if (callback.success) {
2792 if (!callback.scope) {
2793 callback.success(responseObject);
2798 callback.success.apply(callback.scope, [responseObject]);
2803 switch (httpStatus) {
2811 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2812 if (callback.failure) {
2813 if (!callback.scope) {
2814 callback.failure(responseObject);
2817 callback.failure.apply(callback.scope, [responseObject]);
2822 responseObject = this.createResponseObject(o, callback.argument);
2823 if (callback.failure) {
2824 if (!callback.scope) {
2825 callback.failure(responseObject);
2828 callback.failure.apply(callback.scope, [responseObject]);
2834 this.releaseObject(o);
2835 responseObject = null;
2838 createResponseObject:function(o, callbackArg)
2845 var headerStr = o.conn.getAllResponseHeaders();
2846 var header = headerStr.split('\n');
2847 for (var i = 0; i < header.length; i++) {
2848 var delimitPos = header[i].indexOf(':');
2849 if (delimitPos != -1) {
2850 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2858 obj.status = o.conn.status;
2859 obj.statusText = o.conn.statusText;
2860 obj.getResponseHeader = headerObj;
2861 obj.getAllResponseHeaders = headerStr;
2862 obj.responseText = o.conn.responseText;
2863 obj.responseXML = o.conn.responseXML;
2865 if (typeof callbackArg !== undefined) {
2866 obj.argument = callbackArg;
2872 createExceptionObject:function(tId, callbackArg, isAbort)
2875 var COMM_ERROR = 'communication failure';
2876 var ABORT_CODE = -1;
2877 var ABORT_ERROR = 'transaction aborted';
2883 obj.status = ABORT_CODE;
2884 obj.statusText = ABORT_ERROR;
2887 obj.status = COMM_CODE;
2888 obj.statusText = COMM_ERROR;
2892 obj.argument = callbackArg;
2898 initHeader:function(label, value, isDefault)
2900 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2902 if (headerObj[label] === undefined) {
2903 headerObj[label] = value;
2908 headerObj[label] = value + "," + headerObj[label];
2912 this.hasDefaultHeaders = true;
2915 this.hasHeaders = true;
2920 setHeader:function(o)
2922 if (this.hasDefaultHeaders) {
2923 for (var prop in this.defaultHeaders) {
2924 if (this.defaultHeaders.hasOwnProperty(prop)) {
2925 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2930 if (this.hasHeaders) {
2931 for (var prop in this.headers) {
2932 if (this.headers.hasOwnProperty(prop)) {
2933 o.conn.setRequestHeader(prop, this.headers[prop]);
2937 this.hasHeaders = false;
2941 resetDefaultHeaders:function() {
2942 delete this.defaultHeaders;
2943 this.defaultHeaders = {};
2944 this.hasDefaultHeaders = false;
2947 abort:function(o, callback, isTimeout)
2949 if(this.isCallInProgress(o)) {
2951 window.clearInterval(this.poll[o.tId]);
2952 delete this.poll[o.tId];
2954 delete this.timeout[o.tId];
2957 this.handleTransactionResponse(o, callback, true);
2967 isCallInProgress:function(o)
2970 return o.conn.readyState != 4 && o.conn.readyState != 0;
2979 releaseObject:function(o)
2988 'MSXML2.XMLHTTP.3.0',
2996 * Portions of this file are based on pieces of Yahoo User Interface Library
2997 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2998 * YUI licensed under the BSD License:
2999 * http://developer.yahoo.net/yui/license.txt
3000 * <script type="text/javascript">
3004 Roo.lib.Region = function(t, r, b, l) {
3014 Roo.lib.Region.prototype = {
3015 contains : function(region) {
3016 return ( region.left >= this.left &&
3017 region.right <= this.right &&
3018 region.top >= this.top &&
3019 region.bottom <= this.bottom );
3023 getArea : function() {
3024 return ( (this.bottom - this.top) * (this.right - this.left) );
3027 intersect : function(region) {
3028 var t = Math.max(this.top, region.top);
3029 var r = Math.min(this.right, region.right);
3030 var b = Math.min(this.bottom, region.bottom);
3031 var l = Math.max(this.left, region.left);
3033 if (b >= t && r >= l) {
3034 return new Roo.lib.Region(t, r, b, l);
3039 union : function(region) {
3040 var t = Math.min(this.top, region.top);
3041 var r = Math.max(this.right, region.right);
3042 var b = Math.max(this.bottom, region.bottom);
3043 var l = Math.min(this.left, region.left);
3045 return new Roo.lib.Region(t, r, b, l);
3048 adjust : function(t, l, b, r) {
3057 Roo.lib.Region.getRegion = function(el) {
3058 var p = Roo.lib.Dom.getXY(el);
3061 var r = p[0] + el.offsetWidth;
3062 var b = p[1] + el.offsetHeight;
3065 return new Roo.lib.Region(t, r, b, l);
3068 * Portions of this file are based on pieces of Yahoo User Interface Library
3069 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3070 * YUI licensed under the BSD License:
3071 * http://developer.yahoo.net/yui/license.txt
3072 * <script type="text/javascript">
3075 //@@dep Roo.lib.Region
3078 Roo.lib.Point = function(x, y) {
3079 if (x instanceof Array) {
3083 this.x = this.right = this.left = this[0] = x;
3084 this.y = this.top = this.bottom = this[1] = y;
3087 Roo.lib.Point.prototype = new Roo.lib.Region();
3089 * Portions of this file are based on pieces of Yahoo User Interface Library
3090 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3091 * YUI licensed under the BSD License:
3092 * http://developer.yahoo.net/yui/license.txt
3093 * <script type="text/javascript">
3100 scroll : function(el, args, duration, easing, cb, scope) {
3101 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3104 motion : function(el, args, duration, easing, cb, scope) {
3105 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3108 color : function(el, args, duration, easing, cb, scope) {
3109 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3112 run : function(el, args, duration, easing, cb, scope, type) {
3113 type = type || Roo.lib.AnimBase;
3114 if (typeof easing == "string") {
3115 easing = Roo.lib.Easing[easing];
3117 var anim = new type(el, args, duration, easing);
3118 anim.animateX(function() {
3119 Roo.callback(cb, scope);
3125 * Portions of this file are based on pieces of Yahoo User Interface Library
3126 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3127 * YUI licensed under the BSD License:
3128 * http://developer.yahoo.net/yui/license.txt
3129 * <script type="text/javascript">
3137 if (!libFlyweight) {
3138 libFlyweight = new Roo.Element.Flyweight();
3140 libFlyweight.dom = el;
3141 return libFlyweight;
3144 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3148 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3150 this.init(el, attributes, duration, method);
3154 Roo.lib.AnimBase.fly = fly;
3158 Roo.lib.AnimBase.prototype = {
3160 toString: function() {
3161 var el = this.getEl();
3162 var id = el.id || el.tagName;
3163 return ("Anim " + id);
3167 noNegatives: /width|height|opacity|padding/i,
3168 offsetAttribute: /^((width|height)|(top|left))$/,
3169 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3170 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3174 doMethod: function(attr, start, end) {
3175 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3179 setAttribute: function(attr, val, unit) {
3180 if (this.patterns.noNegatives.test(attr)) {
3181 val = (val > 0) ? val : 0;
3184 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3188 getAttribute: function(attr) {
3189 var el = this.getEl();
3190 var val = fly(el).getStyle(attr);
3192 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3193 return parseFloat(val);
3196 var a = this.patterns.offsetAttribute.exec(attr) || [];
3197 var pos = !!( a[3] );
3198 var box = !!( a[2] );
3201 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3202 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3211 getDefaultUnit: function(attr) {
3212 if (this.patterns.defaultUnit.test(attr)) {
3219 animateX : function(callback, scope) {
3220 var f = function() {
3221 this.onComplete.removeListener(f);
3222 if (typeof callback == "function") {
3223 callback.call(scope || this, this);
3226 this.onComplete.addListener(f, this);
3231 setRuntimeAttribute: function(attr) {
3234 var attributes = this.attributes;
3236 this.runtimeAttributes[attr] = {};
3238 var isset = function(prop) {
3239 return (typeof prop !== 'undefined');
3242 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3246 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3249 if (isset(attributes[attr]['to'])) {
3250 end = attributes[attr]['to'];
3251 } else if (isset(attributes[attr]['by'])) {
3252 if (start.constructor == Array) {
3254 for (var i = 0, len = start.length; i < len; ++i) {
3255 end[i] = start[i] + attributes[attr]['by'][i];
3258 end = start + attributes[attr]['by'];
3262 this.runtimeAttributes[attr].start = start;
3263 this.runtimeAttributes[attr].end = end;
3266 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3270 init: function(el, attributes, duration, method) {
3272 var isAnimated = false;
3275 var startTime = null;
3278 var actualFrames = 0;
3281 el = Roo.getDom(el);
3284 this.attributes = attributes || {};
3287 this.duration = duration || 1;
3290 this.method = method || Roo.lib.Easing.easeNone;
3293 this.useSeconds = true;
3296 this.currentFrame = 0;
3299 this.totalFrames = Roo.lib.AnimMgr.fps;
3302 this.getEl = function() {
3307 this.isAnimated = function() {
3312 this.getStartTime = function() {
3316 this.runtimeAttributes = {};
3319 this.animate = function() {
3320 if (this.isAnimated()) {
3324 this.currentFrame = 0;
3326 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3328 Roo.lib.AnimMgr.registerElement(this);
3332 this.stop = function(finish) {
3334 this.currentFrame = this.totalFrames;
3335 this._onTween.fire();
3337 Roo.lib.AnimMgr.stop(this);
3340 var onStart = function() {
3341 this.onStart.fire();
3343 this.runtimeAttributes = {};
3344 for (var attr in this.attributes) {
3345 this.setRuntimeAttribute(attr);
3350 startTime = new Date();
3354 var onTween = function() {
3356 duration: new Date() - this.getStartTime(),
3357 currentFrame: this.currentFrame
3360 data.toString = function() {
3362 'duration: ' + data.duration +
3363 ', currentFrame: ' + data.currentFrame
3367 this.onTween.fire(data);
3369 var runtimeAttributes = this.runtimeAttributes;
3371 for (var attr in runtimeAttributes) {
3372 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3378 var onComplete = function() {
3379 var actual_duration = (new Date() - startTime) / 1000 ;
3382 duration: actual_duration,
3383 frames: actualFrames,
3384 fps: actualFrames / actual_duration
3387 data.toString = function() {
3389 'duration: ' + data.duration +
3390 ', frames: ' + data.frames +
3391 ', fps: ' + data.fps
3397 this.onComplete.fire(data);
3401 this._onStart = new Roo.util.Event(this);
3402 this.onStart = new Roo.util.Event(this);
3403 this.onTween = new Roo.util.Event(this);
3404 this._onTween = new Roo.util.Event(this);
3405 this.onComplete = new Roo.util.Event(this);
3406 this._onComplete = new Roo.util.Event(this);
3407 this._onStart.addListener(onStart);
3408 this._onTween.addListener(onTween);
3409 this._onComplete.addListener(onComplete);
3414 * Portions of this file are based on pieces of Yahoo User Interface Library
3415 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3416 * YUI licensed under the BSD License:
3417 * http://developer.yahoo.net/yui/license.txt
3418 * <script type="text/javascript">
3422 Roo.lib.AnimMgr = new function() {
3439 this.registerElement = function(tween) {
3440 queue[queue.length] = tween;
3442 tween._onStart.fire();
3447 this.unRegister = function(tween, index) {
3448 tween._onComplete.fire();
3449 index = index || getIndex(tween);
3451 queue.splice(index, 1);
3455 if (tweenCount <= 0) {
3461 this.start = function() {
3462 if (thread === null) {
3463 thread = setInterval(this.run, this.delay);
3468 this.stop = function(tween) {
3470 clearInterval(thread);
3472 for (var i = 0, len = queue.length; i < len; ++i) {
3473 if (queue[0].isAnimated()) {
3474 this.unRegister(queue[0], 0);
3483 this.unRegister(tween);
3488 this.run = function() {
3489 for (var i = 0, len = queue.length; i < len; ++i) {
3490 var tween = queue[i];
3491 if (!tween || !tween.isAnimated()) {
3495 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3497 tween.currentFrame += 1;
3499 if (tween.useSeconds) {
3500 correctFrame(tween);
3502 tween._onTween.fire();
3505 Roo.lib.AnimMgr.stop(tween, i);
3510 var getIndex = function(anim) {
3511 for (var i = 0, len = queue.length; i < len; ++i) {
3512 if (queue[i] == anim) {
3520 var correctFrame = function(tween) {
3521 var frames = tween.totalFrames;
3522 var frame = tween.currentFrame;
3523 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3524 var elapsed = (new Date() - tween.getStartTime());
3527 if (elapsed < tween.duration * 1000) {
3528 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3530 tweak = frames - (frame + 1);
3532 if (tweak > 0 && isFinite(tweak)) {
3533 if (tween.currentFrame + tweak >= frames) {
3534 tweak = frames - (frame + 1);
3537 tween.currentFrame += tweak;
3543 * Portions of this file are based on pieces of Yahoo User Interface Library
3544 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545 * YUI licensed under the BSD License:
3546 * http://developer.yahoo.net/yui/license.txt
3547 * <script type="text/javascript">
3550 Roo.lib.Bezier = new function() {
3552 this.getPosition = function(points, t) {
3553 var n = points.length;
3556 for (var i = 0; i < n; ++i) {
3557 tmp[i] = [points[i][0], points[i][1]];
3560 for (var j = 1; j < n; ++j) {
3561 for (i = 0; i < n - j; ++i) {
3562 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3563 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3567 return [ tmp[0][0], tmp[0][1] ];
3571 * Portions of this file are based on pieces of Yahoo User Interface Library
3572 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3573 * YUI licensed under the BSD License:
3574 * http://developer.yahoo.net/yui/license.txt
3575 * <script type="text/javascript">
3580 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3581 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3584 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3586 var fly = Roo.lib.AnimBase.fly;
3588 var superclass = Y.ColorAnim.superclass;
3589 var proto = Y.ColorAnim.prototype;
3591 proto.toString = function() {
3592 var el = this.getEl();
3593 var id = el.id || el.tagName;
3594 return ("ColorAnim " + id);
3597 proto.patterns.color = /color$/i;
3598 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3599 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3600 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3601 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3604 proto.parseColor = function(s) {
3605 if (s.length == 3) {
3609 var c = this.patterns.hex.exec(s);
3610 if (c && c.length == 4) {
3611 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3614 c = this.patterns.rgb.exec(s);
3615 if (c && c.length == 4) {
3616 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3619 c = this.patterns.hex3.exec(s);
3620 if (c && c.length == 4) {
3621 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3626 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3627 proto.getAttribute = function(attr) {
3628 var el = this.getEl();
3629 if (this.patterns.color.test(attr)) {
3630 var val = fly(el).getStyle(attr);
3632 if (this.patterns.transparent.test(val)) {
3633 var parent = el.parentNode;
3634 val = fly(parent).getStyle(attr);
3636 while (parent && this.patterns.transparent.test(val)) {
3637 parent = parent.parentNode;
3638 val = fly(parent).getStyle(attr);
3639 if (parent.tagName.toUpperCase() == 'HTML') {
3645 val = superclass.getAttribute.call(this, attr);
3650 proto.getAttribute = function(attr) {
3651 var el = this.getEl();
3652 if (this.patterns.color.test(attr)) {
3653 var val = fly(el).getStyle(attr);
3655 if (this.patterns.transparent.test(val)) {
3656 var parent = el.parentNode;
3657 val = fly(parent).getStyle(attr);
3659 while (parent && this.patterns.transparent.test(val)) {
3660 parent = parent.parentNode;
3661 val = fly(parent).getStyle(attr);
3662 if (parent.tagName.toUpperCase() == 'HTML') {
3668 val = superclass.getAttribute.call(this, attr);
3674 proto.doMethod = function(attr, start, end) {
3677 if (this.patterns.color.test(attr)) {
3679 for (var i = 0, len = start.length; i < len; ++i) {
3680 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3683 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3686 val = superclass.doMethod.call(this, attr, start, end);
3692 proto.setRuntimeAttribute = function(attr) {
3693 superclass.setRuntimeAttribute.call(this, attr);
3695 if (this.patterns.color.test(attr)) {
3696 var attributes = this.attributes;
3697 var start = this.parseColor(this.runtimeAttributes[attr].start);
3698 var end = this.parseColor(this.runtimeAttributes[attr].end);
3700 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3701 end = this.parseColor(attributes[attr].by);
3703 for (var i = 0, len = start.length; i < len; ++i) {
3704 end[i] = start[i] + end[i];
3708 this.runtimeAttributes[attr].start = start;
3709 this.runtimeAttributes[attr].end = end;
3715 * Portions of this file are based on pieces of Yahoo User Interface Library
3716 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3717 * YUI licensed under the BSD License:
3718 * http://developer.yahoo.net/yui/license.txt
3719 * <script type="text/javascript">
3725 easeNone: function (t, b, c, d) {
3726 return c * t / d + b;
3730 easeIn: function (t, b, c, d) {
3731 return c * (t /= d) * t + b;
3735 easeOut: function (t, b, c, d) {
3736 return -c * (t /= d) * (t - 2) + b;
3740 easeBoth: function (t, b, c, d) {
3741 if ((t /= d / 2) < 1) {
3742 return c / 2 * t * t + b;
3745 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3749 easeInStrong: function (t, b, c, d) {
3750 return c * (t /= d) * t * t * t + b;
3754 easeOutStrong: function (t, b, c, d) {
3755 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3759 easeBothStrong: function (t, b, c, d) {
3760 if ((t /= d / 2) < 1) {
3761 return c / 2 * t * t * t * t + b;
3764 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3769 elasticIn: function (t, b, c, d, a, p) {
3773 if ((t /= d) == 1) {
3780 if (!a || a < Math.abs(c)) {
3785 var s = p / (2 * Math.PI) * Math.asin(c / a);
3788 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3792 elasticOut: function (t, b, c, d, a, p) {
3796 if ((t /= d) == 1) {
3803 if (!a || a < Math.abs(c)) {
3808 var s = p / (2 * Math.PI) * Math.asin(c / a);
3811 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3815 elasticBoth: function (t, b, c, d, a, p) {
3820 if ((t /= d / 2) == 2) {
3828 if (!a || a < Math.abs(c)) {
3833 var s = p / (2 * Math.PI) * Math.asin(c / a);
3837 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3838 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3840 return a * Math.pow(2, -10 * (t -= 1)) *
3841 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3846 backIn: function (t, b, c, d, s) {
3847 if (typeof s == 'undefined') {
3850 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3854 backOut: function (t, b, c, d, s) {
3855 if (typeof s == 'undefined') {
3858 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3862 backBoth: function (t, b, c, d, s) {
3863 if (typeof s == 'undefined') {
3867 if ((t /= d / 2 ) < 1) {
3868 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3870 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3874 bounceIn: function (t, b, c, d) {
3875 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3879 bounceOut: function (t, b, c, d) {
3880 if ((t /= d) < (1 / 2.75)) {
3881 return c * (7.5625 * t * t) + b;
3882 } else if (t < (2 / 2.75)) {
3883 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3884 } else if (t < (2.5 / 2.75)) {
3885 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3887 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3891 bounceBoth: function (t, b, c, d) {
3893 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3895 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3898 * Portions of this file are based on pieces of Yahoo User Interface Library
3899 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3900 * YUI licensed under the BSD License:
3901 * http://developer.yahoo.net/yui/license.txt
3902 * <script type="text/javascript">
3906 Roo.lib.Motion = function(el, attributes, duration, method) {
3908 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3912 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3916 var superclass = Y.Motion.superclass;
3917 var proto = Y.Motion.prototype;
3919 proto.toString = function() {
3920 var el = this.getEl();
3921 var id = el.id || el.tagName;
3922 return ("Motion " + id);
3925 proto.patterns.points = /^points$/i;
3927 proto.setAttribute = function(attr, val, unit) {
3928 if (this.patterns.points.test(attr)) {
3929 unit = unit || 'px';
3930 superclass.setAttribute.call(this, 'left', val[0], unit);
3931 superclass.setAttribute.call(this, 'top', val[1], unit);
3933 superclass.setAttribute.call(this, attr, val, unit);
3937 proto.getAttribute = function(attr) {
3938 if (this.patterns.points.test(attr)) {
3940 superclass.getAttribute.call(this, 'left'),
3941 superclass.getAttribute.call(this, 'top')
3944 val = superclass.getAttribute.call(this, attr);
3950 proto.doMethod = function(attr, start, end) {
3953 if (this.patterns.points.test(attr)) {
3954 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3955 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3957 val = superclass.doMethod.call(this, attr, start, end);
3962 proto.setRuntimeAttribute = function(attr) {
3963 if (this.patterns.points.test(attr)) {
3964 var el = this.getEl();
3965 var attributes = this.attributes;
3967 var control = attributes['points']['control'] || [];
3971 if (control.length > 0 && !(control[0] instanceof Array)) {
3972 control = [control];
3975 for (i = 0,len = control.length; i < len; ++i) {
3976 tmp[i] = control[i];
3981 Roo.fly(el).position();
3983 if (isset(attributes['points']['from'])) {
3984 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3987 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3990 start = this.getAttribute('points');
3993 if (isset(attributes['points']['to'])) {
3994 end = translateValues.call(this, attributes['points']['to'], start);
3996 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3997 for (i = 0,len = control.length; i < len; ++i) {
3998 control[i] = translateValues.call(this, control[i], start);
4002 } else if (isset(attributes['points']['by'])) {
4003 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4005 for (i = 0,len = control.length; i < len; ++i) {
4006 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4010 this.runtimeAttributes[attr] = [start];
4012 if (control.length > 0) {
4013 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4016 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4019 superclass.setRuntimeAttribute.call(this, attr);
4023 var translateValues = function(val, start) {
4024 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4025 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4030 var isset = function(prop) {
4031 return (typeof prop !== 'undefined');
4035 * Portions of this file are based on pieces of Yahoo User Interface Library
4036 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4037 * YUI licensed under the BSD License:
4038 * http://developer.yahoo.net/yui/license.txt
4039 * <script type="text/javascript">
4043 Roo.lib.Scroll = function(el, attributes, duration, method) {
4045 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4049 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4053 var superclass = Y.Scroll.superclass;
4054 var proto = Y.Scroll.prototype;
4056 proto.toString = function() {
4057 var el = this.getEl();
4058 var id = el.id || el.tagName;
4059 return ("Scroll " + id);
4062 proto.doMethod = function(attr, start, end) {
4065 if (attr == 'scroll') {
4067 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4068 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4072 val = superclass.doMethod.call(this, attr, start, end);
4077 proto.getAttribute = function(attr) {
4079 var el = this.getEl();
4081 if (attr == 'scroll') {
4082 val = [ el.scrollLeft, el.scrollTop ];
4084 val = superclass.getAttribute.call(this, attr);
4090 proto.setAttribute = function(attr, val, unit) {
4091 var el = this.getEl();
4093 if (attr == 'scroll') {
4094 el.scrollLeft = val[0];
4095 el.scrollTop = val[1];
4097 superclass.setAttribute.call(this, attr, val, unit);
4103 * Ext JS Library 1.1.1
4104 * Copyright(c) 2006-2007, Ext JS, LLC.
4106 * Originally Released Under LGPL - original licence link has changed is not relivant.
4109 * <script type="text/javascript">
4113 // nasty IE9 hack - what a pile of crap that is..
4115 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4116 Range.prototype.createContextualFragment = function (html) {
4117 var doc = window.document;
4118 var container = doc.createElement("div");
4119 container.innerHTML = html;
4120 var frag = doc.createDocumentFragment(), n;
4121 while ((n = container.firstChild)) {
4122 frag.appendChild(n);
4129 * @class Roo.DomHelper
4130 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4131 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4134 Roo.DomHelper = function(){
4135 var tempTableEl = null;
4136 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4137 var tableRe = /^table|tbody|tr|td$/i;
4139 // build as innerHTML where available
4141 var createHtml = function(o){
4142 if(typeof o == 'string'){
4151 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4152 if(attr == "style"){
4154 if(typeof s == "function"){
4157 if(typeof s == "string"){
4158 b += ' style="' + s + '"';
4159 }else if(typeof s == "object"){
4162 if(typeof s[key] != "function"){
4163 b += key + ":" + s[key] + ";";
4170 b += ' class="' + o["cls"] + '"';
4171 }else if(attr == "htmlFor"){
4172 b += ' for="' + o["htmlFor"] + '"';
4174 b += " " + attr + '="' + o[attr] + '"';
4178 if(emptyTags.test(o.tag)){
4182 var cn = o.children || o.cn;
4184 //http://bugs.kde.org/show_bug.cgi?id=71506
4185 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4186 for(var i = 0, len = cn.length; i < len; i++) {
4187 b += createHtml(cn[i], b);
4190 b += createHtml(cn, b);
4196 b += "</" + o.tag + ">";
4203 var createDom = function(o, parentNode){
4205 // defininition craeted..
4207 if (o.ns && o.ns != 'html') {
4209 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4210 xmlns[o.ns] = o.xmlns;
4213 if (typeof(xmlns[o.ns]) == 'undefined') {
4214 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4220 if (typeof(o) == 'string') {
4221 return parentNode.appendChild(document.createTextNode(o));
4223 o.tag = o.tag || div;
4224 if (o.ns && Roo.isIE) {
4226 o.tag = o.ns + ':' + o.tag;
4229 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4230 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4233 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4234 attr == "style" || typeof o[attr] == "function") continue;
4236 if(attr=="cls" && Roo.isIE){
4237 el.className = o["cls"];
4239 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4240 else el[attr] = o[attr];
4243 Roo.DomHelper.applyStyles(el, o.style);
4244 var cn = o.children || o.cn;
4246 //http://bugs.kde.org/show_bug.cgi?id=71506
4247 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4248 for(var i = 0, len = cn.length; i < len; i++) {
4249 createDom(cn[i], el);
4256 el.innerHTML = o.html;
4259 parentNode.appendChild(el);
4264 var ieTable = function(depth, s, h, e){
4265 tempTableEl.innerHTML = [s, h, e].join('');
4266 var i = -1, el = tempTableEl;
4273 // kill repeat to save bytes
4277 tbe = '</tbody>'+te,
4283 * Nasty code for IE's broken table implementation
4285 var insertIntoTable = function(tag, where, el, html){
4287 tempTableEl = document.createElement('div');
4292 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4295 if(where == 'beforebegin'){
4299 before = el.nextSibling;
4302 node = ieTable(4, trs, html, tre);
4304 else if(tag == 'tr'){
4305 if(where == 'beforebegin'){
4308 node = ieTable(3, tbs, html, tbe);
4309 } else if(where == 'afterend'){
4310 before = el.nextSibling;
4312 node = ieTable(3, tbs, html, tbe);
4313 } else{ // INTO a TR
4314 if(where == 'afterbegin'){
4315 before = el.firstChild;
4317 node = ieTable(4, trs, html, tre);
4319 } else if(tag == 'tbody'){
4320 if(where == 'beforebegin'){
4323 node = ieTable(2, ts, html, te);
4324 } else if(where == 'afterend'){
4325 before = el.nextSibling;
4327 node = ieTable(2, ts, html, te);
4329 if(where == 'afterbegin'){
4330 before = el.firstChild;
4332 node = ieTable(3, tbs, html, tbe);
4335 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4338 if(where == 'afterbegin'){
4339 before = el.firstChild;
4341 node = ieTable(2, ts, html, te);
4343 el.insertBefore(node, before);
4348 /** True to force the use of DOM instead of html fragments @type Boolean */
4352 * Returns the markup for the passed Element(s) config
4353 * @param {Object} o The Dom object spec (and children)
4356 markup : function(o){
4357 return createHtml(o);
4361 * Applies a style specification to an element
4362 * @param {String/HTMLElement} el The element to apply styles to
4363 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4364 * a function which returns such a specification.
4366 applyStyles : function(el, styles){
4369 if(typeof styles == "string"){
4370 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4372 while ((matches = re.exec(styles)) != null){
4373 el.setStyle(matches[1], matches[2]);
4375 }else if (typeof styles == "object"){
4376 for (var style in styles){
4377 el.setStyle(style, styles[style]);
4379 }else if (typeof styles == "function"){
4380 Roo.DomHelper.applyStyles(el, styles.call());
4386 * Inserts an HTML fragment into the Dom
4387 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4388 * @param {HTMLElement} el The context element
4389 * @param {String} html The HTML fragmenet
4390 * @return {HTMLElement} The new node
4392 insertHtml : function(where, el, html){
4393 where = where.toLowerCase();
4394 if(el.insertAdjacentHTML){
4395 if(tableRe.test(el.tagName)){
4397 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4403 el.insertAdjacentHTML('BeforeBegin', html);
4404 return el.previousSibling;
4406 el.insertAdjacentHTML('AfterBegin', html);
4407 return el.firstChild;
4409 el.insertAdjacentHTML('BeforeEnd', html);
4410 return el.lastChild;
4412 el.insertAdjacentHTML('AfterEnd', html);
4413 return el.nextSibling;
4415 throw 'Illegal insertion point -> "' + where + '"';
4417 var range = el.ownerDocument.createRange();
4421 range.setStartBefore(el);
4422 frag = range.createContextualFragment(html);
4423 el.parentNode.insertBefore(frag, el);
4424 return el.previousSibling;
4427 range.setStartBefore(el.firstChild);
4428 frag = range.createContextualFragment(html);
4429 el.insertBefore(frag, el.firstChild);
4430 return el.firstChild;
4432 el.innerHTML = html;
4433 return el.firstChild;
4437 range.setStartAfter(el.lastChild);
4438 frag = range.createContextualFragment(html);
4439 el.appendChild(frag);
4440 return el.lastChild;
4442 el.innerHTML = html;
4443 return el.lastChild;
4446 range.setStartAfter(el);
4447 frag = range.createContextualFragment(html);
4448 el.parentNode.insertBefore(frag, el.nextSibling);
4449 return el.nextSibling;
4451 throw 'Illegal insertion point -> "' + where + '"';
4455 * Creates new Dom element(s) and inserts them before el
4456 * @param {String/HTMLElement/Element} el The context element
4457 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4458 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4459 * @return {HTMLElement/Roo.Element} The new node
4461 insertBefore : function(el, o, returnElement){
4462 return this.doInsert(el, o, returnElement, "beforeBegin");
4466 * Creates new Dom element(s) and inserts them after el
4467 * @param {String/HTMLElement/Element} el The context element
4468 * @param {Object} o The Dom object spec (and children)
4469 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4470 * @return {HTMLElement/Roo.Element} The new node
4472 insertAfter : function(el, o, returnElement){
4473 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4477 * Creates new Dom element(s) and inserts them as the first child of el
4478 * @param {String/HTMLElement/Element} el The context element
4479 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4480 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4481 * @return {HTMLElement/Roo.Element} The new node
4483 insertFirst : function(el, o, returnElement){
4484 return this.doInsert(el, o, returnElement, "afterBegin");
4488 doInsert : function(el, o, returnElement, pos, sibling){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml(pos, el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and appends them to el
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 append : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4511 if(this.useDom || o.ns){
4512 newNode = createDom(o, null);
4513 el.appendChild(newNode);
4515 var html = createHtml(o);
4516 newNode = this.insertHtml("beforeEnd", el, html);
4518 return returnElement ? Roo.get(newNode, true) : newNode;
4522 * Creates new Dom element(s) and overwrites the contents of el with them
4523 * @param {String/HTMLElement/Element} el The context element
4524 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4525 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4526 * @return {HTMLElement/Roo.Element} The new node
4528 overwrite : function(el, o, returnElement){
4529 el = Roo.getDom(el);
4532 while (el.childNodes.length) {
4533 el.removeChild(el.firstChild);
4537 el.innerHTML = createHtml(o);
4540 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4544 * Creates a new Roo.DomHelper.Template from the Dom object spec
4545 * @param {Object} o The Dom object spec (and children)
4546 * @return {Roo.DomHelper.Template} The new template
4548 createTemplate : function(o){
4549 var html = createHtml(o);
4550 return new Roo.Template(html);
4556 * Ext JS Library 1.1.1
4557 * Copyright(c) 2006-2007, Ext JS, LLC.
4559 * Originally Released Under LGPL - original licence link has changed is not relivant.
4562 * <script type="text/javascript">
4566 * @class Roo.Template
4567 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4568 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4571 var t = new Roo.Template({
4572 html : '<div name="{id}">' +
4573 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4575 myformat: function (value, allValues) {
4576 return 'XX' + value;
4579 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4581 * For more information see this blog post with examples:
4582 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4583 - Create Elements using DOM, HTML fragments and Templates</a>.
4585 * @param {Object} cfg - Configuration object.
4587 Roo.Template = function(cfg){
4589 if(cfg instanceof Array){
4591 }else if(arguments.length > 1){
4592 cfg = Array.prototype.join.call(arguments, "");
4596 if (typeof(cfg) == 'object') {
4607 Roo.Template.prototype = {
4610 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4611 * it should be fixed so that template is observable...
4615 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4619 * Returns an HTML fragment of this template with the specified values applied.
4620 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4621 * @return {String} The HTML fragment
4623 applyTemplate : function(values){
4627 return this.compiled(values);
4629 var useF = this.disableFormats !== true;
4630 var fm = Roo.util.Format, tpl = this;
4631 var fn = function(m, name, format, args){
4633 if(format.substr(0, 5) == "this."){
4634 return tpl.call(format.substr(5), values[name], values);
4637 // quoted values are required for strings in compiled templates,
4638 // but for non compiled we need to strip them
4639 // quoted reversed for jsmin
4640 var re = /^\s*['"](.*)["']\s*$/;
4641 args = args.split(',');
4642 for(var i = 0, len = args.length; i < len; i++){
4643 args[i] = args[i].replace(re, "$1");
4645 args = [values[name]].concat(args);
4647 args = [values[name]];
4649 return fm[format].apply(fm, args);
4652 return values[name] !== undefined ? values[name] : "";
4655 return this.html.replace(this.re, fn);
4673 this.loading = true;
4674 this.compiled = false;
4676 var cx = new Roo.data.Connection();
4680 success : function (response) {
4682 _t.html = response.responseText;
4686 failure : function(response) {
4687 Roo.log("Template failed to load from " + _t.url);
4694 * Sets the HTML used as the template and optionally compiles it.
4695 * @param {String} html
4696 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4697 * @return {Roo.Template} this
4699 set : function(html, compile){
4701 this.compiled = null;
4709 * True to disable format functions (defaults to false)
4712 disableFormats : false,
4715 * The regular expression used to match template variables
4719 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4722 * Compiles the template into an internal function, eliminating the RegEx overhead.
4723 * @return {Roo.Template} this
4725 compile : function(){
4726 var fm = Roo.util.Format;
4727 var useF = this.disableFormats !== true;
4728 var sep = Roo.isGecko ? "+" : ",";
4729 var fn = function(m, name, format, args){
4731 args = args ? ',' + args : "";
4732 if(format.substr(0, 5) != "this."){
4733 format = "fm." + format + '(';
4735 format = 'this.call("'+ format.substr(5) + '", ';
4739 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4741 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4744 // branched to use + in gecko and [].join() in others
4746 body = "this.compiled = function(values){ return '" +
4747 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4750 body = ["this.compiled = function(values){ return ['"];
4751 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4752 body.push("'].join('');};");
4753 body = body.join('');
4763 // private function used to call members
4764 call : function(fnName, value, allValues){
4765 return this[fnName](value, allValues);
4769 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4770 * @param {String/HTMLElement/Roo.Element} el The context element
4771 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4772 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4773 * @return {HTMLElement/Roo.Element} The new node or Element
4775 insertFirst: function(el, values, returnElement){
4776 return this.doInsert('afterBegin', el, values, returnElement);
4780 * Applies the supplied values to the template and inserts the new node(s) before el.
4781 * @param {String/HTMLElement/Roo.Element} el The context element
4782 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4783 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4784 * @return {HTMLElement/Roo.Element} The new node or Element
4786 insertBefore: function(el, values, returnElement){
4787 return this.doInsert('beforeBegin', el, values, returnElement);
4791 * Applies the supplied values to the template and inserts the new node(s) after el.
4792 * @param {String/HTMLElement/Roo.Element} el The context element
4793 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4794 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4795 * @return {HTMLElement/Roo.Element} The new node or Element
4797 insertAfter : function(el, values, returnElement){
4798 return this.doInsert('afterEnd', el, values, returnElement);
4802 * Applies the supplied values to the template and appends the new node(s) to el.
4803 * @param {String/HTMLElement/Roo.Element} el The context element
4804 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4805 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4806 * @return {HTMLElement/Roo.Element} The new node or Element
4808 append : function(el, values, returnElement){
4809 return this.doInsert('beforeEnd', el, values, returnElement);
4812 doInsert : function(where, el, values, returnEl){
4813 el = Roo.getDom(el);
4814 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4815 return returnEl ? Roo.get(newNode, true) : newNode;
4819 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4820 * @param {String/HTMLElement/Roo.Element} el The context element
4821 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4822 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823 * @return {HTMLElement/Roo.Element} The new node or Element
4825 overwrite : function(el, values, returnElement){
4826 el = Roo.getDom(el);
4827 el.innerHTML = this.applyTemplate(values);
4828 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4832 * Alias for {@link #applyTemplate}
4835 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4838 Roo.DomHelper.Template = Roo.Template;
4841 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4842 * @param {String/HTMLElement} el A DOM element or its id
4843 * @returns {Roo.Template} The created template
4846 Roo.Template.from = function(el){
4847 el = Roo.getDom(el);
4848 return new Roo.Template(el.value || el.innerHTML);
4851 * Ext JS Library 1.1.1
4852 * Copyright(c) 2006-2007, Ext JS, LLC.
4854 * Originally Released Under LGPL - original licence link has changed is not relivant.
4857 * <script type="text/javascript">
4862 * This is code is also distributed under MIT license for use
4863 * with jQuery and prototype JavaScript libraries.
4866 * @class Roo.DomQuery
4867 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4869 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4872 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4874 <h4>Element Selectors:</h4>
4876 <li> <b>*</b> any element</li>
4877 <li> <b>E</b> an element with the tag E</li>
4878 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4879 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4880 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4881 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4883 <h4>Attribute Selectors:</h4>
4884 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4886 <li> <b>E[foo]</b> has an attribute "foo"</li>
4887 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4888 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4889 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4890 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4891 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4892 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4894 <h4>Pseudo Classes:</h4>
4896 <li> <b>E:first-child</b> E is the first child of its parent</li>
4897 <li> <b>E:last-child</b> E is the last child of its parent</li>
4898 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4899 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4900 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4901 <li> <b>E:only-child</b> E is the only child of its parent</li>
4902 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4903 <li> <b>E:first</b> the first E in the resultset</li>
4904 <li> <b>E:last</b> the last E in the resultset</li>
4905 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4906 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4907 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4908 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4909 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4910 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4911 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4912 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4913 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4915 <h4>CSS Value Selectors:</h4>
4917 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4918 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4919 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4920 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4921 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4922 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4926 Roo.DomQuery = function(){
4927 var cache = {}, simpleCache = {}, valueCache = {};
4928 var nonSpace = /\S/;
4929 var trimRe = /^\s+|\s+$/g;
4930 var tplRe = /\{(\d+)\}/g;
4931 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4932 var tagTokenRe = /^(#)?([\w-\*]+)/;
4933 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4935 function child(p, index){
4937 var n = p.firstChild;
4939 if(n.nodeType == 1){
4950 while((n = n.nextSibling) && n.nodeType != 1);
4955 while((n = n.previousSibling) && n.nodeType != 1);
4959 function children(d){
4960 var n = d.firstChild, ni = -1;
4962 var nx = n.nextSibling;
4963 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4973 function byClassName(c, a, v){
4977 var r = [], ri = -1, cn;
4978 for(var i = 0, ci; ci = c[i]; i++){
4979 if((' '+ci.className+' ').indexOf(v) != -1){
4986 function attrValue(n, attr){
4987 if(!n.tagName && typeof n.length != "undefined"){
4996 if(attr == "class" || attr == "className"){
4999 return n.getAttribute(attr) || n[attr];
5003 function getNodes(ns, mode, tagName){
5004 var result = [], ri = -1, cs;
5008 tagName = tagName || "*";
5009 if(typeof ns.getElementsByTagName != "undefined"){
5013 for(var i = 0, ni; ni = ns[i]; i++){
5014 cs = ni.getElementsByTagName(tagName);
5015 for(var j = 0, ci; ci = cs[j]; j++){
5019 }else if(mode == "/" || mode == ">"){
5020 var utag = tagName.toUpperCase();
5021 for(var i = 0, ni, cn; ni = ns[i]; i++){
5022 cn = ni.children || ni.childNodes;
5023 for(var j = 0, cj; cj = cn[j]; j++){
5024 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5029 }else if(mode == "+"){
5030 var utag = tagName.toUpperCase();
5031 for(var i = 0, n; n = ns[i]; i++){
5032 while((n = n.nextSibling) && n.nodeType != 1);
5033 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5037 }else if(mode == "~"){
5038 for(var i = 0, n; n = ns[i]; i++){
5039 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5048 function concat(a, b){
5052 for(var i = 0, l = b.length; i < l; i++){
5058 function byTag(cs, tagName){
5059 if(cs.tagName || cs == document){
5065 var r = [], ri = -1;
5066 tagName = tagName.toLowerCase();
5067 for(var i = 0, ci; ci = cs[i]; i++){
5068 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5075 function byId(cs, attr, id){
5076 if(cs.tagName || cs == document){
5082 var r = [], ri = -1;
5083 for(var i = 0,ci; ci = cs[i]; i++){
5084 if(ci && ci.id == id){
5092 function byAttribute(cs, attr, value, op, custom){
5093 var r = [], ri = -1, st = custom=="{";
5094 var f = Roo.DomQuery.operators[op];
5095 for(var i = 0, ci; ci = cs[i]; i++){
5098 a = Roo.DomQuery.getStyle(ci, attr);
5100 else if(attr == "class" || attr == "className"){
5102 }else if(attr == "for"){
5104 }else if(attr == "href"){
5105 a = ci.getAttribute("href", 2);
5107 a = ci.getAttribute(attr);
5109 if((f && f(a, value)) || (!f && a)){
5116 function byPseudo(cs, name, value){
5117 return Roo.DomQuery.pseudos[name](cs, value);
5120 // This is for IE MSXML which does not support expandos.
5121 // IE runs the same speed using setAttribute, however FF slows way down
5122 // and Safari completely fails so they need to continue to use expandos.
5123 var isIE = window.ActiveXObject ? true : false;
5125 // this eval is stop the compressor from
5126 // renaming the variable to something shorter
5128 /** eval:var:batch */
5133 function nodupIEXml(cs){
5135 cs[0].setAttribute("_nodup", d);
5137 for(var i = 1, len = cs.length; i < len; i++){
5139 if(!c.getAttribute("_nodup") != d){
5140 c.setAttribute("_nodup", d);
5144 for(var i = 0, len = cs.length; i < len; i++){
5145 cs[i].removeAttribute("_nodup");
5154 var len = cs.length, c, i, r = cs, cj, ri = -1;
5155 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5158 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5159 return nodupIEXml(cs);
5163 for(i = 1; c = cs[i]; i++){
5168 for(var j = 0; j < i; j++){
5171 for(j = i+1; cj = cs[j]; j++){
5183 function quickDiffIEXml(c1, c2){
5185 for(var i = 0, len = c1.length; i < len; i++){
5186 c1[i].setAttribute("_qdiff", d);
5189 for(var i = 0, len = c2.length; i < len; i++){
5190 if(c2[i].getAttribute("_qdiff") != d){
5191 r[r.length] = c2[i];
5194 for(var i = 0, len = c1.length; i < len; i++){
5195 c1[i].removeAttribute("_qdiff");
5200 function quickDiff(c1, c2){
5201 var len1 = c1.length;
5205 if(isIE && c1[0].selectSingleNode){
5206 return quickDiffIEXml(c1, c2);
5209 for(var i = 0; i < len1; i++){
5213 for(var i = 0, len = c2.length; i < len; i++){
5214 if(c2[i]._qdiff != d){
5215 r[r.length] = c2[i];
5221 function quickId(ns, mode, root, id){
5223 var d = root.ownerDocument || root;
5224 return d.getElementById(id);
5226 ns = getNodes(ns, mode, "*");
5227 return byId(ns, null, id);
5231 getStyle : function(el, name){
5232 return Roo.fly(el).getStyle(name);
5235 * Compiles a selector/xpath query into a reusable function. The returned function
5236 * takes one parameter "root" (optional), which is the context node from where the query should start.
5237 * @param {String} selector The selector/xpath query
5238 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5239 * @return {Function}
5241 compile : function(path, type){
5242 type = type || "select";
5244 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5245 var q = path, mode, lq;
5246 var tk = Roo.DomQuery.matchers;
5247 var tklen = tk.length;
5250 // accept leading mode switch
5251 var lmode = q.match(modeRe);
5252 if(lmode && lmode[1]){
5253 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5254 q = q.replace(lmode[1], "");
5256 // strip leading slashes
5257 while(path.substr(0, 1)=="/"){
5258 path = path.substr(1);
5261 while(q && lq != q){
5263 var tm = q.match(tagTokenRe);
5264 if(type == "select"){
5267 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5269 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5271 q = q.replace(tm[0], "");
5272 }else if(q.substr(0, 1) != '@'){
5273 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5278 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5280 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5282 q = q.replace(tm[0], "");
5285 while(!(mm = q.match(modeRe))){
5286 var matched = false;
5287 for(var j = 0; j < tklen; j++){
5289 var m = q.match(t.re);
5291 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5294 q = q.replace(m[0], "");
5299 // prevent infinite loop on bad selector
5301 throw 'Error parsing selector, parsing failed at "' + q + '"';
5305 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5306 q = q.replace(mm[1], "");
5309 fn[fn.length] = "return nodup(n);\n}";
5312 * list of variables that need from compression as they are used by eval.
5322 * eval:var:byClassName
5324 * eval:var:byAttribute
5325 * eval:var:attrValue
5333 * Selects a group of elements.
5334 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5335 * @param {Node} root (optional) The start of the query (defaults to document).
5338 select : function(path, root, type){
5339 if(!root || root == document){
5342 if(typeof root == "string"){
5343 root = document.getElementById(root);
5345 var paths = path.split(",");
5347 for(var i = 0, len = paths.length; i < len; i++){
5348 var p = paths[i].replace(trimRe, "");
5350 cache[p] = Roo.DomQuery.compile(p);
5352 throw p + " is not a valid selector";
5355 var result = cache[p](root);
5356 if(result && result != document){
5357 results = results.concat(result);
5360 if(paths.length > 1){
5361 return nodup(results);
5367 * Selects a single element.
5368 * @param {String} selector The selector/xpath query
5369 * @param {Node} root (optional) The start of the query (defaults to document).
5372 selectNode : function(path, root){
5373 return Roo.DomQuery.select(path, root)[0];
5377 * Selects the value of a node, optionally replacing null with the defaultValue.
5378 * @param {String} selector The selector/xpath query
5379 * @param {Node} root (optional) The start of the query (defaults to document).
5380 * @param {String} defaultValue
5382 selectValue : function(path, root, defaultValue){
5383 path = path.replace(trimRe, "");
5384 if(!valueCache[path]){
5385 valueCache[path] = Roo.DomQuery.compile(path, "select");
5387 var n = valueCache[path](root);
5388 n = n[0] ? n[0] : n;
5389 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5390 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5394 * Selects the value of a node, parsing integers and floats.
5395 * @param {String} selector The selector/xpath query
5396 * @param {Node} root (optional) The start of the query (defaults to document).
5397 * @param {Number} defaultValue
5400 selectNumber : function(path, root, defaultValue){
5401 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5402 return parseFloat(v);
5406 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5407 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5408 * @param {String} selector The simple selector to test
5411 is : function(el, ss){
5412 if(typeof el == "string"){
5413 el = document.getElementById(el);
5415 var isArray = (el instanceof Array);
5416 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5417 return isArray ? (result.length == el.length) : (result.length > 0);
5421 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5422 * @param {Array} el An array of elements to filter
5423 * @param {String} selector The simple selector to test
5424 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5425 * the selector instead of the ones that match
5428 filter : function(els, ss, nonMatches){
5429 ss = ss.replace(trimRe, "");
5430 if(!simpleCache[ss]){
5431 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5433 var result = simpleCache[ss](els);
5434 return nonMatches ? quickDiff(result, els) : result;
5438 * Collection of matching regular expressions and code snippets.
5442 select: 'n = byClassName(n, null, " {1} ");'
5444 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5445 select: 'n = byPseudo(n, "{1}", "{2}");'
5447 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5448 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5451 select: 'n = byId(n, null, "{1}");'
5454 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5459 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5460 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5463 "=" : function(a, v){
5466 "!=" : function(a, v){
5469 "^=" : function(a, v){
5470 return a && a.substr(0, v.length) == v;
5472 "$=" : function(a, v){
5473 return a && a.substr(a.length-v.length) == v;
5475 "*=" : function(a, v){
5476 return a && a.indexOf(v) !== -1;
5478 "%=" : function(a, v){
5479 return (a % v) == 0;
5481 "|=" : function(a, v){
5482 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5484 "~=" : function(a, v){
5485 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5490 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5491 * and the argument (if any) supplied in the selector.
5494 "first-child" : function(c){
5495 var r = [], ri = -1, n;
5496 for(var i = 0, ci; ci = n = c[i]; i++){
5497 while((n = n.previousSibling) && n.nodeType != 1);
5505 "last-child" : function(c){
5506 var r = [], ri = -1, n;
5507 for(var i = 0, ci; ci = n = c[i]; i++){
5508 while((n = n.nextSibling) && n.nodeType != 1);
5516 "nth-child" : function(c, a) {
5517 var r = [], ri = -1;
5518 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5519 var f = (m[1] || 1) - 0, l = m[2] - 0;
5520 for(var i = 0, n; n = c[i]; i++){
5521 var pn = n.parentNode;
5522 if (batch != pn._batch) {
5524 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5525 if(cn.nodeType == 1){
5532 if (l == 0 || n.nodeIndex == l){
5535 } else if ((n.nodeIndex + l) % f == 0){
5543 "only-child" : function(c){
5544 var r = [], ri = -1;;
5545 for(var i = 0, ci; ci = c[i]; i++){
5546 if(!prev(ci) && !next(ci)){
5553 "empty" : function(c){
5554 var r = [], ri = -1;
5555 for(var i = 0, ci; ci = c[i]; i++){
5556 var cns = ci.childNodes, j = 0, cn, empty = true;
5559 if(cn.nodeType == 1 || cn.nodeType == 3){
5571 "contains" : function(c, v){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5581 "nodeValue" : function(c, v){
5582 var r = [], ri = -1;
5583 for(var i = 0, ci; ci = c[i]; i++){
5584 if(ci.firstChild && ci.firstChild.nodeValue == v){
5591 "checked" : function(c){
5592 var r = [], ri = -1;
5593 for(var i = 0, ci; ci = c[i]; i++){
5594 if(ci.checked == true){
5601 "not" : function(c, ss){
5602 return Roo.DomQuery.filter(c, ss, true);
5605 "odd" : function(c){
5606 return this["nth-child"](c, "odd");
5609 "even" : function(c){
5610 return this["nth-child"](c, "even");
5613 "nth" : function(c, a){
5614 return c[a-1] || [];
5617 "first" : function(c){
5621 "last" : function(c){
5622 return c[c.length-1] || [];
5625 "has" : function(c, ss){
5626 var s = Roo.DomQuery.select;
5627 var r = [], ri = -1;
5628 for(var i = 0, ci; ci = c[i]; i++){
5629 if(s(ss, ci).length > 0){
5636 "next" : function(c, ss){
5637 var is = Roo.DomQuery.is;
5638 var r = [], ri = -1;
5639 for(var i = 0, ci; ci = c[i]; i++){
5648 "prev" : function(c, ss){
5649 var is = Roo.DomQuery.is;
5650 var r = [], ri = -1;
5651 for(var i = 0, ci; ci = c[i]; i++){
5664 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5665 * @param {String} path The selector/xpath query
5666 * @param {Node} root (optional) The start of the query (defaults to document).
5671 Roo.query = Roo.DomQuery.select;
5674 * Ext JS Library 1.1.1
5675 * Copyright(c) 2006-2007, Ext JS, LLC.
5677 * Originally Released Under LGPL - original licence link has changed is not relivant.
5680 * <script type="text/javascript">
5684 * @class Roo.util.Observable
5685 * Base class that provides a common interface for publishing events. Subclasses are expected to
5686 * to have a property "events" with all the events defined.<br>
5689 Employee = function(name){
5696 Roo.extend(Employee, Roo.util.Observable);
5698 * @param {Object} config properties to use (incuding events / listeners)
5701 Roo.util.Observable = function(cfg){
5704 this.addEvents(cfg.events || {});
5706 delete cfg.events; // make sure
5709 Roo.apply(this, cfg);
5712 this.on(this.listeners);
5713 delete this.listeners;
5716 Roo.util.Observable.prototype = {
5718 * @cfg {Object} listeners list of events and functions to call for this object,
5722 'click' : function(e) {
5732 * Fires the specified event with the passed parameters (minus the event name).
5733 * @param {String} eventName
5734 * @param {Object...} args Variable number of parameters are passed to handlers
5735 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5737 fireEvent : function(){
5738 var ce = this.events[arguments[0].toLowerCase()];
5739 if(typeof ce == "object"){
5740 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5747 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5750 * Appends an event handler to this component
5751 * @param {String} eventName The type of event to listen for
5752 * @param {Function} handler The method the event invokes
5753 * @param {Object} scope (optional) The scope in which to execute the handler
5754 * function. The handler function's "this" context.
5755 * @param {Object} options (optional) An object containing handler configuration
5756 * properties. This may contain any of the following properties:<ul>
5757 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5758 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5759 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5760 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5761 * by the specified number of milliseconds. If the event fires again within that time, the original
5762 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5765 * <b>Combining Options</b><br>
5766 * Using the options argument, it is possible to combine different types of listeners:<br>
5768 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5770 el.on('click', this.onClick, this, {
5777 * <b>Attaching multiple handlers in 1 call</b><br>
5778 * The method also allows for a single argument to be passed which is a config object containing properties
5779 * which specify multiple handlers.
5788 fn: this.onMouseOver,
5792 fn: this.onMouseOut,
5798 * Or a shorthand syntax which passes the same scope object to all handlers:
5801 'click': this.onClick,
5802 'mouseover': this.onMouseOver,
5803 'mouseout': this.onMouseOut,
5808 addListener : function(eventName, fn, scope, o){
5809 if(typeof eventName == "object"){
5812 if(this.filterOptRe.test(e)){
5815 if(typeof o[e] == "function"){
5817 this.addListener(e, o[e], o.scope, o);
5819 // individual options
5820 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5825 o = (!o || typeof o == "boolean") ? {} : o;
5826 eventName = eventName.toLowerCase();
5827 var ce = this.events[eventName] || true;
5828 if(typeof ce == "boolean"){
5829 ce = new Roo.util.Event(this, eventName);
5830 this.events[eventName] = ce;
5832 ce.addListener(fn, scope, o);
5836 * Removes a listener
5837 * @param {String} eventName The type of event to listen for
5838 * @param {Function} handler The handler to remove
5839 * @param {Object} scope (optional) The scope (this object) for the handler
5841 removeListener : function(eventName, fn, scope){
5842 var ce = this.events[eventName.toLowerCase()];
5843 if(typeof ce == "object"){
5844 ce.removeListener(fn, scope);
5849 * Removes all listeners for this object
5851 purgeListeners : function(){
5852 for(var evt in this.events){
5853 if(typeof this.events[evt] == "object"){
5854 this.events[evt].clearListeners();
5859 relayEvents : function(o, events){
5860 var createHandler = function(ename){
5862 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5865 for(var i = 0, len = events.length; i < len; i++){
5866 var ename = events[i];
5867 if(!this.events[ename]){ this.events[ename] = true; };
5868 o.on(ename, createHandler(ename), this);
5873 * Used to define events on this Observable
5874 * @param {Object} object The object with the events defined
5876 addEvents : function(o){
5880 Roo.applyIf(this.events, o);
5884 * Checks to see if this object has any listeners for a specified event
5885 * @param {String} eventName The name of the event to check for
5886 * @return {Boolean} True if the event is being listened for, else false
5888 hasListener : function(eventName){
5889 var e = this.events[eventName];
5890 return typeof e == "object" && e.listeners.length > 0;
5894 * Appends an event handler to this element (shorthand for addListener)
5895 * @param {String} eventName The type of event to listen for
5896 * @param {Function} handler The method the event invokes
5897 * @param {Object} scope (optional) The scope in which to execute the handler
5898 * function. The handler function's "this" context.
5899 * @param {Object} options (optional)
5902 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5904 * Removes a listener (shorthand for removeListener)
5905 * @param {String} eventName The type of event to listen for
5906 * @param {Function} handler The handler to remove
5907 * @param {Object} scope (optional) The scope (this object) for the handler
5910 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5913 * Starts capture on the specified Observable. All events will be passed
5914 * to the supplied function with the event name + standard signature of the event
5915 * <b>before</b> the event is fired. If the supplied function returns false,
5916 * the event will not fire.
5917 * @param {Observable} o The Observable to capture
5918 * @param {Function} fn The function to call
5919 * @param {Object} scope (optional) The scope (this object) for the fn
5922 Roo.util.Observable.capture = function(o, fn, scope){
5923 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5927 * Removes <b>all</b> added captures from the Observable.
5928 * @param {Observable} o The Observable to release
5931 Roo.util.Observable.releaseCapture = function(o){
5932 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5937 var createBuffered = function(h, o, scope){
5938 var task = new Roo.util.DelayedTask();
5940 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5944 var createSingle = function(h, e, fn, scope){
5946 e.removeListener(fn, scope);
5947 return h.apply(scope, arguments);
5951 var createDelayed = function(h, o, scope){
5953 var args = Array.prototype.slice.call(arguments, 0);
5954 setTimeout(function(){
5955 h.apply(scope, args);
5960 Roo.util.Event = function(obj, name){
5963 this.listeners = [];
5966 Roo.util.Event.prototype = {
5967 addListener : function(fn, scope, options){
5968 var o = options || {};
5969 scope = scope || this.obj;
5970 if(!this.isListening(fn, scope)){
5971 var l = {fn: fn, scope: scope, options: o};
5974 h = createDelayed(h, o, scope);
5977 h = createSingle(h, this, fn, scope);
5980 h = createBuffered(h, o, scope);
5983 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5984 this.listeners.push(l);
5986 this.listeners = this.listeners.slice(0);
5987 this.listeners.push(l);
5992 findListener : function(fn, scope){
5993 scope = scope || this.obj;
5994 var ls = this.listeners;
5995 for(var i = 0, len = ls.length; i < len; i++){
5997 if(l.fn == fn && l.scope == scope){
6004 isListening : function(fn, scope){
6005 return this.findListener(fn, scope) != -1;
6008 removeListener : function(fn, scope){
6010 if((index = this.findListener(fn, scope)) != -1){
6012 this.listeners.splice(index, 1);
6014 this.listeners = this.listeners.slice(0);
6015 this.listeners.splice(index, 1);
6022 clearListeners : function(){
6023 this.listeners = [];
6027 var ls = this.listeners, scope, len = ls.length;
6030 var args = Array.prototype.slice.call(arguments, 0);
6031 for(var i = 0; i < len; i++){
6033 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6034 this.firing = false;
6038 this.firing = false;
6045 * Ext JS Library 1.1.1
6046 * Copyright(c) 2006-2007, Ext JS, LLC.
6048 * Originally Released Under LGPL - original licence link has changed is not relivant.
6051 * <script type="text/javascript">
6055 * @class Roo.EventManager
6056 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6057 * several useful events directly.
6058 * See {@link Roo.EventObject} for more details on normalized event objects.
6061 Roo.EventManager = function(){
6062 var docReadyEvent, docReadyProcId, docReadyState = false;
6063 var resizeEvent, resizeTask, textEvent, textSize;
6064 var E = Roo.lib.Event;
6065 var D = Roo.lib.Dom;
6070 var fireDocReady = function(){
6072 docReadyState = true;
6075 clearInterval(docReadyProcId);
6077 if(Roo.isGecko || Roo.isOpera) {
6078 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6081 var defer = document.getElementById("ie-deferred-loader");
6083 defer.onreadystatechange = null;
6084 defer.parentNode.removeChild(defer);
6088 docReadyEvent.fire();
6089 docReadyEvent.clearListeners();
6094 var initDocReady = function(){
6095 docReadyEvent = new Roo.util.Event();
6096 if(Roo.isGecko || Roo.isOpera) {
6097 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6099 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6100 var defer = document.getElementById("ie-deferred-loader");
6101 defer.onreadystatechange = function(){
6102 if(this.readyState == "complete"){
6106 }else if(Roo.isSafari){
6107 docReadyProcId = setInterval(function(){
6108 var rs = document.readyState;
6109 if(rs == "complete") {
6114 // no matter what, make sure it fires on load
6115 E.on(window, "load", fireDocReady);
6118 var createBuffered = function(h, o){
6119 var task = new Roo.util.DelayedTask(h);
6121 // create new event object impl so new events don't wipe out properties
6122 e = new Roo.EventObjectImpl(e);
6123 task.delay(o.buffer, h, null, [e]);
6127 var createSingle = function(h, el, ename, fn){
6129 Roo.EventManager.removeListener(el, ename, fn);
6134 var createDelayed = function(h, o){
6136 // create new event object impl so new events don't wipe out properties
6137 e = new Roo.EventObjectImpl(e);
6138 setTimeout(function(){
6143 var transitionEndVal = false;
6145 var transitionEnd = function()
6147 if (transitionEndVal) {
6148 return transitionEndVal;
6150 var el = document.createElement('div');
6152 var transEndEventNames = {
6153 WebkitTransition : 'webkitTransitionEnd',
6154 MozTransition : 'transitionend',
6155 OTransition : 'oTransitionEnd otransitionend',
6156 transition : 'transitionend'
6159 for (var name in transEndEventNames) {
6160 if (el.style[name] !== undefined) {
6161 transitionEndVal = transEndEventNames[name];
6162 return transitionEndVal ;
6168 var listen = function(element, ename, opt, fn, scope){
6169 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6170 fn = fn || o.fn; scope = scope || o.scope;
6171 var el = Roo.getDom(element);
6175 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6178 if (ename == 'transitionend') {
6179 ename = transitionEnd();
6181 var h = function(e){
6182 e = Roo.EventObject.setEvent(e);
6185 t = e.getTarget(o.delegate, el);
6192 if(o.stopEvent === true){
6195 if(o.preventDefault === true){
6198 if(o.stopPropagation === true){
6199 e.stopPropagation();
6202 if(o.normalized === false){
6206 fn.call(scope || el, e, t, o);
6209 h = createDelayed(h, o);
6212 h = createSingle(h, el, ename, fn);
6215 h = createBuffered(h, o);
6217 fn._handlers = fn._handlers || [];
6220 fn._handlers.push([Roo.id(el), ename, h]);
6225 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6226 el.addEventListener("DOMMouseScroll", h, false);
6227 E.on(window, 'unload', function(){
6228 el.removeEventListener("DOMMouseScroll", h, false);
6231 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6232 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6237 var stopListening = function(el, ename, fn){
6238 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6240 for(var i = 0, len = hds.length; i < len; i++){
6242 if(h[0] == id && h[1] == ename){
6249 E.un(el, ename, hd);
6250 el = Roo.getDom(el);
6251 if(ename == "mousewheel" && el.addEventListener){
6252 el.removeEventListener("DOMMouseScroll", hd, false);
6254 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6255 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6259 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6266 * @scope Roo.EventManager
6271 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6272 * object with a Roo.EventObject
6273 * @param {Function} fn The method the event invokes
6274 * @param {Object} scope An object that becomes the scope of the handler
6275 * @param {boolean} override If true, the obj passed in becomes
6276 * the execution scope of the listener
6277 * @return {Function} The wrapped function
6280 wrap : function(fn, scope, override){
6282 Roo.EventObject.setEvent(e);
6283 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6288 * Appends an event handler to an element (shorthand for addListener)
6289 * @param {String/HTMLElement} element The html element or id to assign the
6290 * @param {String} eventName The type of event to listen for
6291 * @param {Function} handler The method the event invokes
6292 * @param {Object} scope (optional) The scope in which to execute the handler
6293 * function. The handler function's "this" context.
6294 * @param {Object} options (optional) An object containing handler configuration
6295 * properties. This may contain any of the following properties:<ul>
6296 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6297 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6298 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6299 * <li>preventDefault {Boolean} True to prevent the default action</li>
6300 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6301 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6302 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6303 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6304 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6305 * by the specified number of milliseconds. If the event fires again within that time, the original
6306 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6309 * <b>Combining Options</b><br>
6310 * Using the options argument, it is possible to combine different types of listeners:<br>
6312 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6314 el.on('click', this.onClick, this, {
6321 * <b>Attaching multiple handlers in 1 call</b><br>
6322 * The method also allows for a single argument to be passed which is a config object containing properties
6323 * which specify multiple handlers.
6333 fn: this.onMouseOver
6342 * Or a shorthand syntax:<br>
6345 'click' : this.onClick,
6346 'mouseover' : this.onMouseOver,
6347 'mouseout' : this.onMouseOut
6351 addListener : function(element, eventName, fn, scope, options){
6352 if(typeof eventName == "object"){
6358 if(typeof o[e] == "function"){
6360 listen(element, e, o, o[e], o.scope);
6362 // individual options
6363 listen(element, e, o[e]);
6368 return listen(element, eventName, options, fn, scope);
6372 * Removes an event handler
6374 * @param {String/HTMLElement} element The id or html element to remove the
6376 * @param {String} eventName The type of event
6377 * @param {Function} fn
6378 * @return {Boolean} True if a listener was actually removed
6380 removeListener : function(element, eventName, fn){
6381 return stopListening(element, eventName, fn);
6385 * Fires when the document is ready (before onload and before images are loaded). Can be
6386 * accessed shorthanded Roo.onReady().
6387 * @param {Function} fn The method the event invokes
6388 * @param {Object} scope An object that becomes the scope of the handler
6389 * @param {boolean} options
6391 onDocumentReady : function(fn, scope, options){
6392 if(docReadyState){ // if it already fired
6393 docReadyEvent.addListener(fn, scope, options);
6394 docReadyEvent.fire();
6395 docReadyEvent.clearListeners();
6401 docReadyEvent.addListener(fn, scope, options);
6405 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6406 * @param {Function} fn The method the event invokes
6407 * @param {Object} scope An object that becomes the scope of the handler
6408 * @param {boolean} options
6410 onWindowResize : function(fn, scope, options){
6412 resizeEvent = new Roo.util.Event();
6413 resizeTask = new Roo.util.DelayedTask(function(){
6414 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6416 E.on(window, "resize", function(){
6418 resizeTask.delay(50);
6420 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6424 resizeEvent.addListener(fn, scope, options);
6428 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6429 * @param {Function} fn The method the event invokes
6430 * @param {Object} scope An object that becomes the scope of the handler
6431 * @param {boolean} options
6433 onTextResize : function(fn, scope, options){
6435 textEvent = new Roo.util.Event();
6436 var textEl = new Roo.Element(document.createElement('div'));
6437 textEl.dom.className = 'x-text-resize';
6438 textEl.dom.innerHTML = 'X';
6439 textEl.appendTo(document.body);
6440 textSize = textEl.dom.offsetHeight;
6441 setInterval(function(){
6442 if(textEl.dom.offsetHeight != textSize){
6443 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6445 }, this.textResizeInterval);
6447 textEvent.addListener(fn, scope, options);
6451 * Removes the passed window resize listener.
6452 * @param {Function} fn The method the event invokes
6453 * @param {Object} scope The scope of handler
6455 removeResizeListener : function(fn, scope){
6457 resizeEvent.removeListener(fn, scope);
6462 fireResize : function(){
6464 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6468 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6472 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6474 textResizeInterval : 50
6479 * @scopeAlias pub=Roo.EventManager
6483 * Appends an event handler to an element (shorthand for addListener)
6484 * @param {String/HTMLElement} element The html element or id to assign the
6485 * @param {String} eventName The type of event to listen for
6486 * @param {Function} handler The method the event invokes
6487 * @param {Object} scope (optional) The scope in which to execute the handler
6488 * function. The handler function's "this" context.
6489 * @param {Object} options (optional) An object containing handler configuration
6490 * properties. This may contain any of the following properties:<ul>
6491 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6492 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6493 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6494 * <li>preventDefault {Boolean} True to prevent the default action</li>
6495 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6496 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6497 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6498 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6499 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6500 * by the specified number of milliseconds. If the event fires again within that time, the original
6501 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6504 * <b>Combining Options</b><br>
6505 * Using the options argument, it is possible to combine different types of listeners:<br>
6507 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6509 el.on('click', this.onClick, this, {
6516 * <b>Attaching multiple handlers in 1 call</b><br>
6517 * The method also allows for a single argument to be passed which is a config object containing properties
6518 * which specify multiple handlers.
6528 fn: this.onMouseOver
6537 * Or a shorthand syntax:<br>
6540 'click' : this.onClick,
6541 'mouseover' : this.onMouseOver,
6542 'mouseout' : this.onMouseOut
6546 pub.on = pub.addListener;
6547 pub.un = pub.removeListener;
6549 pub.stoppedMouseDownEvent = new Roo.util.Event();
6553 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6554 * @param {Function} fn The method the event invokes
6555 * @param {Object} scope An object that becomes the scope of the handler
6556 * @param {boolean} override If true, the obj passed in becomes
6557 * the execution scope of the listener
6561 Roo.onReady = Roo.EventManager.onDocumentReady;
6563 Roo.onReady(function(){
6564 var bd = Roo.get(document.body);
6569 : Roo.isGecko ? "roo-gecko"
6570 : Roo.isOpera ? "roo-opera"
6571 : Roo.isSafari ? "roo-safari" : ""];
6574 cls.push("roo-mac");
6577 cls.push("roo-linux");
6579 if(Roo.isBorderBox){
6580 cls.push('roo-border-box');
6582 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6583 var p = bd.dom.parentNode;
6585 p.className += ' roo-strict';
6588 bd.addClass(cls.join(' '));
6592 * @class Roo.EventObject
6593 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6594 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6597 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6599 var target = e.getTarget();
6602 var myDiv = Roo.get("myDiv");
6603 myDiv.on("click", handleClick);
6605 Roo.EventManager.on("myDiv", 'click', handleClick);
6606 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6610 Roo.EventObject = function(){
6612 var E = Roo.lib.Event;
6614 // safari keypress events for special keys return bad keycodes
6617 63235 : 39, // right
6620 63276 : 33, // page up
6621 63277 : 34, // page down
6622 63272 : 46, // delete
6627 // normalize button clicks
6628 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6629 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6631 Roo.EventObjectImpl = function(e){
6633 this.setEvent(e.browserEvent || e);
6636 Roo.EventObjectImpl.prototype = {
6638 * Used to fix doc tools.
6639 * @scope Roo.EventObject.prototype
6645 /** The normal browser event */
6646 browserEvent : null,
6647 /** The button pressed in a mouse event */
6649 /** True if the shift key was down during the event */
6651 /** True if the control key was down during the event */
6653 /** True if the alt key was down during the event */
6712 setEvent : function(e){
6713 if(e == this || (e && e.browserEvent)){ // already wrapped
6716 this.browserEvent = e;
6718 // normalize buttons
6719 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6720 if(e.type == 'click' && this.button == -1){
6724 this.shiftKey = e.shiftKey;
6725 // mac metaKey behaves like ctrlKey
6726 this.ctrlKey = e.ctrlKey || e.metaKey;
6727 this.altKey = e.altKey;
6728 // in getKey these will be normalized for the mac
6729 this.keyCode = e.keyCode;
6730 // keyup warnings on firefox.
6731 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6732 // cache the target for the delayed and or buffered events
6733 this.target = E.getTarget(e);
6735 this.xy = E.getXY(e);
6738 this.shiftKey = false;
6739 this.ctrlKey = false;
6740 this.altKey = false;
6750 * Stop the event (preventDefault and stopPropagation)
6752 stopEvent : function(){
6753 if(this.browserEvent){
6754 if(this.browserEvent.type == 'mousedown'){
6755 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6757 E.stopEvent(this.browserEvent);
6762 * Prevents the browsers default handling of the event.
6764 preventDefault : function(){
6765 if(this.browserEvent){
6766 E.preventDefault(this.browserEvent);
6771 isNavKeyPress : function(){
6772 var k = this.keyCode;
6773 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6774 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6777 isSpecialKey : function(){
6778 var k = this.keyCode;
6779 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6780 (k == 16) || (k == 17) ||
6781 (k >= 18 && k <= 20) ||
6782 (k >= 33 && k <= 35) ||
6783 (k >= 36 && k <= 39) ||
6784 (k >= 44 && k <= 45);
6787 * Cancels bubbling of the event.
6789 stopPropagation : function(){
6790 if(this.browserEvent){
6791 if(this.type == 'mousedown'){
6792 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6794 E.stopPropagation(this.browserEvent);
6799 * Gets the key code for the event.
6802 getCharCode : function(){
6803 return this.charCode || this.keyCode;
6807 * Returns a normalized keyCode for the event.
6808 * @return {Number} The key code
6810 getKey : function(){
6811 var k = this.keyCode || this.charCode;
6812 return Roo.isSafari ? (safariKeys[k] || k) : k;
6816 * Gets the x coordinate of the event.
6819 getPageX : function(){
6824 * Gets the y coordinate of the event.
6827 getPageY : function(){
6832 * Gets the time of the event.
6835 getTime : function(){
6836 if(this.browserEvent){
6837 return E.getTime(this.browserEvent);
6843 * Gets the page coordinates of the event.
6844 * @return {Array} The xy values like [x, y]
6851 * Gets the target for the event.
6852 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6853 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6854 search as a number or element (defaults to 10 || document.body)
6855 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6856 * @return {HTMLelement}
6858 getTarget : function(selector, maxDepth, returnEl){
6859 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6862 * Gets the related target.
6863 * @return {HTMLElement}
6865 getRelatedTarget : function(){
6866 if(this.browserEvent){
6867 return E.getRelatedTarget(this.browserEvent);
6873 * Normalizes mouse wheel delta across browsers
6874 * @return {Number} The delta
6876 getWheelDelta : function(){
6877 var e = this.browserEvent;
6879 if(e.wheelDelta){ /* IE/Opera. */
6880 delta = e.wheelDelta/120;
6881 }else if(e.detail){ /* Mozilla case. */
6882 delta = -e.detail/3;
6888 * Returns true if the control, meta, shift or alt key was pressed during this event.
6891 hasModifier : function(){
6892 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6896 * Returns true if the target of this event equals el or is a child of el
6897 * @param {String/HTMLElement/Element} el
6898 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6901 within : function(el, related){
6902 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6903 return t && Roo.fly(el).contains(t);
6906 getPoint : function(){
6907 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6911 return new Roo.EventObjectImpl();
6916 * Ext JS Library 1.1.1
6917 * Copyright(c) 2006-2007, Ext JS, LLC.
6919 * Originally Released Under LGPL - original licence link has changed is not relivant.
6922 * <script type="text/javascript">
6926 // was in Composite Element!??!?!
6929 var D = Roo.lib.Dom;
6930 var E = Roo.lib.Event;
6931 var A = Roo.lib.Anim;
6933 // local style camelizing for speed
6935 var camelRe = /(-[a-z])/gi;
6936 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6937 var view = document.defaultView;
6940 * @class Roo.Element
6941 * Represents an Element in the DOM.<br><br>
6944 var el = Roo.get("my-div");
6947 var el = getEl("my-div");
6949 // or with a DOM element
6950 var el = Roo.get(myDivElement);
6952 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6953 * each call instead of constructing a new one.<br><br>
6954 * <b>Animations</b><br />
6955 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6956 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6958 Option Default Description
6959 --------- -------- ---------------------------------------------
6960 duration .35 The duration of the animation in seconds
6961 easing easeOut The YUI easing method
6962 callback none A function to execute when the anim completes
6963 scope this The scope (this) of the callback function
6965 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6966 * manipulate the animation. Here's an example:
6968 var el = Roo.get("my-div");
6973 // default animation
6974 el.setWidth(100, true);
6976 // animation with some options set
6983 // using the "anim" property to get the Anim object
6989 el.setWidth(100, opt);
6991 if(opt.anim.isAnimated()){
6995 * <b> Composite (Collections of) Elements</b><br />
6996 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6997 * @constructor Create a new Element directly.
6998 * @param {String/HTMLElement} element
6999 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7001 Roo.Element = function(element, forceNew){
7002 var dom = typeof element == "string" ?
7003 document.getElementById(element) : element;
7004 if(!dom){ // invalid id/element
7008 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7009 return Roo.Element.cache[id];
7019 * The DOM element ID
7022 this.id = id || Roo.id(dom);
7025 var El = Roo.Element;
7029 * The element's default display mode (defaults to "")
7032 originalDisplay : "",
7036 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7041 * Sets the element's visibility mode. When setVisible() is called it
7042 * will use this to determine whether to set the visibility or the display property.
7043 * @param visMode Element.VISIBILITY or Element.DISPLAY
7044 * @return {Roo.Element} this
7046 setVisibilityMode : function(visMode){
7047 this.visibilityMode = visMode;
7051 * Convenience method for setVisibilityMode(Element.DISPLAY)
7052 * @param {String} display (optional) What to set display to when visible
7053 * @return {Roo.Element} this
7055 enableDisplayMode : function(display){
7056 this.setVisibilityMode(El.DISPLAY);
7057 if(typeof display != "undefined") this.originalDisplay = display;
7062 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7063 * @param {String} selector The simple selector to test
7064 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7065 search as a number or element (defaults to 10 || document.body)
7066 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7067 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7069 findParent : function(simpleSelector, maxDepth, returnEl){
7070 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7071 maxDepth = maxDepth || 50;
7072 if(typeof maxDepth != "number"){
7073 stopEl = Roo.getDom(maxDepth);
7076 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7077 if(dq.is(p, simpleSelector)){
7078 return returnEl ? Roo.get(p) : p;
7088 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7089 * @param {String} selector The simple selector to test
7090 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7091 search as a number or element (defaults to 10 || document.body)
7092 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7093 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7095 findParentNode : function(simpleSelector, maxDepth, returnEl){
7096 var p = Roo.fly(this.dom.parentNode, '_internal');
7097 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7101 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7102 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7103 * @param {String} selector The simple selector to test
7104 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7105 search as a number or element (defaults to 10 || document.body)
7106 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7108 up : function(simpleSelector, maxDepth){
7109 return this.findParentNode(simpleSelector, maxDepth, true);
7115 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7116 * @param {String} selector The simple selector to test
7117 * @return {Boolean} True if this element matches the selector, else false
7119 is : function(simpleSelector){
7120 return Roo.DomQuery.is(this.dom, simpleSelector);
7124 * Perform animation on this element.
7125 * @param {Object} args The YUI animation control args
7126 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7127 * @param {Function} onComplete (optional) Function to call when animation completes
7128 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7129 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7130 * @return {Roo.Element} this
7132 animate : function(args, duration, onComplete, easing, animType){
7133 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7138 * @private Internal animation call
7140 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7141 animType = animType || 'run';
7143 var anim = Roo.lib.Anim[animType](
7145 (opt.duration || defaultDur) || .35,
7146 (opt.easing || defaultEase) || 'easeOut',
7148 Roo.callback(cb, this);
7149 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7157 // private legacy anim prep
7158 preanim : function(a, i){
7159 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7163 * Removes worthless text nodes
7164 * @param {Boolean} forceReclean (optional) By default the element
7165 * keeps track if it has been cleaned already so
7166 * you can call this over and over. However, if you update the element and
7167 * need to force a reclean, you can pass true.
7169 clean : function(forceReclean){
7170 if(this.isCleaned && forceReclean !== true){
7174 var d = this.dom, n = d.firstChild, ni = -1;
7176 var nx = n.nextSibling;
7177 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7184 this.isCleaned = true;
7189 calcOffsetsTo : function(el){
7192 var restorePos = false;
7193 if(el.getStyle('position') == 'static'){
7194 el.position('relative');
7199 while(op && op != d && op.tagName != 'HTML'){
7202 op = op.offsetParent;
7205 el.position('static');
7211 * Scrolls this element into view within the passed container.
7212 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7213 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7214 * @return {Roo.Element} this
7216 scrollIntoView : function(container, hscroll){
7217 var c = Roo.getDom(container) || document.body;
7220 var o = this.calcOffsetsTo(c),
7223 b = t+el.offsetHeight,
7224 r = l+el.offsetWidth;
7226 var ch = c.clientHeight;
7227 var ct = parseInt(c.scrollTop, 10);
7228 var cl = parseInt(c.scrollLeft, 10);
7230 var cr = cl + c.clientWidth;
7238 if(hscroll !== false){
7242 c.scrollLeft = r-c.clientWidth;
7249 scrollChildIntoView : function(child, hscroll){
7250 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7254 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7255 * the new height may not be available immediately.
7256 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7257 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7258 * @param {Function} onComplete (optional) Function to call when animation completes
7259 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7260 * @return {Roo.Element} this
7262 autoHeight : function(animate, duration, onComplete, easing){
7263 var oldHeight = this.getHeight();
7265 this.setHeight(1); // force clipping
7266 setTimeout(function(){
7267 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7269 this.setHeight(height);
7271 if(typeof onComplete == "function"){
7275 this.setHeight(oldHeight); // restore original height
7276 this.setHeight(height, animate, duration, function(){
7278 if(typeof onComplete == "function") onComplete();
7279 }.createDelegate(this), easing);
7281 }.createDelegate(this), 0);
7286 * Returns true if this element is an ancestor of the passed element
7287 * @param {HTMLElement/String} el The element to check
7288 * @return {Boolean} True if this element is an ancestor of el, else false
7290 contains : function(el){
7291 if(!el){return false;}
7292 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7296 * Checks whether the element is currently visible using both visibility and display properties.
7297 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7298 * @return {Boolean} True if the element is currently visible, else false
7300 isVisible : function(deep) {
7301 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7302 if(deep !== true || !vis){
7305 var p = this.dom.parentNode;
7306 while(p && p.tagName.toLowerCase() != "body"){
7307 if(!Roo.fly(p, '_isVisible').isVisible()){
7316 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7317 * @param {String} selector The CSS selector
7318 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7319 * @return {CompositeElement/CompositeElementLite} The composite element
7321 select : function(selector, unique){
7322 return El.select(selector, unique, this.dom);
7326 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7327 * @param {String} selector The CSS selector
7328 * @return {Array} An array of the matched nodes
7330 query : function(selector, unique){
7331 return Roo.DomQuery.select(selector, this.dom);
7335 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7336 * @param {String} selector The CSS selector
7337 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7338 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7340 child : function(selector, returnDom){
7341 var n = Roo.DomQuery.selectNode(selector, this.dom);
7342 return returnDom ? n : Roo.get(n);
7346 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7347 * @param {String} selector The CSS selector
7348 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7349 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7351 down : function(selector, returnDom){
7352 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7353 return returnDom ? n : Roo.get(n);
7357 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7358 * @param {String} group The group the DD object is member of
7359 * @param {Object} config The DD config object
7360 * @param {Object} overrides An object containing methods to override/implement on the DD object
7361 * @return {Roo.dd.DD} The DD object
7363 initDD : function(group, config, overrides){
7364 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7365 return Roo.apply(dd, overrides);
7369 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7370 * @param {String} group The group the DDProxy object is member of
7371 * @param {Object} config The DDProxy config object
7372 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7373 * @return {Roo.dd.DDProxy} The DDProxy object
7375 initDDProxy : function(group, config, overrides){
7376 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7377 return Roo.apply(dd, overrides);
7381 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7382 * @param {String} group The group the DDTarget object is member of
7383 * @param {Object} config The DDTarget config object
7384 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7385 * @return {Roo.dd.DDTarget} The DDTarget object
7387 initDDTarget : function(group, config, overrides){
7388 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7389 return Roo.apply(dd, overrides);
7393 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7394 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7395 * @param {Boolean} visible Whether the element is visible
7396 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7397 * @return {Roo.Element} this
7399 setVisible : function(visible, animate){
7401 if(this.visibilityMode == El.DISPLAY){
7402 this.setDisplayed(visible);
7405 this.dom.style.visibility = visible ? "visible" : "hidden";
7408 // closure for composites
7410 var visMode = this.visibilityMode;
7412 this.setOpacity(.01);
7413 this.setVisible(true);
7415 this.anim({opacity: { to: (visible?1:0) }},
7416 this.preanim(arguments, 1),
7417 null, .35, 'easeIn', function(){
7419 if(visMode == El.DISPLAY){
7420 dom.style.display = "none";
7422 dom.style.visibility = "hidden";
7424 Roo.get(dom).setOpacity(1);
7432 * Returns true if display is not "none"
7435 isDisplayed : function() {
7436 return this.getStyle("display") != "none";
7440 * Toggles the element's visibility or display, depending on visibility mode.
7441 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7442 * @return {Roo.Element} this
7444 toggle : function(animate){
7445 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7450 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7451 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7452 * @return {Roo.Element} this
7454 setDisplayed : function(value) {
7455 if(typeof value == "boolean"){
7456 value = value ? this.originalDisplay : "none";
7458 this.setStyle("display", value);
7463 * Tries to focus the element. Any exceptions are caught and ignored.
7464 * @return {Roo.Element} this
7466 focus : function() {
7474 * Tries to blur the element. Any exceptions are caught and ignored.
7475 * @return {Roo.Element} this
7485 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7486 * @param {String/Array} className The CSS class to add, or an array of classes
7487 * @return {Roo.Element} this
7489 addClass : function(className){
7490 if(className instanceof Array){
7491 for(var i = 0, len = className.length; i < len; i++) {
7492 this.addClass(className[i]);
7495 if(className && !this.hasClass(className)){
7496 this.dom.className = this.dom.className + " " + className;
7503 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7504 * @param {String/Array} className The CSS class to add, or an array of classes
7505 * @return {Roo.Element} this
7507 radioClass : function(className){
7508 var siblings = this.dom.parentNode.childNodes;
7509 for(var i = 0; i < siblings.length; i++) {
7510 var s = siblings[i];
7511 if(s.nodeType == 1){
7512 Roo.get(s).removeClass(className);
7515 this.addClass(className);
7520 * Removes one or more CSS classes from the element.
7521 * @param {String/Array} className The CSS class to remove, or an array of classes
7522 * @return {Roo.Element} this
7524 removeClass : function(className){
7525 if(!className || !this.dom.className){
7528 if(className instanceof Array){
7529 for(var i = 0, len = className.length; i < len; i++) {
7530 this.removeClass(className[i]);
7533 if(this.hasClass(className)){
7534 var re = this.classReCache[className];
7536 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7537 this.classReCache[className] = re;
7539 this.dom.className =
7540 this.dom.className.replace(re, " ");
7550 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7551 * @param {String} className The CSS class to toggle
7552 * @return {Roo.Element} this
7554 toggleClass : function(className){
7555 if(this.hasClass(className)){
7556 this.removeClass(className);
7558 this.addClass(className);
7564 * Checks if the specified CSS class exists on this element's DOM node.
7565 * @param {String} className The CSS class to check for
7566 * @return {Boolean} True if the class exists, else false
7568 hasClass : function(className){
7569 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7573 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7574 * @param {String} oldClassName The CSS class to replace
7575 * @param {String} newClassName The replacement CSS class
7576 * @return {Roo.Element} this
7578 replaceClass : function(oldClassName, newClassName){
7579 this.removeClass(oldClassName);
7580 this.addClass(newClassName);
7585 * Returns an object with properties matching the styles requested.
7586 * For example, el.getStyles('color', 'font-size', 'width') might return
7587 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7588 * @param {String} style1 A style name
7589 * @param {String} style2 A style name
7590 * @param {String} etc.
7591 * @return {Object} The style object
7593 getStyles : function(){
7594 var a = arguments, len = a.length, r = {};
7595 for(var i = 0; i < len; i++){
7596 r[a[i]] = this.getStyle(a[i]);
7602 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7603 * @param {String} property The style property whose value is returned.
7604 * @return {String} The current value of the style property for this element.
7606 getStyle : function(){
7607 return view && view.getComputedStyle ?
7609 var el = this.dom, v, cs, camel;
7610 if(prop == 'float'){
7613 if(el.style && (v = el.style[prop])){
7616 if(cs = view.getComputedStyle(el, "")){
7617 if(!(camel = propCache[prop])){
7618 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7625 var el = this.dom, v, cs, camel;
7626 if(prop == 'opacity'){
7627 if(typeof el.style.filter == 'string'){
7628 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7630 var fv = parseFloat(m[1]);
7632 return fv ? fv / 100 : 0;
7637 }else if(prop == 'float'){
7638 prop = "styleFloat";
7640 if(!(camel = propCache[prop])){
7641 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7643 if(v = el.style[camel]){
7646 if(cs = el.currentStyle){
7654 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7655 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7656 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7657 * @return {Roo.Element} this
7659 setStyle : function(prop, value){
7660 if(typeof prop == "string"){
7662 if (prop == 'float') {
7663 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7668 if(!(camel = propCache[prop])){
7669 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7672 if(camel == 'opacity') {
7673 this.setOpacity(value);
7675 this.dom.style[camel] = value;
7678 for(var style in prop){
7679 if(typeof prop[style] != "function"){
7680 this.setStyle(style, prop[style]);
7688 * More flexible version of {@link #setStyle} for setting style properties.
7689 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7690 * a function which returns such a specification.
7691 * @return {Roo.Element} this
7693 applyStyles : function(style){
7694 Roo.DomHelper.applyStyles(this.dom, style);
7699 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7700 * @return {Number} The X position of the element
7703 return D.getX(this.dom);
7707 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7708 * @return {Number} The Y position of the element
7711 return D.getY(this.dom);
7715 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7716 * @return {Array} The XY position of the element
7719 return D.getXY(this.dom);
7723 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7724 * @param {Number} The X position of the element
7725 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7726 * @return {Roo.Element} this
7728 setX : function(x, animate){
7730 D.setX(this.dom, x);
7732 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7738 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Number} The Y position of the element
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setY : function(y, animate){
7745 D.setY(this.dom, y);
7747 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7753 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7754 * @param {String} left The left CSS property value
7755 * @return {Roo.Element} this
7757 setLeft : function(left){
7758 this.setStyle("left", this.addUnits(left));
7763 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7764 * @param {String} top The top CSS property value
7765 * @return {Roo.Element} this
7767 setTop : function(top){
7768 this.setStyle("top", this.addUnits(top));
7773 * Sets the element's CSS right style.
7774 * @param {String} right The right CSS property value
7775 * @return {Roo.Element} this
7777 setRight : function(right){
7778 this.setStyle("right", this.addUnits(right));
7783 * Sets the element's CSS bottom style.
7784 * @param {String} bottom The bottom CSS property value
7785 * @return {Roo.Element} this
7787 setBottom : function(bottom){
7788 this.setStyle("bottom", this.addUnits(bottom));
7793 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7794 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7795 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7796 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7797 * @return {Roo.Element} this
7799 setXY : function(pos, animate){
7801 D.setXY(this.dom, pos);
7803 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7809 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7810 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7811 * @param {Number} x X value for new position (coordinates are page-based)
7812 * @param {Number} y Y value for new position (coordinates are page-based)
7813 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7814 * @return {Roo.Element} this
7816 setLocation : function(x, y, animate){
7817 this.setXY([x, y], this.preanim(arguments, 2));
7822 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7823 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7824 * @param {Number} x X value for new position (coordinates are page-based)
7825 * @param {Number} y Y value for new position (coordinates are page-based)
7826 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7827 * @return {Roo.Element} this
7829 moveTo : function(x, y, animate){
7830 this.setXY([x, y], this.preanim(arguments, 2));
7835 * Returns the region of the given element.
7836 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7837 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7839 getRegion : function(){
7840 return D.getRegion(this.dom);
7844 * Returns the offset height of the element
7845 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7846 * @return {Number} The element's height
7848 getHeight : function(contentHeight){
7849 var h = this.dom.offsetHeight || 0;
7850 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7854 * Returns the offset width of the element
7855 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7856 * @return {Number} The element's width
7858 getWidth : function(contentWidth){
7859 var w = this.dom.offsetWidth || 0;
7860 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7864 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7865 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7866 * if a height has not been set using CSS.
7869 getComputedHeight : function(){
7870 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7872 h = parseInt(this.getStyle('height'), 10) || 0;
7873 if(!this.isBorderBox()){
7874 h += this.getFrameWidth('tb');
7881 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7882 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7883 * if a width has not been set using CSS.
7886 getComputedWidth : function(){
7887 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7889 w = parseInt(this.getStyle('width'), 10) || 0;
7890 if(!this.isBorderBox()){
7891 w += this.getFrameWidth('lr');
7898 * Returns the size of the element.
7899 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7900 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7902 getSize : function(contentSize){
7903 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7907 * Returns the width and height of the viewport.
7908 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7910 getViewSize : function(){
7911 var d = this.dom, doc = document, aw = 0, ah = 0;
7912 if(d == doc || d == doc.body){
7913 return {width : D.getViewWidth(), height: D.getViewHeight()};
7916 width : d.clientWidth,
7917 height: d.clientHeight
7923 * Returns the value of the "value" attribute
7924 * @param {Boolean} asNumber true to parse the value as a number
7925 * @return {String/Number}
7927 getValue : function(asNumber){
7928 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7932 adjustWidth : function(width){
7933 if(typeof width == "number"){
7934 if(this.autoBoxAdjust && !this.isBorderBox()){
7935 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7945 adjustHeight : function(height){
7946 if(typeof height == "number"){
7947 if(this.autoBoxAdjust && !this.isBorderBox()){
7948 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7958 * Set the width of the element
7959 * @param {Number} width The new width
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setWidth : function(width, animate){
7964 width = this.adjustWidth(width);
7966 this.dom.style.width = this.addUnits(width);
7968 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7974 * Set the height of the element
7975 * @param {Number} height The new height
7976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977 * @return {Roo.Element} this
7979 setHeight : function(height, animate){
7980 height = this.adjustHeight(height);
7982 this.dom.style.height = this.addUnits(height);
7984 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7990 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7991 * @param {Number} width The new width
7992 * @param {Number} height The new height
7993 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7994 * @return {Roo.Element} this
7996 setSize : function(width, height, animate){
7997 if(typeof width == "object"){ // in case of object from getSize()
7998 height = width.height; width = width.width;
8000 width = this.adjustWidth(width); height = this.adjustHeight(height);
8002 this.dom.style.width = this.addUnits(width);
8003 this.dom.style.height = this.addUnits(height);
8005 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8011 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8012 * @param {Number} x X value for new position (coordinates are page-based)
8013 * @param {Number} y Y value for new position (coordinates are page-based)
8014 * @param {Number} width The new width
8015 * @param {Number} height The new height
8016 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8017 * @return {Roo.Element} this
8019 setBounds : function(x, y, width, height, animate){
8021 this.setSize(width, height);
8022 this.setLocation(x, y);
8024 width = this.adjustWidth(width); height = this.adjustHeight(height);
8025 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8026 this.preanim(arguments, 4), 'motion');
8032 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8033 * @param {Roo.lib.Region} region The region to fill
8034 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8035 * @return {Roo.Element} this
8037 setRegion : function(region, animate){
8038 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8043 * Appends an event handler
8045 * @param {String} eventName The type of event to append
8046 * @param {Function} fn The method the event invokes
8047 * @param {Object} scope (optional) The scope (this object) of the fn
8048 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8050 addListener : function(eventName, fn, scope, options){
8052 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8057 * Removes an event handler from this element
8058 * @param {String} eventName the type of event to remove
8059 * @param {Function} fn the method the event invokes
8060 * @return {Roo.Element} this
8062 removeListener : function(eventName, fn){
8063 Roo.EventManager.removeListener(this.dom, eventName, fn);
8068 * Removes all previous added listeners from this element
8069 * @return {Roo.Element} this
8071 removeAllListeners : function(){
8072 E.purgeElement(this.dom);
8076 relayEvent : function(eventName, observable){
8077 this.on(eventName, function(e){
8078 observable.fireEvent(eventName, e);
8083 * Set the opacity of the element
8084 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8085 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8086 * @return {Roo.Element} this
8088 setOpacity : function(opacity, animate){
8090 var s = this.dom.style;
8093 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8094 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8096 s.opacity = opacity;
8099 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8105 * Gets the left X coordinate
8106 * @param {Boolean} local True to get the local css position instead of page coordinate
8109 getLeft : function(local){
8113 return parseInt(this.getStyle("left"), 10) || 0;
8118 * Gets the right X coordinate of the element (element X position + element width)
8119 * @param {Boolean} local True to get the local css position instead of page coordinate
8122 getRight : function(local){
8124 return this.getX() + this.getWidth();
8126 return (this.getLeft(true) + this.getWidth()) || 0;
8131 * Gets the top Y coordinate
8132 * @param {Boolean} local True to get the local css position instead of page coordinate
8135 getTop : function(local) {
8139 return parseInt(this.getStyle("top"), 10) || 0;
8144 * Gets the bottom Y coordinate of the element (element Y position + element height)
8145 * @param {Boolean} local True to get the local css position instead of page coordinate
8148 getBottom : function(local){
8150 return this.getY() + this.getHeight();
8152 return (this.getTop(true) + this.getHeight()) || 0;
8157 * Initializes positioning on this element. If a desired position is not passed, it will make the
8158 * the element positioned relative IF it is not already positioned.
8159 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8160 * @param {Number} zIndex (optional) The zIndex to apply
8161 * @param {Number} x (optional) Set the page X position
8162 * @param {Number} y (optional) Set the page Y position
8164 position : function(pos, zIndex, x, y){
8166 if(this.getStyle('position') == 'static'){
8167 this.setStyle('position', 'relative');
8170 this.setStyle("position", pos);
8173 this.setStyle("z-index", zIndex);
8175 if(x !== undefined && y !== undefined){
8177 }else if(x !== undefined){
8179 }else if(y !== undefined){
8185 * Clear positioning back to the default when the document was loaded
8186 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8187 * @return {Roo.Element} this
8189 clearPositioning : function(value){
8197 "position" : "static"
8203 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8204 * snapshot before performing an update and then restoring the element.
8207 getPositioning : function(){
8208 var l = this.getStyle("left");
8209 var t = this.getStyle("top");
8211 "position" : this.getStyle("position"),
8213 "right" : l ? "" : this.getStyle("right"),
8215 "bottom" : t ? "" : this.getStyle("bottom"),
8216 "z-index" : this.getStyle("z-index")
8221 * Gets the width of the border(s) for the specified side(s)
8222 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8223 * passing lr would get the border (l)eft width + the border (r)ight width.
8224 * @return {Number} The width of the sides passed added together
8226 getBorderWidth : function(side){
8227 return this.addStyles(side, El.borders);
8231 * Gets the width of the padding(s) for the specified side(s)
8232 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8233 * passing lr would get the padding (l)eft + the padding (r)ight.
8234 * @return {Number} The padding of the sides passed added together
8236 getPadding : function(side){
8237 return this.addStyles(side, El.paddings);
8241 * Set positioning with an object returned by getPositioning().
8242 * @param {Object} posCfg
8243 * @return {Roo.Element} this
8245 setPositioning : function(pc){
8246 this.applyStyles(pc);
8247 if(pc.right == "auto"){
8248 this.dom.style.right = "";
8250 if(pc.bottom == "auto"){
8251 this.dom.style.bottom = "";
8257 fixDisplay : function(){
8258 if(this.getStyle("display") == "none"){
8259 this.setStyle("visibility", "hidden");
8260 this.setStyle("display", this.originalDisplay); // first try reverting to default
8261 if(this.getStyle("display") == "none"){ // if that fails, default to block
8262 this.setStyle("display", "block");
8268 * Quick set left and top adding default units
8269 * @param {String} left The left CSS property value
8270 * @param {String} top The top CSS property value
8271 * @return {Roo.Element} this
8273 setLeftTop : function(left, top){
8274 this.dom.style.left = this.addUnits(left);
8275 this.dom.style.top = this.addUnits(top);
8280 * Move this element relative to its current position.
8281 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8282 * @param {Number} distance How far to move the element in pixels
8283 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8284 * @return {Roo.Element} this
8286 move : function(direction, distance, animate){
8287 var xy = this.getXY();
8288 direction = direction.toLowerCase();
8292 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8296 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8301 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8306 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8313 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8314 * @return {Roo.Element} this
8317 if(!this.isClipped){
8318 this.isClipped = true;
8319 this.originalClip = {
8320 "o": this.getStyle("overflow"),
8321 "x": this.getStyle("overflow-x"),
8322 "y": this.getStyle("overflow-y")
8324 this.setStyle("overflow", "hidden");
8325 this.setStyle("overflow-x", "hidden");
8326 this.setStyle("overflow-y", "hidden");
8332 * Return clipping (overflow) to original clipping before clip() was called
8333 * @return {Roo.Element} this
8335 unclip : function(){
8337 this.isClipped = false;
8338 var o = this.originalClip;
8339 if(o.o){this.setStyle("overflow", o.o);}
8340 if(o.x){this.setStyle("overflow-x", o.x);}
8341 if(o.y){this.setStyle("overflow-y", o.y);}
8348 * Gets the x,y coordinates specified by the anchor position on the element.
8349 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8350 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8351 * {width: (target width), height: (target height)} (defaults to the element's current size)
8352 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8353 * @return {Array} [x, y] An array containing the element's x and y coordinates
8355 getAnchorXY : function(anchor, local, s){
8356 //Passing a different size is useful for pre-calculating anchors,
8357 //especially for anchored animations that change the el size.
8359 var w, h, vp = false;
8362 if(d == document.body || d == document){
8364 w = D.getViewWidth(); h = D.getViewHeight();
8366 w = this.getWidth(); h = this.getHeight();
8369 w = s.width; h = s.height;
8371 var x = 0, y = 0, r = Math.round;
8372 switch((anchor || "tl").toLowerCase()){
8414 var sc = this.getScroll();
8415 return [x + sc.left, y + sc.top];
8417 //Add the element's offset xy
8418 var o = this.getXY();
8419 return [x+o[0], y+o[1]];
8423 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8424 * supported position values.
8425 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8426 * @param {String} position The position to align to.
8427 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8428 * @return {Array} [x, y]
8430 getAlignToXY : function(el, p, o){
8434 throw "Element.alignTo with an element that doesn't exist";
8436 var c = false; //constrain to viewport
8437 var p1 = "", p2 = "";
8444 }else if(p.indexOf("-") == -1){
8447 p = p.toLowerCase();
8448 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8450 throw "Element.alignTo with an invalid alignment " + p;
8452 p1 = m[1]; p2 = m[2]; c = !!m[3];
8454 //Subtract the aligned el's internal xy from the target's offset xy
8455 //plus custom offset to get the aligned el's new offset xy
8456 var a1 = this.getAnchorXY(p1, true);
8457 var a2 = el.getAnchorXY(p2, false);
8458 var x = a2[0] - a1[0] + o[0];
8459 var y = a2[1] - a1[1] + o[1];
8461 //constrain the aligned el to viewport if necessary
8462 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8463 // 5px of margin for ie
8464 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8466 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8467 //perpendicular to the vp border, allow the aligned el to slide on that border,
8468 //otherwise swap the aligned el to the opposite border of the target.
8469 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8470 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8471 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8472 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8475 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8476 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8478 if((x+w) > dw + scrollX){
8479 x = swapX ? r.left-w : dw+scrollX-w;
8482 x = swapX ? r.right : scrollX;
8484 if((y+h) > dh + scrollY){
8485 y = swapY ? r.top-h : dh+scrollY-h;
8488 y = swapY ? r.bottom : scrollY;
8495 getConstrainToXY : function(){
8496 var os = {top:0, left:0, bottom:0, right: 0};
8498 return function(el, local, offsets, proposedXY){
8500 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8502 var vw, vh, vx = 0, vy = 0;
8503 if(el.dom == document.body || el.dom == document){
8504 vw = Roo.lib.Dom.getViewWidth();
8505 vh = Roo.lib.Dom.getViewHeight();
8507 vw = el.dom.clientWidth;
8508 vh = el.dom.clientHeight;
8510 var vxy = el.getXY();
8516 var s = el.getScroll();
8518 vx += offsets.left + s.left;
8519 vy += offsets.top + s.top;
8521 vw -= offsets.right;
8522 vh -= offsets.bottom;
8527 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8528 var x = xy[0], y = xy[1];
8529 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8531 // only move it if it needs it
8534 // first validate right/bottom
8543 // then make sure top/left isn't negative
8552 return moved ? [x, y] : false;
8557 adjustForConstraints : function(xy, parent, offsets){
8558 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8562 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8563 * document it aligns it to the viewport.
8564 * The position parameter is optional, and can be specified in any one of the following formats:
8566 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8567 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8568 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8569 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8570 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8571 * element's anchor point, and the second value is used as the target's anchor point.</li>
8573 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8574 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8575 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8576 * that specified in order to enforce the viewport constraints.
8577 * Following are all of the supported anchor positions:
8580 ----- -----------------------------
8581 tl The top left corner (default)
8582 t The center of the top edge
8583 tr The top right corner
8584 l The center of the left edge
8585 c In the center of the element
8586 r The center of the right edge
8587 bl The bottom left corner
8588 b The center of the bottom edge
8589 br The bottom right corner
8593 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8594 el.alignTo("other-el");
8596 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8597 el.alignTo("other-el", "tr?");
8599 // align the bottom right corner of el with the center left edge of other-el
8600 el.alignTo("other-el", "br-l?");
8602 // align the center of el with the bottom left corner of other-el and
8603 // adjust the x position by -6 pixels (and the y position by 0)
8604 el.alignTo("other-el", "c-bl", [-6, 0]);
8606 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8607 * @param {String} position The position to align to.
8608 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8609 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8610 * @return {Roo.Element} this
8612 alignTo : function(element, position, offsets, animate){
8613 var xy = this.getAlignToXY(element, position, offsets);
8614 this.setXY(xy, this.preanim(arguments, 3));
8619 * Anchors an element to another element and realigns it when the window is resized.
8620 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8621 * @param {String} position The position to align to.
8622 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8623 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8624 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8625 * is a number, it is used as the buffer delay (defaults to 50ms).
8626 * @param {Function} callback The function to call after the animation finishes
8627 * @return {Roo.Element} this
8629 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8630 var action = function(){
8631 this.alignTo(el, alignment, offsets, animate);
8632 Roo.callback(callback, this);
8634 Roo.EventManager.onWindowResize(action, this);
8635 var tm = typeof monitorScroll;
8636 if(tm != 'undefined'){
8637 Roo.EventManager.on(window, 'scroll', action, this,
8638 {buffer: tm == 'number' ? monitorScroll : 50});
8640 action.call(this); // align immediately
8644 * Clears any opacity settings from this element. Required in some cases for IE.
8645 * @return {Roo.Element} this
8647 clearOpacity : function(){
8648 if (window.ActiveXObject) {
8649 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8650 this.dom.style.filter = "";
8653 this.dom.style.opacity = "";
8654 this.dom.style["-moz-opacity"] = "";
8655 this.dom.style["-khtml-opacity"] = "";
8661 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8662 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8663 * @return {Roo.Element} this
8665 hide : function(animate){
8666 this.setVisible(false, this.preanim(arguments, 0));
8671 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8672 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8673 * @return {Roo.Element} this
8675 show : function(animate){
8676 this.setVisible(true, this.preanim(arguments, 0));
8681 * @private Test if size has a unit, otherwise appends the default
8683 addUnits : function(size){
8684 return Roo.Element.addUnits(size, this.defaultUnit);
8688 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8689 * @return {Roo.Element} this
8691 beginMeasure : function(){
8693 if(el.offsetWidth || el.offsetHeight){
8694 return this; // offsets work already
8697 var p = this.dom, b = document.body; // start with this element
8698 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8699 var pe = Roo.get(p);
8700 if(pe.getStyle('display') == 'none'){
8701 changed.push({el: p, visibility: pe.getStyle("visibility")});
8702 p.style.visibility = "hidden";
8703 p.style.display = "block";
8707 this._measureChanged = changed;
8713 * Restores displays to before beginMeasure was called
8714 * @return {Roo.Element} this
8716 endMeasure : function(){
8717 var changed = this._measureChanged;
8719 for(var i = 0, len = changed.length; i < len; i++) {
8721 r.el.style.visibility = r.visibility;
8722 r.el.style.display = "none";
8724 this._measureChanged = null;
8730 * Update the innerHTML of this element, optionally searching for and processing scripts
8731 * @param {String} html The new HTML
8732 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8733 * @param {Function} callback For async script loading you can be noticed when the update completes
8734 * @return {Roo.Element} this
8736 update : function(html, loadScripts, callback){
8737 if(typeof html == "undefined"){
8740 if(loadScripts !== true){
8741 this.dom.innerHTML = html;
8742 if(typeof callback == "function"){
8750 html += '<span id="' + id + '"></span>';
8752 E.onAvailable(id, function(){
8753 var hd = document.getElementsByTagName("head")[0];
8754 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8755 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8756 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8759 while(match = re.exec(html)){
8760 var attrs = match[1];
8761 var srcMatch = attrs ? attrs.match(srcRe) : false;
8762 if(srcMatch && srcMatch[2]){
8763 var s = document.createElement("script");
8764 s.src = srcMatch[2];
8765 var typeMatch = attrs.match(typeRe);
8766 if(typeMatch && typeMatch[2]){
8767 s.type = typeMatch[2];
8770 }else if(match[2] && match[2].length > 0){
8771 if(window.execScript) {
8772 window.execScript(match[2]);
8780 window.eval(match[2]);
8784 var el = document.getElementById(id);
8785 if(el){el.parentNode.removeChild(el);}
8786 if(typeof callback == "function"){
8790 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8795 * Direct access to the UpdateManager update() method (takes the same parameters).
8796 * @param {String/Function} url The url for this request or a function to call to get the url
8797 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8798 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8799 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8800 * @return {Roo.Element} this
8803 var um = this.getUpdateManager();
8804 um.update.apply(um, arguments);
8809 * Gets this element's UpdateManager
8810 * @return {Roo.UpdateManager} The UpdateManager
8812 getUpdateManager : function(){
8813 if(!this.updateManager){
8814 this.updateManager = new Roo.UpdateManager(this);
8816 return this.updateManager;
8820 * Disables text selection for this element (normalized across browsers)
8821 * @return {Roo.Element} this
8823 unselectable : function(){
8824 this.dom.unselectable = "on";
8825 this.swallowEvent("selectstart", true);
8826 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8827 this.addClass("x-unselectable");
8832 * Calculates the x, y to center this element on the screen
8833 * @return {Array} The x, y values [x, y]
8835 getCenterXY : function(){
8836 return this.getAlignToXY(document, 'c-c');
8840 * Centers the Element in either the viewport, or another Element.
8841 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8843 center : function(centerIn){
8844 this.alignTo(centerIn || document, 'c-c');
8849 * Tests various css rules/browsers to determine if this element uses a border box
8852 isBorderBox : function(){
8853 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8857 * Return a box {x, y, width, height} that can be used to set another elements
8858 * size/location to match this element.
8859 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8860 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8861 * @return {Object} box An object in the format {x, y, width, height}
8863 getBox : function(contentBox, local){
8868 var left = parseInt(this.getStyle("left"), 10) || 0;
8869 var top = parseInt(this.getStyle("top"), 10) || 0;
8872 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8874 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8876 var l = this.getBorderWidth("l")+this.getPadding("l");
8877 var r = this.getBorderWidth("r")+this.getPadding("r");
8878 var t = this.getBorderWidth("t")+this.getPadding("t");
8879 var b = this.getBorderWidth("b")+this.getPadding("b");
8880 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8882 bx.right = bx.x + bx.width;
8883 bx.bottom = bx.y + bx.height;
8888 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8889 for more information about the sides.
8890 * @param {String} sides
8893 getFrameWidth : function(sides, onlyContentBox){
8894 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8898 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8899 * @param {Object} box The box to fill {x, y, width, height}
8900 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8901 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8902 * @return {Roo.Element} this
8904 setBox : function(box, adjust, animate){
8905 var w = box.width, h = box.height;
8906 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8907 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8908 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8910 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8915 * Forces the browser to repaint this element
8916 * @return {Roo.Element} this
8918 repaint : function(){
8920 this.addClass("x-repaint");
8921 setTimeout(function(){
8922 Roo.get(dom).removeClass("x-repaint");
8928 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8929 * then it returns the calculated width of the sides (see getPadding)
8930 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8931 * @return {Object/Number}
8933 getMargins : function(side){
8936 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8937 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8938 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8939 right: parseInt(this.getStyle("margin-right"), 10) || 0
8942 return this.addStyles(side, El.margins);
8947 addStyles : function(sides, styles){
8949 for(var i = 0, len = sides.length; i < len; i++){
8950 v = this.getStyle(styles[sides.charAt(i)]);
8952 w = parseInt(v, 10);
8960 * Creates a proxy element of this element
8961 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8962 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8963 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8964 * @return {Roo.Element} The new proxy element
8966 createProxy : function(config, renderTo, matchBox){
8968 renderTo = Roo.getDom(renderTo);
8970 renderTo = document.body;
8972 config = typeof config == "object" ?
8973 config : {tag : "div", cls: config};
8974 var proxy = Roo.DomHelper.append(renderTo, config, true);
8976 proxy.setBox(this.getBox());
8982 * Puts a mask over this element to disable user interaction. Requires core.css.
8983 * This method can only be applied to elements which accept child nodes.
8984 * @param {String} msg (optional) A message to display in the mask
8985 * @param {String} msgCls (optional) A css class to apply to the msg element
8986 * @return {Element} The mask element
8988 mask : function(msg, msgCls)
8990 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8991 this.setStyle("position", "relative");
8994 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8996 this.addClass("x-masked");
8997 this._mask.setDisplayed(true);
9002 while (dom && dom.style) {
9003 if (!isNaN(parseInt(dom.style.zIndex))) {
9004 z = Math.max(z, parseInt(dom.style.zIndex));
9006 dom = dom.parentNode;
9008 // if we are masking the body - then it hides everything..
9009 if (this.dom == document.body) {
9011 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9012 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9015 if(typeof msg == 'string'){
9017 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9019 var mm = this._maskMsg;
9020 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9021 if (mm.dom.firstChild) { // weird IE issue?
9022 mm.dom.firstChild.innerHTML = msg;
9024 mm.setDisplayed(true);
9026 mm.setStyle('z-index', z + 102);
9028 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9029 this._mask.setHeight(this.getHeight());
9031 this._mask.setStyle('z-index', z + 100);
9037 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9038 * it is cached for reuse.
9040 unmask : function(removeEl){
9042 if(removeEl === true){
9043 this._mask.remove();
9046 this._maskMsg.remove();
9047 delete this._maskMsg;
9050 this._mask.setDisplayed(false);
9052 this._maskMsg.setDisplayed(false);
9056 this.removeClass("x-masked");
9060 * Returns true if this element is masked
9063 isMasked : function(){
9064 return this._mask && this._mask.isVisible();
9068 * Creates an iframe shim for this element to keep selects and other windowed objects from
9070 * @return {Roo.Element} The new shim element
9072 createShim : function(){
9073 var el = document.createElement('iframe');
9074 el.frameBorder = 'no';
9075 el.className = 'roo-shim';
9076 if(Roo.isIE && Roo.isSecure){
9077 el.src = Roo.SSL_SECURE_URL;
9079 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9080 shim.autoBoxAdjust = false;
9085 * Removes this element from the DOM and deletes it from the cache
9087 remove : function(){
9088 if(this.dom.parentNode){
9089 this.dom.parentNode.removeChild(this.dom);
9091 delete El.cache[this.dom.id];
9095 * Sets up event handlers to add and remove a css class when the mouse is over this element
9096 * @param {String} className
9097 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9098 * mouseout events for children elements
9099 * @return {Roo.Element} this
9101 addClassOnOver : function(className, preventFlicker){
9102 this.on("mouseover", function(){
9103 Roo.fly(this, '_internal').addClass(className);
9105 var removeFn = function(e){
9106 if(preventFlicker !== true || !e.within(this, true)){
9107 Roo.fly(this, '_internal').removeClass(className);
9110 this.on("mouseout", removeFn, this.dom);
9115 * Sets up event handlers to add and remove a css class when this element has the focus
9116 * @param {String} className
9117 * @return {Roo.Element} this
9119 addClassOnFocus : function(className){
9120 this.on("focus", function(){
9121 Roo.fly(this, '_internal').addClass(className);
9123 this.on("blur", function(){
9124 Roo.fly(this, '_internal').removeClass(className);
9129 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9130 * @param {String} className
9131 * @return {Roo.Element} this
9133 addClassOnClick : function(className){
9135 this.on("mousedown", function(){
9136 Roo.fly(dom, '_internal').addClass(className);
9137 var d = Roo.get(document);
9138 var fn = function(){
9139 Roo.fly(dom, '_internal').removeClass(className);
9140 d.removeListener("mouseup", fn);
9142 d.on("mouseup", fn);
9148 * Stops the specified event from bubbling and optionally prevents the default action
9149 * @param {String} eventName
9150 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9151 * @return {Roo.Element} this
9153 swallowEvent : function(eventName, preventDefault){
9154 var fn = function(e){
9155 e.stopPropagation();
9160 if(eventName instanceof Array){
9161 for(var i = 0, len = eventName.length; i < len; i++){
9162 this.on(eventName[i], fn);
9166 this.on(eventName, fn);
9173 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9176 * Sizes this element to its parent element's dimensions performing
9177 * neccessary box adjustments.
9178 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9179 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9180 * @return {Roo.Element} this
9182 fitToParent : function(monitorResize, targetParent) {
9183 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9184 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9185 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9188 var p = Roo.get(targetParent || this.dom.parentNode);
9189 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9190 if (monitorResize === true) {
9191 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9192 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9198 * Gets the next sibling, skipping text nodes
9199 * @return {HTMLElement} The next sibling or null
9201 getNextSibling : function(){
9202 var n = this.dom.nextSibling;
9203 while(n && n.nodeType != 1){
9210 * Gets the previous sibling, skipping text nodes
9211 * @return {HTMLElement} The previous sibling or null
9213 getPrevSibling : function(){
9214 var n = this.dom.previousSibling;
9215 while(n && n.nodeType != 1){
9216 n = n.previousSibling;
9223 * Appends the passed element(s) to this element
9224 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9225 * @return {Roo.Element} this
9227 appendChild: function(el){
9234 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9235 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9236 * automatically generated with the specified attributes.
9237 * @param {HTMLElement} insertBefore (optional) a child element of this element
9238 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9239 * @return {Roo.Element} The new child element
9241 createChild: function(config, insertBefore, returnDom){
9242 config = config || {tag:'div'};
9244 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9246 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9250 * Appends this element to the passed element
9251 * @param {String/HTMLElement/Element} el The new parent element
9252 * @return {Roo.Element} this
9254 appendTo: function(el){
9255 el = Roo.getDom(el);
9256 el.appendChild(this.dom);
9261 * Inserts this element before the passed element in the DOM
9262 * @param {String/HTMLElement/Element} el The element to insert before
9263 * @return {Roo.Element} this
9265 insertBefore: function(el){
9266 el = Roo.getDom(el);
9267 el.parentNode.insertBefore(this.dom, el);
9272 * Inserts this element after the passed element in the DOM
9273 * @param {String/HTMLElement/Element} el The element to insert after
9274 * @return {Roo.Element} this
9276 insertAfter: function(el){
9277 el = Roo.getDom(el);
9278 el.parentNode.insertBefore(this.dom, el.nextSibling);
9283 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9284 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9285 * @return {Roo.Element} The new child
9287 insertFirst: function(el, returnDom){
9289 if(typeof el == 'object' && !el.nodeType){ // dh config
9290 return this.createChild(el, this.dom.firstChild, returnDom);
9292 el = Roo.getDom(el);
9293 this.dom.insertBefore(el, this.dom.firstChild);
9294 return !returnDom ? Roo.get(el) : el;
9299 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9300 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9301 * @param {String} where (optional) 'before' or 'after' defaults to before
9302 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9303 * @return {Roo.Element} the inserted Element
9305 insertSibling: function(el, where, returnDom){
9306 where = where ? where.toLowerCase() : 'before';
9308 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9310 if(typeof el == 'object' && !el.nodeType){ // dh config
9311 if(where == 'after' && !this.dom.nextSibling){
9312 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9314 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9318 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9319 where == 'before' ? this.dom : this.dom.nextSibling);
9328 * Creates and wraps this element with another element
9329 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9330 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9331 * @return {HTMLElement/Element} The newly created wrapper element
9333 wrap: function(config, returnDom){
9335 config = {tag: "div"};
9337 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9338 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9343 * Replaces the passed element with this element
9344 * @param {String/HTMLElement/Element} el The element to replace
9345 * @return {Roo.Element} this
9347 replace: function(el){
9349 this.insertBefore(el);
9355 * Inserts an html fragment into this element
9356 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9357 * @param {String} html The HTML fragment
9358 * @param {Boolean} returnEl True to return an Roo.Element
9359 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9361 insertHtml : function(where, html, returnEl){
9362 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9363 return returnEl ? Roo.get(el) : el;
9367 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9368 * @param {Object} o The object with the attributes
9369 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9370 * @return {Roo.Element} this
9372 set : function(o, useSet){
9374 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9376 if(attr == "style" || typeof o[attr] == "function") continue;
9378 el.className = o["cls"];
9380 if(useSet) el.setAttribute(attr, o[attr]);
9381 else el[attr] = o[attr];
9385 Roo.DomHelper.applyStyles(el, o.style);
9391 * Convenience method for constructing a KeyMap
9392 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9393 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9394 * @param {Function} fn The function to call
9395 * @param {Object} scope (optional) The scope of the function
9396 * @return {Roo.KeyMap} The KeyMap created
9398 addKeyListener : function(key, fn, scope){
9400 if(typeof key != "object" || key instanceof Array){
9416 return new Roo.KeyMap(this, config);
9420 * Creates a KeyMap for this element
9421 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9422 * @return {Roo.KeyMap} The KeyMap created
9424 addKeyMap : function(config){
9425 return new Roo.KeyMap(this, config);
9429 * Returns true if this element is scrollable.
9432 isScrollable : function(){
9434 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9438 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9439 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9440 * @param {Number} value The new scroll value
9441 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9442 * @return {Element} this
9445 scrollTo : function(side, value, animate){
9446 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9448 this.dom[prop] = value;
9450 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9451 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9457 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9458 * within this element's scrollable range.
9459 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9460 * @param {Number} distance How far to scroll the element in pixels
9461 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9462 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9463 * was scrolled as far as it could go.
9465 scroll : function(direction, distance, animate){
9466 if(!this.isScrollable()){
9470 var l = el.scrollLeft, t = el.scrollTop;
9471 var w = el.scrollWidth, h = el.scrollHeight;
9472 var cw = el.clientWidth, ch = el.clientHeight;
9473 direction = direction.toLowerCase();
9474 var scrolled = false;
9475 var a = this.preanim(arguments, 2);
9480 var v = Math.min(l + distance, w-cw);
9481 this.scrollTo("left", v, a);
9488 var v = Math.max(l - distance, 0);
9489 this.scrollTo("left", v, a);
9497 var v = Math.max(t - distance, 0);
9498 this.scrollTo("top", v, a);
9506 var v = Math.min(t + distance, h-ch);
9507 this.scrollTo("top", v, a);
9516 * Translates the passed page coordinates into left/top css values for this element
9517 * @param {Number/Array} x The page x or an array containing [x, y]
9518 * @param {Number} y The page y
9519 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9521 translatePoints : function(x, y){
9522 if(typeof x == 'object' || x instanceof Array){
9525 var p = this.getStyle('position');
9526 var o = this.getXY();
9528 var l = parseInt(this.getStyle('left'), 10);
9529 var t = parseInt(this.getStyle('top'), 10);
9532 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9535 t = (p == "relative") ? 0 : this.dom.offsetTop;
9538 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9542 * Returns the current scroll position of the element.
9543 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9545 getScroll : function(){
9546 var d = this.dom, doc = document;
9547 if(d == doc || d == doc.body){
9548 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9549 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9550 return {left: l, top: t};
9552 return {left: d.scrollLeft, top: d.scrollTop};
9557 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9558 * are convert to standard 6 digit hex color.
9559 * @param {String} attr The css attribute
9560 * @param {String} defaultValue The default value to use when a valid color isn't found
9561 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9564 getColor : function(attr, defaultValue, prefix){
9565 var v = this.getStyle(attr);
9566 if(!v || v == "transparent" || v == "inherit") {
9567 return defaultValue;
9569 var color = typeof prefix == "undefined" ? "#" : prefix;
9570 if(v.substr(0, 4) == "rgb("){
9571 var rvs = v.slice(4, v.length -1).split(",");
9572 for(var i = 0; i < 3; i++){
9573 var h = parseInt(rvs[i]).toString(16);
9580 if(v.substr(0, 1) == "#"){
9582 for(var i = 1; i < 4; i++){
9583 var c = v.charAt(i);
9586 }else if(v.length == 7){
9587 color += v.substr(1);
9591 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9595 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9596 * gradient background, rounded corners and a 4-way shadow.
9597 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9598 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9599 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9600 * @return {Roo.Element} this
9602 boxWrap : function(cls){
9603 cls = cls || 'x-box';
9604 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9605 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9610 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9611 * @param {String} namespace The namespace in which to look for the attribute
9612 * @param {String} name The attribute name
9613 * @return {String} The attribute value
9615 getAttributeNS : Roo.isIE ? function(ns, name){
9617 var type = typeof d[ns+":"+name];
9618 if(type != 'undefined' && type != 'unknown'){
9619 return d[ns+":"+name];
9622 } : function(ns, name){
9624 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9629 * Sets or Returns the value the dom attribute value
9630 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9631 * @param {String} value (optional) The value to set the attribute to
9632 * @return {String} The attribute value
9634 attr : function(name){
9635 if (arguments.length > 1) {
9636 this.dom.setAttribute(name, arguments[1]);
9637 return arguments[1];
9639 if (typeof(name) == 'object') {
9640 for(var i in name) {
9641 this.attr(i, name[i]);
9647 if (!this.dom.hasAttribute(name)) {
9650 return this.dom.getAttribute(name);
9657 var ep = El.prototype;
9660 * Appends an event handler (Shorthand for addListener)
9661 * @param {String} eventName The type of event to append
9662 * @param {Function} fn The method the event invokes
9663 * @param {Object} scope (optional) The scope (this object) of the fn
9664 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9667 ep.on = ep.addListener;
9669 ep.mon = ep.addListener;
9672 * Removes an event handler from this element (shorthand for removeListener)
9673 * @param {String} eventName the type of event to remove
9674 * @param {Function} fn the method the event invokes
9675 * @return {Roo.Element} this
9678 ep.un = ep.removeListener;
9681 * true to automatically adjust width and height settings for box-model issues (default to true)
9683 ep.autoBoxAdjust = true;
9686 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9689 El.addUnits = function(v, defaultUnit){
9690 if(v === "" || v == "auto"){
9693 if(v === undefined){
9696 if(typeof v == "number" || !El.unitPattern.test(v)){
9697 return v + (defaultUnit || 'px');
9702 // special markup used throughout Roo when box wrapping elements
9703 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9705 * Visibility mode constant - Use visibility to hide element
9711 * Visibility mode constant - Use display to hide element
9717 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9718 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9719 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9731 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9732 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9733 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9734 * @return {Element} The Element object
9737 El.get = function(el){
9739 if(!el){ return null; }
9740 if(typeof el == "string"){ // element id
9741 if(!(elm = document.getElementById(el))){
9744 if(ex = El.cache[el]){
9747 ex = El.cache[el] = new El(elm);
9750 }else if(el.tagName){ // dom element
9754 if(ex = El.cache[id]){
9757 ex = El.cache[id] = new El(el);
9760 }else if(el instanceof El){
9762 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9763 // catch case where it hasn't been appended
9764 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9767 }else if(el.isComposite){
9769 }else if(el instanceof Array){
9770 return El.select(el);
9771 }else if(el == document){
9772 // create a bogus element object representing the document object
9774 var f = function(){};
9775 f.prototype = El.prototype;
9777 docEl.dom = document;
9785 El.uncache = function(el){
9786 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9788 delete El.cache[a[i].id || a[i]];
9794 // Garbage collection - uncache elements/purge listeners on orphaned elements
9795 // so we don't hold a reference and cause the browser to retain them
9796 El.garbageCollect = function(){
9797 if(!Roo.enableGarbageCollector){
9798 clearInterval(El.collectorThread);
9801 for(var eid in El.cache){
9802 var el = El.cache[eid], d = el.dom;
9803 // -------------------------------------------------------
9804 // Determining what is garbage:
9805 // -------------------------------------------------------
9807 // dom node is null, definitely garbage
9808 // -------------------------------------------------------
9810 // no parentNode == direct orphan, definitely garbage
9811 // -------------------------------------------------------
9812 // !d.offsetParent && !document.getElementById(eid)
9813 // display none elements have no offsetParent so we will
9814 // also try to look it up by it's id. However, check
9815 // offsetParent first so we don't do unneeded lookups.
9816 // This enables collection of elements that are not orphans
9817 // directly, but somewhere up the line they have an orphan
9819 // -------------------------------------------------------
9820 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9821 delete El.cache[eid];
9822 if(d && Roo.enableListenerCollection){
9828 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9832 El.Flyweight = function(dom){
9835 El.Flyweight.prototype = El.prototype;
9837 El._flyweights = {};
9839 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9840 * the dom node can be overwritten by other code.
9841 * @param {String/HTMLElement} el The dom node or id
9842 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9843 * prevent conflicts (e.g. internally Roo uses "_internal")
9845 * @return {Element} The shared Element object
9847 El.fly = function(el, named){
9848 named = named || '_global';
9849 el = Roo.getDom(el);
9853 if(!El._flyweights[named]){
9854 El._flyweights[named] = new El.Flyweight();
9856 El._flyweights[named].dom = el;
9857 return El._flyweights[named];
9861 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9862 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9863 * Shorthand of {@link Roo.Element#get}
9864 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9865 * @return {Element} The Element object
9871 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9872 * the dom node can be overwritten by other code.
9873 * Shorthand of {@link Roo.Element#fly}
9874 * @param {String/HTMLElement} el The dom node or id
9875 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9876 * prevent conflicts (e.g. internally Roo uses "_internal")
9878 * @return {Element} The shared Element object
9884 // speedy lookup for elements never to box adjust
9885 var noBoxAdjust = Roo.isStrict ? {
9888 input:1, select:1, textarea:1
9890 if(Roo.isIE || Roo.isGecko){
9891 noBoxAdjust['button'] = 1;
9895 Roo.EventManager.on(window, 'unload', function(){
9897 delete El._flyweights;
9905 Roo.Element.selectorFunction = Roo.DomQuery.select;
9908 Roo.Element.select = function(selector, unique, root){
9910 if(typeof selector == "string"){
9911 els = Roo.Element.selectorFunction(selector, root);
9912 }else if(selector.length !== undefined){
9915 throw "Invalid selector";
9917 if(unique === true){
9918 return new Roo.CompositeElement(els);
9920 return new Roo.CompositeElementLite(els);
9924 * Selects elements based on the passed CSS selector to enable working on them as 1.
9925 * @param {String/Array} selector The CSS selector or an array of elements
9926 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9927 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9928 * @return {CompositeElementLite/CompositeElement}
9932 Roo.select = Roo.Element.select;
9949 * Ext JS Library 1.1.1
9950 * Copyright(c) 2006-2007, Ext JS, LLC.
9952 * Originally Released Under LGPL - original licence link has changed is not relivant.
9955 * <script type="text/javascript">
9960 //Notifies Element that fx methods are available
9961 Roo.enableFx = true;
9965 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9966 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9967 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9968 * Element effects to work.</p><br/>
9970 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9971 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9972 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9973 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9974 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9975 * expected results and should be done with care.</p><br/>
9977 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9978 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9981 ----- -----------------------------
9982 tl The top left corner
9983 t The center of the top edge
9984 tr The top right corner
9985 l The center of the left edge
9986 r The center of the right edge
9987 bl The bottom left corner
9988 b The center of the bottom edge
9989 br The bottom right corner
9991 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9992 * below are common options that can be passed to any Fx method.</b>
9993 * @cfg {Function} callback A function called when the effect is finished
9994 * @cfg {Object} scope The scope of the effect function
9995 * @cfg {String} easing A valid Easing value for the effect
9996 * @cfg {String} afterCls A css class to apply after the effect
9997 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9998 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9999 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10000 * effects that end with the element being visually hidden, ignored otherwise)
10001 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10002 * a function which returns such a specification that will be applied to the Element after the effect finishes
10003 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10004 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
10005 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10009 * Slides the element into view. An anchor point can be optionally passed to set the point of
10010 * origin for the slide effect. This function automatically handles wrapping the element with
10011 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10014 // default: slide the element in from the top
10017 // custom: slide the element in from the right with a 2-second duration
10018 el.slideIn('r', { duration: 2 });
10020 // common config options shown with default values
10026 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10027 * @param {Object} options (optional) Object literal with any of the Fx config options
10028 * @return {Roo.Element} The Element
10030 slideIn : function(anchor, o){
10031 var el = this.getFxEl();
10034 el.queueFx(o, function(){
10036 anchor = anchor || "t";
10038 // fix display to visibility
10041 // restore values after effect
10042 var r = this.getFxRestore();
10043 var b = this.getBox();
10044 // fixed size for slide
10048 var wrap = this.fxWrap(r.pos, o, "hidden");
10050 var st = this.dom.style;
10051 st.visibility = "visible";
10052 st.position = "absolute";
10054 // clear out temp styles after slide and unwrap
10055 var after = function(){
10056 el.fxUnwrap(wrap, r.pos, o);
10057 st.width = r.width;
10058 st.height = r.height;
10061 // time to calc the positions
10062 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10064 switch(anchor.toLowerCase()){
10066 wrap.setSize(b.width, 0);
10067 st.left = st.bottom = "0";
10071 wrap.setSize(0, b.height);
10072 st.right = st.top = "0";
10076 wrap.setSize(0, b.height);
10077 wrap.setX(b.right);
10078 st.left = st.top = "0";
10079 a = {width: bw, points: pt};
10082 wrap.setSize(b.width, 0);
10083 wrap.setY(b.bottom);
10084 st.left = st.top = "0";
10085 a = {height: bh, points: pt};
10088 wrap.setSize(0, 0);
10089 st.right = st.bottom = "0";
10090 a = {width: bw, height: bh};
10093 wrap.setSize(0, 0);
10094 wrap.setY(b.y+b.height);
10095 st.right = st.top = "0";
10096 a = {width: bw, height: bh, points: pt};
10099 wrap.setSize(0, 0);
10100 wrap.setXY([b.right, b.bottom]);
10101 st.left = st.top = "0";
10102 a = {width: bw, height: bh, points: pt};
10105 wrap.setSize(0, 0);
10106 wrap.setX(b.x+b.width);
10107 st.left = st.bottom = "0";
10108 a = {width: bw, height: bh, points: pt};
10111 this.dom.style.visibility = "visible";
10114 arguments.callee.anim = wrap.fxanim(a,
10124 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10125 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10126 * 'hidden') but block elements will still take up space in the document. The element must be removed
10127 * from the DOM using the 'remove' config option if desired. This function automatically handles
10128 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10131 // default: slide the element out to the top
10134 // custom: slide the element out to the right with a 2-second duration
10135 el.slideOut('r', { duration: 2 });
10137 // common config options shown with default values
10145 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10146 * @param {Object} options (optional) Object literal with any of the Fx config options
10147 * @return {Roo.Element} The Element
10149 slideOut : function(anchor, o){
10150 var el = this.getFxEl();
10153 el.queueFx(o, function(){
10155 anchor = anchor || "t";
10157 // restore values after effect
10158 var r = this.getFxRestore();
10160 var b = this.getBox();
10161 // fixed size for slide
10165 var wrap = this.fxWrap(r.pos, o, "visible");
10167 var st = this.dom.style;
10168 st.visibility = "visible";
10169 st.position = "absolute";
10173 var after = function(){
10175 el.setDisplayed(false);
10180 el.fxUnwrap(wrap, r.pos, o);
10182 st.width = r.width;
10183 st.height = r.height;
10188 var a, zero = {to: 0};
10189 switch(anchor.toLowerCase()){
10191 st.left = st.bottom = "0";
10192 a = {height: zero};
10195 st.right = st.top = "0";
10199 st.left = st.top = "0";
10200 a = {width: zero, points: {to:[b.right, b.y]}};
10203 st.left = st.top = "0";
10204 a = {height: zero, points: {to:[b.x, b.bottom]}};
10207 st.right = st.bottom = "0";
10208 a = {width: zero, height: zero};
10211 st.right = st.top = "0";
10212 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10215 st.left = st.top = "0";
10216 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10219 st.left = st.bottom = "0";
10220 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10224 arguments.callee.anim = wrap.fxanim(a,
10234 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10235 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10236 * The element must be removed from the DOM using the 'remove' config option if desired.
10242 // common config options shown with default values
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 puff : function(o){
10254 var el = this.getFxEl();
10257 el.queueFx(o, function(){
10258 this.clearOpacity();
10261 // restore values after effect
10262 var r = this.getFxRestore();
10263 var st = this.dom.style;
10265 var after = function(){
10267 el.setDisplayed(false);
10274 el.setPositioning(r.pos);
10275 st.width = r.width;
10276 st.height = r.height;
10281 var width = this.getWidth();
10282 var height = this.getHeight();
10284 arguments.callee.anim = this.fxanim({
10285 width : {to: this.adjustWidth(width * 2)},
10286 height : {to: this.adjustHeight(height * 2)},
10287 points : {by: [-(width * .5), -(height * .5)]},
10289 fontSize: {to:200, unit: "%"}
10300 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10301 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10302 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10308 // all config options shown with default values
10316 * @param {Object} options (optional) Object literal with any of the Fx config options
10317 * @return {Roo.Element} The Element
10319 switchOff : function(o){
10320 var el = this.getFxEl();
10323 el.queueFx(o, function(){
10324 this.clearOpacity();
10327 // restore values after effect
10328 var r = this.getFxRestore();
10329 var st = this.dom.style;
10331 var after = function(){
10333 el.setDisplayed(false);
10339 el.setPositioning(r.pos);
10340 st.width = r.width;
10341 st.height = r.height;
10346 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10347 this.clearOpacity();
10351 points:{by:[0, this.getHeight() * .5]}
10352 }, o, 'motion', 0.3, 'easeIn', after);
10353 }).defer(100, this);
10360 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10361 * changed using the "attr" config option) and then fading back to the original color. If no original
10362 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10365 // default: highlight background to yellow
10368 // custom: highlight foreground text to blue for 2 seconds
10369 el.highlight("0000ff", { attr: 'color', duration: 2 });
10371 // common config options shown with default values
10372 el.highlight("ffff9c", {
10373 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10374 endColor: (current color) or "ffffff",
10379 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10380 * @param {Object} options (optional) Object literal with any of the Fx config options
10381 * @return {Roo.Element} The Element
10383 highlight : function(color, o){
10384 var el = this.getFxEl();
10387 el.queueFx(o, function(){
10388 color = color || "ffff9c";
10389 attr = o.attr || "backgroundColor";
10391 this.clearOpacity();
10394 var origColor = this.getColor(attr);
10395 var restoreColor = this.dom.style[attr];
10396 endColor = (o.endColor || origColor) || "ffffff";
10398 var after = function(){
10399 el.dom.style[attr] = restoreColor;
10404 a[attr] = {from: color, to: endColor};
10405 arguments.callee.anim = this.fxanim(a,
10415 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10418 // default: a single light blue ripple
10421 // custom: 3 red ripples lasting 3 seconds total
10422 el.frame("ff0000", 3, { duration: 3 });
10424 // common config options shown with default values
10425 el.frame("C3DAF9", 1, {
10426 duration: 1 //duration of entire animation (not each individual ripple)
10427 // Note: Easing is not configurable and will be ignored if included
10430 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10431 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10432 * @param {Object} options (optional) Object literal with any of the Fx config options
10433 * @return {Roo.Element} The Element
10435 frame : function(color, count, o){
10436 var el = this.getFxEl();
10439 el.queueFx(o, function(){
10440 color = color || "#C3DAF9";
10441 if(color.length == 6){
10442 color = "#" + color;
10444 count = count || 1;
10445 duration = o.duration || 1;
10448 var b = this.getBox();
10449 var animFn = function(){
10450 var proxy = this.createProxy({
10453 visbility:"hidden",
10454 position:"absolute",
10455 "z-index":"35000", // yee haw
10456 border:"0px solid " + color
10459 var scale = Roo.isBorderBox ? 2 : 1;
10461 top:{from:b.y, to:b.y - 20},
10462 left:{from:b.x, to:b.x - 20},
10463 borderWidth:{from:0, to:10},
10464 opacity:{from:1, to:0},
10465 height:{from:b.height, to:(b.height + (20*scale))},
10466 width:{from:b.width, to:(b.width + (20*scale))}
10467 }, duration, function(){
10471 animFn.defer((duration/2)*1000, this);
10482 * Creates a pause before any subsequent queued effects begin. If there are
10483 * no effects queued after the pause it will have no effect.
10488 * @param {Number} seconds The length of time to pause (in seconds)
10489 * @return {Roo.Element} The Element
10491 pause : function(seconds){
10492 var el = this.getFxEl();
10495 el.queueFx(o, function(){
10496 setTimeout(function(){
10498 }, seconds * 1000);
10504 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10505 * using the "endOpacity" config option.
10508 // default: fade in from opacity 0 to 100%
10511 // custom: fade in from opacity 0 to 75% over 2 seconds
10512 el.fadeIn({ endOpacity: .75, duration: 2});
10514 // common config options shown with default values
10516 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10521 * @param {Object} options (optional) Object literal with any of the Fx config options
10522 * @return {Roo.Element} The Element
10524 fadeIn : function(o){
10525 var el = this.getFxEl();
10527 el.queueFx(o, function(){
10528 this.setOpacity(0);
10530 this.dom.style.visibility = 'visible';
10531 var to = o.endOpacity || 1;
10532 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10533 o, null, .5, "easeOut", function(){
10535 this.clearOpacity();
10544 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10545 * using the "endOpacity" config option.
10548 // default: fade out from the element's current opacity to 0
10551 // custom: fade out from the element's current opacity to 25% over 2 seconds
10552 el.fadeOut({ endOpacity: .25, duration: 2});
10554 // common config options shown with default values
10556 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10563 * @param {Object} options (optional) Object literal with any of the Fx config options
10564 * @return {Roo.Element} The Element
10566 fadeOut : function(o){
10567 var el = this.getFxEl();
10569 el.queueFx(o, function(){
10570 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10571 o, null, .5, "easeOut", function(){
10572 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10573 this.dom.style.display = "none";
10575 this.dom.style.visibility = "hidden";
10577 this.clearOpacity();
10585 * Animates the transition of an element's dimensions from a starting height/width
10586 * to an ending height/width.
10589 // change height and width to 100x100 pixels
10590 el.scale(100, 100);
10592 // common config options shown with default values. The height and width will default to
10593 // the element's existing values if passed as null.
10596 [element's height], {
10601 * @param {Number} width The new width (pass undefined to keep the original width)
10602 * @param {Number} height The new height (pass undefined to keep the original height)
10603 * @param {Object} options (optional) Object literal with any of the Fx config options
10604 * @return {Roo.Element} The Element
10606 scale : function(w, h, o){
10607 this.shift(Roo.apply({}, o, {
10615 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10616 * Any of these properties not specified in the config object will not be changed. This effect
10617 * requires that at least one new dimension, position or opacity setting must be passed in on
10618 * the config object in order for the function to have any effect.
10621 // slide the element horizontally to x position 200 while changing the height and opacity
10622 el.shift({ x: 200, height: 50, opacity: .8 });
10624 // common config options shown with default values.
10626 width: [element's width],
10627 height: [element's height],
10628 x: [element's x position],
10629 y: [element's y position],
10630 opacity: [element's opacity],
10635 * @param {Object} options Object literal with any of the Fx config options
10636 * @return {Roo.Element} The Element
10638 shift : function(o){
10639 var el = this.getFxEl();
10641 el.queueFx(o, function(){
10642 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10643 if(w !== undefined){
10644 a.width = {to: this.adjustWidth(w)};
10646 if(h !== undefined){
10647 a.height = {to: this.adjustHeight(h)};
10649 if(x !== undefined || y !== undefined){
10651 x !== undefined ? x : this.getX(),
10652 y !== undefined ? y : this.getY()
10655 if(op !== undefined){
10656 a.opacity = {to: op};
10658 if(o.xy !== undefined){
10659 a.points = {to: o.xy};
10661 arguments.callee.anim = this.fxanim(a,
10662 o, 'motion', .35, "easeOut", function(){
10670 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10671 * ending point of the effect.
10674 // default: slide the element downward while fading out
10677 // custom: slide the element out to the right with a 2-second duration
10678 el.ghost('r', { duration: 2 });
10680 // common config options shown with default values
10688 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10689 * @param {Object} options (optional) Object literal with any of the Fx config options
10690 * @return {Roo.Element} The Element
10692 ghost : function(anchor, o){
10693 var el = this.getFxEl();
10696 el.queueFx(o, function(){
10697 anchor = anchor || "b";
10699 // restore values after effect
10700 var r = this.getFxRestore();
10701 var w = this.getWidth(),
10702 h = this.getHeight();
10704 var st = this.dom.style;
10706 var after = function(){
10708 el.setDisplayed(false);
10714 el.setPositioning(r.pos);
10715 st.width = r.width;
10716 st.height = r.height;
10721 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10722 switch(anchor.toLowerCase()){
10749 arguments.callee.anim = this.fxanim(a,
10759 * Ensures that all effects queued after syncFx is called on the element are
10760 * run concurrently. This is the opposite of {@link #sequenceFx}.
10761 * @return {Roo.Element} The Element
10763 syncFx : function(){
10764 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10773 * Ensures that all effects queued after sequenceFx is called on the element are
10774 * run in sequence. This is the opposite of {@link #syncFx}.
10775 * @return {Roo.Element} The Element
10777 sequenceFx : function(){
10778 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10780 concurrent : false,
10787 nextFx : function(){
10788 var ef = this.fxQueue[0];
10795 * Returns true if the element has any effects actively running or queued, else returns false.
10796 * @return {Boolean} True if element has active effects, else false
10798 hasActiveFx : function(){
10799 return this.fxQueue && this.fxQueue[0];
10803 * Stops any running effects and clears the element's internal effects queue if it contains
10804 * any additional effects that haven't started yet.
10805 * @return {Roo.Element} The Element
10807 stopFx : function(){
10808 if(this.hasActiveFx()){
10809 var cur = this.fxQueue[0];
10810 if(cur && cur.anim && cur.anim.isAnimated()){
10811 this.fxQueue = [cur]; // clear out others
10812 cur.anim.stop(true);
10819 beforeFx : function(o){
10820 if(this.hasActiveFx() && !o.concurrent){
10831 * Returns true if the element is currently blocking so that no other effect can be queued
10832 * until this effect is finished, else returns false if blocking is not set. This is commonly
10833 * used to ensure that an effect initiated by a user action runs to completion prior to the
10834 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10835 * @return {Boolean} True if blocking, else false
10837 hasFxBlock : function(){
10838 var q = this.fxQueue;
10839 return q && q[0] && q[0].block;
10843 queueFx : function(o, fn){
10847 if(!this.hasFxBlock()){
10848 Roo.applyIf(o, this.fxDefaults);
10850 var run = this.beforeFx(o);
10851 fn.block = o.block;
10852 this.fxQueue.push(fn);
10864 fxWrap : function(pos, o, vis){
10866 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10869 wrapXY = this.getXY();
10871 var div = document.createElement("div");
10872 div.style.visibility = vis;
10873 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10874 wrap.setPositioning(pos);
10875 if(wrap.getStyle("position") == "static"){
10876 wrap.position("relative");
10878 this.clearPositioning('auto');
10880 wrap.dom.appendChild(this.dom);
10882 wrap.setXY(wrapXY);
10889 fxUnwrap : function(wrap, pos, o){
10890 this.clearPositioning();
10891 this.setPositioning(pos);
10893 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10899 getFxRestore : function(){
10900 var st = this.dom.style;
10901 return {pos: this.getPositioning(), width: st.width, height : st.height};
10905 afterFx : function(o){
10907 this.applyStyles(o.afterStyle);
10910 this.addClass(o.afterCls);
10912 if(o.remove === true){
10915 Roo.callback(o.callback, o.scope, [this]);
10917 this.fxQueue.shift();
10923 getFxEl : function(){ // support for composite element fx
10924 return Roo.get(this.dom);
10928 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10929 animType = animType || 'run';
10931 var anim = Roo.lib.Anim[animType](
10933 (opt.duration || defaultDur) || .35,
10934 (opt.easing || defaultEase) || 'easeOut',
10936 Roo.callback(cb, this);
10945 // backwords compat
10946 Roo.Fx.resize = Roo.Fx.scale;
10948 //When included, Roo.Fx is automatically applied to Element so that all basic
10949 //effects are available directly via the Element API
10950 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10952 * Ext JS Library 1.1.1
10953 * Copyright(c) 2006-2007, Ext JS, LLC.
10955 * Originally Released Under LGPL - original licence link has changed is not relivant.
10958 * <script type="text/javascript">
10963 * @class Roo.CompositeElement
10964 * Standard composite class. Creates a Roo.Element for every element in the collection.
10966 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10967 * actions will be performed on all the elements in this collection.</b>
10969 * All methods return <i>this</i> and can be chained.
10971 var els = Roo.select("#some-el div.some-class", true);
10972 // or select directly from an existing element
10973 var el = Roo.get('some-el');
10974 el.select('div.some-class', true);
10976 els.setWidth(100); // all elements become 100 width
10977 els.hide(true); // all elements fade out and hide
10979 els.setWidth(100).hide(true);
10982 Roo.CompositeElement = function(els){
10983 this.elements = [];
10984 this.addElements(els);
10986 Roo.CompositeElement.prototype = {
10988 addElements : function(els){
10989 if(!els) return this;
10990 if(typeof els == "string"){
10991 els = Roo.Element.selectorFunction(els);
10993 var yels = this.elements;
10994 var index = yels.length-1;
10995 for(var i = 0, len = els.length; i < len; i++) {
10996 yels[++index] = Roo.get(els[i]);
11002 * Clears this composite and adds the elements returned by the passed selector.
11003 * @param {String/Array} els A string CSS selector, an array of elements or an element
11004 * @return {CompositeElement} this
11006 fill : function(els){
11007 this.elements = [];
11013 * Filters this composite to only elements that match the passed selector.
11014 * @param {String} selector A string CSS selector
11015 * @param {Boolean} inverse return inverse filter (not matches)
11016 * @return {CompositeElement} this
11018 filter : function(selector, inverse){
11020 inverse = inverse || false;
11021 this.each(function(el){
11022 var match = inverse ? !el.is(selector) : el.is(selector);
11024 els[els.length] = el.dom;
11031 invoke : function(fn, args){
11032 var els = this.elements;
11033 for(var i = 0, len = els.length; i < len; i++) {
11034 Roo.Element.prototype[fn].apply(els[i], args);
11039 * Adds elements to this composite.
11040 * @param {String/Array} els A string CSS selector, an array of elements or an element
11041 * @return {CompositeElement} this
11043 add : function(els){
11044 if(typeof els == "string"){
11045 this.addElements(Roo.Element.selectorFunction(els));
11046 }else if(els.length !== undefined){
11047 this.addElements(els);
11049 this.addElements([els]);
11054 * Calls the passed function passing (el, this, index) for each element in this composite.
11055 * @param {Function} fn The function to call
11056 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11057 * @return {CompositeElement} this
11059 each : function(fn, scope){
11060 var els = this.elements;
11061 for(var i = 0, len = els.length; i < len; i++){
11062 if(fn.call(scope || els[i], els[i], this, i) === false) {
11070 * Returns the Element object at the specified index
11071 * @param {Number} index
11072 * @return {Roo.Element}
11074 item : function(index){
11075 return this.elements[index] || null;
11079 * Returns the first Element
11080 * @return {Roo.Element}
11082 first : function(){
11083 return this.item(0);
11087 * Returns the last Element
11088 * @return {Roo.Element}
11091 return this.item(this.elements.length-1);
11095 * Returns the number of elements in this composite
11098 getCount : function(){
11099 return this.elements.length;
11103 * Returns true if this composite contains the passed element
11106 contains : function(el){
11107 return this.indexOf(el) !== -1;
11111 * Returns true if this composite contains the passed element
11114 indexOf : function(el){
11115 return this.elements.indexOf(Roo.get(el));
11120 * Removes the specified element(s).
11121 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11122 * or an array of any of those.
11123 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11124 * @return {CompositeElement} this
11126 removeElement : function(el, removeDom){
11127 if(el instanceof Array){
11128 for(var i = 0, len = el.length; i < len; i++){
11129 this.removeElement(el[i]);
11133 var index = typeof el == 'number' ? el : this.indexOf(el);
11136 var d = this.elements[index];
11140 d.parentNode.removeChild(d);
11143 this.elements.splice(index, 1);
11149 * Replaces the specified element with the passed element.
11150 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11152 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11153 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11154 * @return {CompositeElement} this
11156 replaceElement : function(el, replacement, domReplace){
11157 var index = typeof el == 'number' ? el : this.indexOf(el);
11160 this.elements[index].replaceWith(replacement);
11162 this.elements.splice(index, 1, Roo.get(replacement))
11169 * Removes all elements.
11171 clear : function(){
11172 this.elements = [];
11176 Roo.CompositeElement.createCall = function(proto, fnName){
11177 if(!proto[fnName]){
11178 proto[fnName] = function(){
11179 return this.invoke(fnName, arguments);
11183 for(var fnName in Roo.Element.prototype){
11184 if(typeof Roo.Element.prototype[fnName] == "function"){
11185 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11191 * Ext JS Library 1.1.1
11192 * Copyright(c) 2006-2007, Ext JS, LLC.
11194 * Originally Released Under LGPL - original licence link has changed is not relivant.
11197 * <script type="text/javascript">
11201 * @class Roo.CompositeElementLite
11202 * @extends Roo.CompositeElement
11203 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11205 var els = Roo.select("#some-el div.some-class");
11206 // or select directly from an existing element
11207 var el = Roo.get('some-el');
11208 el.select('div.some-class');
11210 els.setWidth(100); // all elements become 100 width
11211 els.hide(true); // all elements fade out and hide
11213 els.setWidth(100).hide(true);
11214 </code></pre><br><br>
11215 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11216 * actions will be performed on all the elements in this collection.</b>
11218 Roo.CompositeElementLite = function(els){
11219 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11220 this.el = new Roo.Element.Flyweight();
11222 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11223 addElements : function(els){
11225 if(els instanceof Array){
11226 this.elements = this.elements.concat(els);
11228 var yels = this.elements;
11229 var index = yels.length-1;
11230 for(var i = 0, len = els.length; i < len; i++) {
11231 yels[++index] = els[i];
11237 invoke : function(fn, args){
11238 var els = this.elements;
11240 for(var i = 0, len = els.length; i < len; i++) {
11242 Roo.Element.prototype[fn].apply(el, args);
11247 * Returns a flyweight Element of the dom element object at the specified index
11248 * @param {Number} index
11249 * @return {Roo.Element}
11251 item : function(index){
11252 if(!this.elements[index]){
11255 this.el.dom = this.elements[index];
11259 // fixes scope with flyweight
11260 addListener : function(eventName, handler, scope, opt){
11261 var els = this.elements;
11262 for(var i = 0, len = els.length; i < len; i++) {
11263 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11269 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11270 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11271 * a reference to the dom node, use el.dom.</b>
11272 * @param {Function} fn The function to call
11273 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11274 * @return {CompositeElement} this
11276 each : function(fn, scope){
11277 var els = this.elements;
11279 for(var i = 0, len = els.length; i < len; i++){
11281 if(fn.call(scope || el, el, this, i) === false){
11288 indexOf : function(el){
11289 return this.elements.indexOf(Roo.getDom(el));
11292 replaceElement : function(el, replacement, domReplace){
11293 var index = typeof el == 'number' ? el : this.indexOf(el);
11295 replacement = Roo.getDom(replacement);
11297 var d = this.elements[index];
11298 d.parentNode.insertBefore(replacement, d);
11299 d.parentNode.removeChild(d);
11301 this.elements.splice(index, 1, replacement);
11306 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11310 * Ext JS Library 1.1.1
11311 * Copyright(c) 2006-2007, Ext JS, LLC.
11313 * Originally Released Under LGPL - original licence link has changed is not relivant.
11316 * <script type="text/javascript">
11322 * @class Roo.data.Connection
11323 * @extends Roo.util.Observable
11324 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11325 * either to a configured URL, or to a URL specified at request time.<br><br>
11327 * Requests made by this class are asynchronous, and will return immediately. No data from
11328 * the server will be available to the statement immediately following the {@link #request} call.
11329 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11331 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11332 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11333 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11334 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11335 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11336 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11337 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11338 * standard DOM methods.
11340 * @param {Object} config a configuration object.
11342 Roo.data.Connection = function(config){
11343 Roo.apply(this, config);
11346 * @event beforerequest
11347 * Fires before a network request is made to retrieve a data object.
11348 * @param {Connection} conn This Connection object.
11349 * @param {Object} options The options config object passed to the {@link #request} method.
11351 "beforerequest" : true,
11353 * @event requestcomplete
11354 * Fires if the request was successfully completed.
11355 * @param {Connection} conn This Connection object.
11356 * @param {Object} response The XHR object containing the response data.
11357 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11358 * @param {Object} options The options config object passed to the {@link #request} method.
11360 "requestcomplete" : true,
11362 * @event requestexception
11363 * Fires if an error HTTP status was returned from the server.
11364 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11365 * @param {Connection} conn This Connection object.
11366 * @param {Object} response The XHR object containing the response data.
11367 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11368 * @param {Object} options The options config object passed to the {@link #request} method.
11370 "requestexception" : true
11372 Roo.data.Connection.superclass.constructor.call(this);
11375 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11377 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11380 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11381 * extra parameters to each request made by this object. (defaults to undefined)
11384 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11385 * to each request made by this object. (defaults to undefined)
11388 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11391 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11395 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11401 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11404 disableCaching: true,
11407 * Sends an HTTP request to a remote server.
11408 * @param {Object} options An object which may contain the following properties:<ul>
11409 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11410 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11411 * request, a url encoded string or a function to call to get either.</li>
11412 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11413 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11414 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11415 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11416 * <li>options {Object} The parameter to the request call.</li>
11417 * <li>success {Boolean} True if the request succeeded.</li>
11418 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11420 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11421 * The callback is passed the following parameters:<ul>
11422 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11423 * <li>options {Object} The parameter to the request call.</li>
11425 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11426 * The callback is passed the following parameters:<ul>
11427 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11428 * <li>options {Object} The parameter to the request call.</li>
11430 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11431 * for the callback function. Defaults to the browser window.</li>
11432 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11433 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11434 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11435 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11436 * params for the post data. Any params will be appended to the URL.</li>
11437 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11439 * @return {Number} transactionId
11441 request : function(o){
11442 if(this.fireEvent("beforerequest", this, o) !== false){
11445 if(typeof p == "function"){
11446 p = p.call(o.scope||window, o);
11448 if(typeof p == "object"){
11449 p = Roo.urlEncode(o.params);
11451 if(this.extraParams){
11452 var extras = Roo.urlEncode(this.extraParams);
11453 p = p ? (p + '&' + extras) : extras;
11456 var url = o.url || this.url;
11457 if(typeof url == 'function'){
11458 url = url.call(o.scope||window, o);
11462 var form = Roo.getDom(o.form);
11463 url = url || form.action;
11465 var enctype = form.getAttribute("enctype");
11466 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11467 return this.doFormUpload(o, p, url);
11469 var f = Roo.lib.Ajax.serializeForm(form);
11470 p = p ? (p + '&' + f) : f;
11473 var hs = o.headers;
11474 if(this.defaultHeaders){
11475 hs = Roo.apply(hs || {}, this.defaultHeaders);
11482 success: this.handleResponse,
11483 failure: this.handleFailure,
11485 argument: {options: o},
11486 timeout : o.timeout || this.timeout
11489 var method = o.method||this.method||(p ? "POST" : "GET");
11491 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11492 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11495 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11499 }else if(this.autoAbort !== false){
11503 if((method == 'GET' && p) || o.xmlData){
11504 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11507 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11508 return this.transId;
11510 Roo.callback(o.callback, o.scope, [o, null, null]);
11516 * Determine whether this object has a request outstanding.
11517 * @param {Number} transactionId (Optional) defaults to the last transaction
11518 * @return {Boolean} True if there is an outstanding request.
11520 isLoading : function(transId){
11522 return Roo.lib.Ajax.isCallInProgress(transId);
11524 return this.transId ? true : false;
11529 * Aborts any outstanding request.
11530 * @param {Number} transactionId (Optional) defaults to the last transaction
11532 abort : function(transId){
11533 if(transId || this.isLoading()){
11534 Roo.lib.Ajax.abort(transId || this.transId);
11539 handleResponse : function(response){
11540 this.transId = false;
11541 var options = response.argument.options;
11542 response.argument = options ? options.argument : null;
11543 this.fireEvent("requestcomplete", this, response, options);
11544 Roo.callback(options.success, options.scope, [response, options]);
11545 Roo.callback(options.callback, options.scope, [options, true, response]);
11549 handleFailure : function(response, e){
11550 this.transId = false;
11551 var options = response.argument.options;
11552 response.argument = options ? options.argument : null;
11553 this.fireEvent("requestexception", this, response, options, e);
11554 Roo.callback(options.failure, options.scope, [response, options]);
11555 Roo.callback(options.callback, options.scope, [options, false, response]);
11559 doFormUpload : function(o, ps, url){
11561 var frame = document.createElement('iframe');
11564 frame.className = 'x-hidden';
11566 frame.src = Roo.SSL_SECURE_URL;
11568 document.body.appendChild(frame);
11571 document.frames[id].name = id;
11574 var form = Roo.getDom(o.form);
11576 form.method = 'POST';
11577 form.enctype = form.encoding = 'multipart/form-data';
11583 if(ps){ // add dynamic params
11585 ps = Roo.urlDecode(ps, false);
11587 if(ps.hasOwnProperty(k)){
11588 hd = document.createElement('input');
11589 hd.type = 'hidden';
11592 form.appendChild(hd);
11599 var r = { // bogus response object
11604 r.argument = o ? o.argument : null;
11609 doc = frame.contentWindow.document;
11611 doc = (frame.contentDocument || window.frames[id].document);
11613 if(doc && doc.body){
11614 r.responseText = doc.body.innerHTML;
11616 if(doc && doc.XMLDocument){
11617 r.responseXML = doc.XMLDocument;
11619 r.responseXML = doc;
11626 Roo.EventManager.removeListener(frame, 'load', cb, this);
11628 this.fireEvent("requestcomplete", this, r, o);
11629 Roo.callback(o.success, o.scope, [r, o]);
11630 Roo.callback(o.callback, o.scope, [o, true, r]);
11632 setTimeout(function(){document.body.removeChild(frame);}, 100);
11635 Roo.EventManager.on(frame, 'load', cb, this);
11638 if(hiddens){ // remove dynamic params
11639 for(var i = 0, len = hiddens.length; i < len; i++){
11640 form.removeChild(hiddens[i]);
11647 * Ext JS Library 1.1.1
11648 * Copyright(c) 2006-2007, Ext JS, LLC.
11650 * Originally Released Under LGPL - original licence link has changed is not relivant.
11653 * <script type="text/javascript">
11657 * Global Ajax request class.
11660 * @extends Roo.data.Connection
11663 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11664 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11665 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11666 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11667 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11668 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11669 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11671 Roo.Ajax = new Roo.data.Connection({
11680 * Serialize the passed form into a url encoded string
11682 * @param {String/HTMLElement} form
11685 serializeForm : function(form){
11686 return Roo.lib.Ajax.serializeForm(form);
11690 * Ext JS Library 1.1.1
11691 * Copyright(c) 2006-2007, Ext JS, LLC.
11693 * Originally Released Under LGPL - original licence link has changed is not relivant.
11696 * <script type="text/javascript">
11701 * @class Roo.UpdateManager
11702 * @extends Roo.util.Observable
11703 * Provides AJAX-style update for Element object.<br><br>
11706 * // Get it from a Roo.Element object
11707 * var el = Roo.get("foo");
11708 * var mgr = el.getUpdateManager();
11709 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11711 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11713 * // or directly (returns the same UpdateManager instance)
11714 * var mgr = new Roo.UpdateManager("myElementId");
11715 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11716 * mgr.on("update", myFcnNeedsToKnow);
11718 // short handed call directly from the element object
11719 Roo.get("foo").load({
11723 text: "Loading Foo..."
11727 * Create new UpdateManager directly.
11728 * @param {String/HTMLElement/Roo.Element} el The element to update
11729 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11731 Roo.UpdateManager = function(el, forceNew){
11733 if(!forceNew && el.updateManager){
11734 return el.updateManager;
11737 * The Element object
11738 * @type Roo.Element
11742 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11745 this.defaultUrl = null;
11749 * @event beforeupdate
11750 * Fired before an update is made, return false from your handler and the update is cancelled.
11751 * @param {Roo.Element} el
11752 * @param {String/Object/Function} url
11753 * @param {String/Object} params
11755 "beforeupdate": true,
11758 * Fired after successful update is made.
11759 * @param {Roo.Element} el
11760 * @param {Object} oResponseObject The response Object
11765 * Fired on update failure.
11766 * @param {Roo.Element} el
11767 * @param {Object} oResponseObject The response Object
11771 var d = Roo.UpdateManager.defaults;
11773 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11776 this.sslBlankUrl = d.sslBlankUrl;
11778 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11781 this.disableCaching = d.disableCaching;
11783 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11786 this.indicatorText = d.indicatorText;
11788 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11791 this.showLoadIndicator = d.showLoadIndicator;
11793 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11796 this.timeout = d.timeout;
11799 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11802 this.loadScripts = d.loadScripts;
11805 * Transaction object of current executing transaction
11807 this.transaction = null;
11812 this.autoRefreshProcId = null;
11814 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11817 this.refreshDelegate = this.refresh.createDelegate(this);
11819 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11822 this.updateDelegate = this.update.createDelegate(this);
11824 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11827 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11831 this.successDelegate = this.processSuccess.createDelegate(this);
11835 this.failureDelegate = this.processFailure.createDelegate(this);
11837 if(!this.renderer){
11839 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11841 this.renderer = new Roo.UpdateManager.BasicRenderer();
11844 Roo.UpdateManager.superclass.constructor.call(this);
11847 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11849 * Get the Element this UpdateManager is bound to
11850 * @return {Roo.Element} The element
11852 getEl : function(){
11856 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11857 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11860 url: "your-url.php",<br/>
11861 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11862 callback: yourFunction,<br/>
11863 scope: yourObject, //(optional scope) <br/>
11864 discardUrl: false, <br/>
11865 nocache: false,<br/>
11866 text: "Loading...",<br/>
11868 scripts: false<br/>
11871 * The only required property is url. The optional properties nocache, text and scripts
11872 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11873 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11874 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11875 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11877 update : function(url, params, callback, discardUrl){
11878 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11879 var method = this.method,
11881 if(typeof url == "object"){ // must be config object
11884 params = params || cfg.params;
11885 callback = callback || cfg.callback;
11886 discardUrl = discardUrl || cfg.discardUrl;
11887 if(callback && cfg.scope){
11888 callback = callback.createDelegate(cfg.scope);
11890 if(typeof cfg.method != "undefined"){method = cfg.method;};
11891 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11892 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11893 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11894 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11896 this.showLoading();
11898 this.defaultUrl = url;
11900 if(typeof url == "function"){
11901 url = url.call(this);
11904 method = method || (params ? "POST" : "GET");
11905 if(method == "GET"){
11906 url = this.prepareUrl(url);
11909 var o = Roo.apply(cfg ||{}, {
11912 success: this.successDelegate,
11913 failure: this.failureDelegate,
11914 callback: undefined,
11915 timeout: (this.timeout*1000),
11916 argument: {"url": url, "form": null, "callback": callback, "params": params}
11918 Roo.log("updated manager called with timeout of " + o.timeout);
11919 this.transaction = Roo.Ajax.request(o);
11924 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11925 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11926 * @param {String/HTMLElement} form The form Id or form element
11927 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11928 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11929 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11931 formUpdate : function(form, url, reset, callback){
11932 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11933 if(typeof url == "function"){
11934 url = url.call(this);
11936 form = Roo.getDom(form);
11937 this.transaction = Roo.Ajax.request({
11940 success: this.successDelegate,
11941 failure: this.failureDelegate,
11942 timeout: (this.timeout*1000),
11943 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11945 this.showLoading.defer(1, this);
11950 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11951 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11953 refresh : function(callback){
11954 if(this.defaultUrl == null){
11957 this.update(this.defaultUrl, null, callback, true);
11961 * Set this element to auto refresh.
11962 * @param {Number} interval How often to update (in seconds).
11963 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11964 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11965 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11966 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11968 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11970 this.update(url || this.defaultUrl, params, callback, true);
11972 if(this.autoRefreshProcId){
11973 clearInterval(this.autoRefreshProcId);
11975 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11979 * Stop auto refresh on this element.
11981 stopAutoRefresh : function(){
11982 if(this.autoRefreshProcId){
11983 clearInterval(this.autoRefreshProcId);
11984 delete this.autoRefreshProcId;
11988 isAutoRefreshing : function(){
11989 return this.autoRefreshProcId ? true : false;
11992 * Called to update the element to "Loading" state. Override to perform custom action.
11994 showLoading : function(){
11995 if(this.showLoadIndicator){
11996 this.el.update(this.indicatorText);
12001 * Adds unique parameter to query string if disableCaching = true
12004 prepareUrl : function(url){
12005 if(this.disableCaching){
12006 var append = "_dc=" + (new Date().getTime());
12007 if(url.indexOf("?") !== -1){
12008 url += "&" + append;
12010 url += "?" + append;
12019 processSuccess : function(response){
12020 this.transaction = null;
12021 if(response.argument.form && response.argument.reset){
12022 try{ // put in try/catch since some older FF releases had problems with this
12023 response.argument.form.reset();
12026 if(this.loadScripts){
12027 this.renderer.render(this.el, response, this,
12028 this.updateComplete.createDelegate(this, [response]));
12030 this.renderer.render(this.el, response, this);
12031 this.updateComplete(response);
12035 updateComplete : function(response){
12036 this.fireEvent("update", this.el, response);
12037 if(typeof response.argument.callback == "function"){
12038 response.argument.callback(this.el, true, response);
12045 processFailure : function(response){
12046 this.transaction = null;
12047 this.fireEvent("failure", this.el, response);
12048 if(typeof response.argument.callback == "function"){
12049 response.argument.callback(this.el, false, response);
12054 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12055 * @param {Object} renderer The object implementing the render() method
12057 setRenderer : function(renderer){
12058 this.renderer = renderer;
12061 getRenderer : function(){
12062 return this.renderer;
12066 * Set the defaultUrl used for updates
12067 * @param {String/Function} defaultUrl The url or a function to call to get the url
12069 setDefaultUrl : function(defaultUrl){
12070 this.defaultUrl = defaultUrl;
12074 * Aborts the executing transaction
12076 abort : function(){
12077 if(this.transaction){
12078 Roo.Ajax.abort(this.transaction);
12083 * Returns true if an update is in progress
12084 * @return {Boolean}
12086 isUpdating : function(){
12087 if(this.transaction){
12088 return Roo.Ajax.isLoading(this.transaction);
12095 * @class Roo.UpdateManager.defaults
12096 * @static (not really - but it helps the doc tool)
12097 * The defaults collection enables customizing the default properties of UpdateManager
12099 Roo.UpdateManager.defaults = {
12101 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12107 * True to process scripts by default (Defaults to false).
12110 loadScripts : false,
12113 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12116 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12118 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12121 disableCaching : false,
12123 * Whether to show indicatorText when loading (Defaults to true).
12126 showLoadIndicator : true,
12128 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12131 indicatorText : '<div class="loading-indicator">Loading...</div>'
12135 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12137 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12138 * @param {String/HTMLElement/Roo.Element} el The element to update
12139 * @param {String} url The url
12140 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12141 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12144 * @member Roo.UpdateManager
12146 Roo.UpdateManager.updateElement = function(el, url, params, options){
12147 var um = Roo.get(el, true).getUpdateManager();
12148 Roo.apply(um, options);
12149 um.update(url, params, options ? options.callback : null);
12151 // alias for backwards compat
12152 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12154 * @class Roo.UpdateManager.BasicRenderer
12155 * Default Content renderer. Updates the elements innerHTML with the responseText.
12157 Roo.UpdateManager.BasicRenderer = function(){};
12159 Roo.UpdateManager.BasicRenderer.prototype = {
12161 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12162 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12163 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12164 * @param {Roo.Element} el The element being rendered
12165 * @param {Object} response The YUI Connect response object
12166 * @param {UpdateManager} updateManager The calling update manager
12167 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12169 render : function(el, response, updateManager, callback){
12170 el.update(response.responseText, updateManager.loadScripts, callback);
12176 * (c)) Alan Knowles
12182 * @class Roo.DomTemplate
12183 * @extends Roo.Template
12184 * An effort at a dom based template engine..
12186 * Similar to XTemplate, except it uses dom parsing to create the template..
12188 * Supported features:
12193 {a_variable} - output encoded.
12194 {a_variable.format:("Y-m-d")} - call a method on the variable
12195 {a_variable:raw} - unencoded output
12196 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12197 {a_variable:this.method_on_template(...)} - call a method on the template object.
12202 <div roo-for="a_variable or condition.."></div>
12203 <div roo-if="a_variable or condition"></div>
12204 <div roo-exec="some javascript"></div>
12205 <div roo-name="named_template"></div>
12210 Roo.DomTemplate = function()
12212 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12219 Roo.extend(Roo.DomTemplate, Roo.Template, {
12221 * id counter for sub templates.
12225 * flag to indicate if dom parser is inside a pre,
12226 * it will strip whitespace if not.
12231 * The various sub templates
12239 * basic tag replacing syntax
12242 * // you can fake an object call by doing this
12246 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12247 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12249 iterChild : function (node, method) {
12251 var oldPre = this.inPre;
12252 if (node.tagName == 'PRE') {
12255 for( var i = 0; i < node.childNodes.length; i++) {
12256 method.call(this, node.childNodes[i]);
12258 this.inPre = oldPre;
12264 * compile the template
12266 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12269 compile: function()
12273 // covert the html into DOM...
12277 doc = document.implementation.createHTMLDocument("");
12278 doc.documentElement.innerHTML = this.html ;
12279 div = doc.documentElement;
12281 // old IE... - nasty -- it causes all sorts of issues.. with
12282 // images getting pulled from server..
12283 div = document.createElement('div');
12284 div.innerHTML = this.html;
12286 //doc.documentElement.innerHTML = htmlBody
12292 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12294 var tpls = this.tpls;
12296 // create a top level template from the snippet..
12298 //Roo.log(div.innerHTML);
12305 body : div.innerHTML,
12318 Roo.each(tpls, function(tp){
12319 this.compileTpl(tp);
12320 this.tpls[tp.id] = tp;
12323 this.master = tpls[0];
12329 compileNode : function(node, istop) {
12334 // skip anything not a tag..
12335 if (node.nodeType != 1) {
12336 if (node.nodeType == 3 && !this.inPre) {
12337 // reduce white space..
12338 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12361 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12362 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12363 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12364 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12370 // just itterate children..
12371 this.iterChild(node,this.compileNode);
12374 tpl.uid = this.id++;
12375 tpl.value = node.getAttribute('roo-' + tpl.attr);
12376 node.removeAttribute('roo-'+ tpl.attr);
12377 if (tpl.attr != 'name') {
12378 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12379 node.parentNode.replaceChild(placeholder, node);
12382 var placeholder = document.createElement('span');
12383 placeholder.className = 'roo-tpl-' + tpl.value;
12384 node.parentNode.replaceChild(placeholder, node);
12387 // parent now sees '{domtplXXXX}
12388 this.iterChild(node,this.compileNode);
12390 // we should now have node body...
12391 var div = document.createElement('div');
12392 div.appendChild(node);
12394 // this has the unfortunate side effect of converting tagged attributes
12395 // eg. href="{...}" into %7C...%7D
12396 // this has been fixed by searching for those combo's although it's a bit hacky..
12399 tpl.body = div.innerHTML;
12406 switch (tpl.value) {
12407 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12408 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12409 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12414 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12418 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12422 tpl.id = tpl.value; // replace non characters???
12428 this.tpls.push(tpl);
12438 * Compile a segment of the template into a 'sub-template'
12444 compileTpl : function(tpl)
12446 var fm = Roo.util.Format;
12447 var useF = this.disableFormats !== true;
12449 var sep = Roo.isGecko ? "+\n" : ",\n";
12451 var undef = function(str) {
12452 Roo.debug && Roo.log("Property not found :" + str);
12456 //Roo.log(tpl.body);
12460 var fn = function(m, lbrace, name, format, args)
12463 //Roo.log(arguments);
12464 args = args ? args.replace(/\\'/g,"'") : args;
12465 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12466 if (typeof(format) == 'undefined') {
12467 format = 'htmlEncode';
12469 if (format == 'raw' ) {
12473 if(name.substr(0, 6) == 'domtpl'){
12474 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12477 // build an array of options to determine if value is undefined..
12479 // basically get 'xxxx.yyyy' then do
12480 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12481 // (function () { Roo.log("Property not found"); return ''; })() :
12486 Roo.each(name.split('.'), function(st) {
12487 lookfor += (lookfor.length ? '.': '') + st;
12488 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12491 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12494 if(format && useF){
12496 args = args ? ',' + args : "";
12498 if(format.substr(0, 5) != "this."){
12499 format = "fm." + format + '(';
12501 format = 'this.call("'+ format.substr(5) + '", ';
12505 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12508 if (args && args.length) {
12509 // called with xxyx.yuu:(test,test)
12511 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12513 // raw.. - :raw modifier..
12514 return "'"+ sep + udef_st + name + ")"+sep+"'";
12518 // branched to use + in gecko and [].join() in others
12520 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12521 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12524 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12525 body.push(tpl.body.replace(/(\r\n|\n)/g,
12526 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12527 body.push("'].join('');};};");
12528 body = body.join('');
12531 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12533 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12540 * same as applyTemplate, except it's done to one of the subTemplates
12541 * when using named templates, you can do:
12543 * var str = pl.applySubTemplate('your-name', values);
12546 * @param {Number} id of the template
12547 * @param {Object} values to apply to template
12548 * @param {Object} parent (normaly the instance of this object)
12550 applySubTemplate : function(id, values, parent)
12554 var t = this.tpls[id];
12558 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12559 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12563 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12570 if(t.execCall && t.execCall.call(this, values, parent)){
12574 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12580 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12581 parent = t.target ? values : parent;
12582 if(t.forCall && vs instanceof Array){
12584 for(var i = 0, len = vs.length; i < len; i++){
12586 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12588 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12590 //Roo.log(t.compiled);
12594 return buf.join('');
12597 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12602 return t.compiled.call(this, vs, parent);
12604 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12606 //Roo.log(t.compiled);
12614 applyTemplate : function(values){
12615 return this.master.compiled.call(this, values, {});
12616 //var s = this.subs;
12619 apply : function(){
12620 return this.applyTemplate.apply(this, arguments);
12625 Roo.DomTemplate.from = function(el){
12626 el = Roo.getDom(el);
12627 return new Roo.Domtemplate(el.value || el.innerHTML);
12630 * Ext JS Library 1.1.1
12631 * Copyright(c) 2006-2007, Ext JS, LLC.
12633 * Originally Released Under LGPL - original licence link has changed is not relivant.
12636 * <script type="text/javascript">
12640 * @class Roo.util.DelayedTask
12641 * Provides a convenient method of performing setTimeout where a new
12642 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12643 * You can use this class to buffer
12644 * the keypress events for a certain number of milliseconds, and perform only if they stop
12645 * for that amount of time.
12646 * @constructor The parameters to this constructor serve as defaults and are not required.
12647 * @param {Function} fn (optional) The default function to timeout
12648 * @param {Object} scope (optional) The default scope of that timeout
12649 * @param {Array} args (optional) The default Array of arguments
12651 Roo.util.DelayedTask = function(fn, scope, args){
12652 var id = null, d, t;
12654 var call = function(){
12655 var now = new Date().getTime();
12659 fn.apply(scope, args || []);
12663 * Cancels any pending timeout and queues a new one
12664 * @param {Number} delay The milliseconds to delay
12665 * @param {Function} newFn (optional) Overrides function passed to constructor
12666 * @param {Object} newScope (optional) Overrides scope passed to constructor
12667 * @param {Array} newArgs (optional) Overrides args passed to constructor
12669 this.delay = function(delay, newFn, newScope, newArgs){
12670 if(id && delay != d){
12674 t = new Date().getTime();
12676 scope = newScope || scope;
12677 args = newArgs || args;
12679 id = setInterval(call, d);
12684 * Cancel the last queued timeout
12686 this.cancel = function(){
12694 * Ext JS Library 1.1.1
12695 * Copyright(c) 2006-2007, Ext JS, LLC.
12697 * Originally Released Under LGPL - original licence link has changed is not relivant.
12700 * <script type="text/javascript">
12704 Roo.util.TaskRunner = function(interval){
12705 interval = interval || 10;
12706 var tasks = [], removeQueue = [];
12708 var running = false;
12710 var stopThread = function(){
12716 var startThread = function(){
12719 id = setInterval(runTasks, interval);
12723 var removeTask = function(task){
12724 removeQueue.push(task);
12730 var runTasks = function(){
12731 if(removeQueue.length > 0){
12732 for(var i = 0, len = removeQueue.length; i < len; i++){
12733 tasks.remove(removeQueue[i]);
12736 if(tasks.length < 1){
12741 var now = new Date().getTime();
12742 for(var i = 0, len = tasks.length; i < len; ++i){
12744 var itime = now - t.taskRunTime;
12745 if(t.interval <= itime){
12746 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12747 t.taskRunTime = now;
12748 if(rt === false || t.taskRunCount === t.repeat){
12753 if(t.duration && t.duration <= (now - t.taskStartTime)){
12760 * Queues a new task.
12761 * @param {Object} task
12763 this.start = function(task){
12765 task.taskStartTime = new Date().getTime();
12766 task.taskRunTime = 0;
12767 task.taskRunCount = 0;
12772 this.stop = function(task){
12777 this.stopAll = function(){
12779 for(var i = 0, len = tasks.length; i < len; i++){
12780 if(tasks[i].onStop){
12789 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12791 * Ext JS Library 1.1.1
12792 * Copyright(c) 2006-2007, Ext JS, LLC.
12794 * Originally Released Under LGPL - original licence link has changed is not relivant.
12797 * <script type="text/javascript">
12802 * @class Roo.util.MixedCollection
12803 * @extends Roo.util.Observable
12804 * A Collection class that maintains both numeric indexes and keys and exposes events.
12806 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12807 * collection (defaults to false)
12808 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12809 * and return the key value for that item. This is used when available to look up the key on items that
12810 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12811 * equivalent to providing an implementation for the {@link #getKey} method.
12813 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12821 * Fires when the collection is cleared.
12826 * Fires when an item is added to the collection.
12827 * @param {Number} index The index at which the item was added.
12828 * @param {Object} o The item added.
12829 * @param {String} key The key associated with the added item.
12834 * Fires when an item is replaced in the collection.
12835 * @param {String} key he key associated with the new added.
12836 * @param {Object} old The item being replaced.
12837 * @param {Object} new The new item.
12842 * Fires when an item is removed from the collection.
12843 * @param {Object} o The item being removed.
12844 * @param {String} key (optional) The key associated with the removed item.
12849 this.allowFunctions = allowFunctions === true;
12851 this.getKey = keyFn;
12853 Roo.util.MixedCollection.superclass.constructor.call(this);
12856 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12857 allowFunctions : false,
12860 * Adds an item to the collection.
12861 * @param {String} key The key to associate with the item
12862 * @param {Object} o The item to add.
12863 * @return {Object} The item added.
12865 add : function(key, o){
12866 if(arguments.length == 1){
12868 key = this.getKey(o);
12870 if(typeof key == "undefined" || key === null){
12872 this.items.push(o);
12873 this.keys.push(null);
12875 var old = this.map[key];
12877 return this.replace(key, o);
12880 this.items.push(o);
12882 this.keys.push(key);
12884 this.fireEvent("add", this.length-1, o, key);
12889 * MixedCollection has a generic way to fetch keys if you implement getKey.
12892 var mc = new Roo.util.MixedCollection();
12893 mc.add(someEl.dom.id, someEl);
12894 mc.add(otherEl.dom.id, otherEl);
12898 var mc = new Roo.util.MixedCollection();
12899 mc.getKey = function(el){
12905 // or via the constructor
12906 var mc = new Roo.util.MixedCollection(false, function(el){
12912 * @param o {Object} The item for which to find the key.
12913 * @return {Object} The key for the passed item.
12915 getKey : function(o){
12920 * Replaces an item in the collection.
12921 * @param {String} key The key associated with the item to replace, or the item to replace.
12922 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12923 * @return {Object} The new item.
12925 replace : function(key, o){
12926 if(arguments.length == 1){
12928 key = this.getKey(o);
12930 var old = this.item(key);
12931 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12932 return this.add(key, o);
12934 var index = this.indexOfKey(key);
12935 this.items[index] = o;
12937 this.fireEvent("replace", key, old, o);
12942 * Adds all elements of an Array or an Object to the collection.
12943 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12944 * an Array of values, each of which are added to the collection.
12946 addAll : function(objs){
12947 if(arguments.length > 1 || objs instanceof Array){
12948 var args = arguments.length > 1 ? arguments : objs;
12949 for(var i = 0, len = args.length; i < len; i++){
12953 for(var key in objs){
12954 if(this.allowFunctions || typeof objs[key] != "function"){
12955 this.add(key, objs[key]);
12962 * Executes the specified function once for every item in the collection, passing each
12963 * item as the first and only parameter. returning false from the function will stop the iteration.
12964 * @param {Function} fn The function to execute for each item.
12965 * @param {Object} scope (optional) The scope in which to execute the function.
12967 each : function(fn, scope){
12968 var items = [].concat(this.items); // each safe for removal
12969 for(var i = 0, len = items.length; i < len; i++){
12970 if(fn.call(scope || items[i], items[i], i, len) === false){
12977 * Executes the specified function once for every key in the collection, passing each
12978 * key, and its associated item as the first two parameters.
12979 * @param {Function} fn The function to execute for each item.
12980 * @param {Object} scope (optional) The scope in which to execute the function.
12982 eachKey : function(fn, scope){
12983 for(var i = 0, len = this.keys.length; i < len; i++){
12984 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12989 * Returns the first item in the collection which elicits a true return value from the
12990 * passed selection function.
12991 * @param {Function} fn The selection function to execute for each item.
12992 * @param {Object} scope (optional) The scope in which to execute the function.
12993 * @return {Object} The first item in the collection which returned true from the selection function.
12995 find : function(fn, scope){
12996 for(var i = 0, len = this.items.length; i < len; i++){
12997 if(fn.call(scope || window, this.items[i], this.keys[i])){
12998 return this.items[i];
13005 * Inserts an item at the specified index in the collection.
13006 * @param {Number} index The index to insert the item at.
13007 * @param {String} key The key to associate with the new item, or the item itself.
13008 * @param {Object} o (optional) If the second parameter was a key, the new item.
13009 * @return {Object} The item inserted.
13011 insert : function(index, key, o){
13012 if(arguments.length == 2){
13014 key = this.getKey(o);
13016 if(index >= this.length){
13017 return this.add(key, o);
13020 this.items.splice(index, 0, o);
13021 if(typeof key != "undefined" && key != null){
13024 this.keys.splice(index, 0, key);
13025 this.fireEvent("add", index, o, key);
13030 * Removed an item from the collection.
13031 * @param {Object} o The item to remove.
13032 * @return {Object} The item removed.
13034 remove : function(o){
13035 return this.removeAt(this.indexOf(o));
13039 * Remove an item from a specified index in the collection.
13040 * @param {Number} index The index within the collection of the item to remove.
13042 removeAt : function(index){
13043 if(index < this.length && index >= 0){
13045 var o = this.items[index];
13046 this.items.splice(index, 1);
13047 var key = this.keys[index];
13048 if(typeof key != "undefined"){
13049 delete this.map[key];
13051 this.keys.splice(index, 1);
13052 this.fireEvent("remove", o, key);
13057 * Removed an item associated with the passed key fom the collection.
13058 * @param {String} key The key of the item to remove.
13060 removeKey : function(key){
13061 return this.removeAt(this.indexOfKey(key));
13065 * Returns the number of items in the collection.
13066 * @return {Number} the number of items in the collection.
13068 getCount : function(){
13069 return this.length;
13073 * Returns index within the collection of the passed Object.
13074 * @param {Object} o The item to find the index of.
13075 * @return {Number} index of the item.
13077 indexOf : function(o){
13078 if(!this.items.indexOf){
13079 for(var i = 0, len = this.items.length; i < len; i++){
13080 if(this.items[i] == o) return i;
13084 return this.items.indexOf(o);
13089 * Returns index within the collection of the passed key.
13090 * @param {String} key The key to find the index of.
13091 * @return {Number} index of the key.
13093 indexOfKey : function(key){
13094 if(!this.keys.indexOf){
13095 for(var i = 0, len = this.keys.length; i < len; i++){
13096 if(this.keys[i] == key) return i;
13100 return this.keys.indexOf(key);
13105 * Returns the item associated with the passed key OR index. Key has priority over index.
13106 * @param {String/Number} key The key or index of the item.
13107 * @return {Object} The item associated with the passed key.
13109 item : function(key){
13110 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13111 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13115 * Returns the item at the specified index.
13116 * @param {Number} index The index of the item.
13119 itemAt : function(index){
13120 return this.items[index];
13124 * Returns the item associated with the passed key.
13125 * @param {String/Number} key The key of the item.
13126 * @return {Object} The item associated with the passed key.
13128 key : function(key){
13129 return this.map[key];
13133 * Returns true if the collection contains the passed Object as an item.
13134 * @param {Object} o The Object to look for in the collection.
13135 * @return {Boolean} True if the collection contains the Object as an item.
13137 contains : function(o){
13138 return this.indexOf(o) != -1;
13142 * Returns true if the collection contains the passed Object as a key.
13143 * @param {String} key The key to look for in the collection.
13144 * @return {Boolean} True if the collection contains the Object as a key.
13146 containsKey : function(key){
13147 return typeof this.map[key] != "undefined";
13151 * Removes all items from the collection.
13153 clear : function(){
13158 this.fireEvent("clear");
13162 * Returns the first item in the collection.
13163 * @return {Object} the first item in the collection..
13165 first : function(){
13166 return this.items[0];
13170 * Returns the last item in the collection.
13171 * @return {Object} the last item in the collection..
13174 return this.items[this.length-1];
13177 _sort : function(property, dir, fn){
13178 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13179 fn = fn || function(a, b){
13182 var c = [], k = this.keys, items = this.items;
13183 for(var i = 0, len = items.length; i < len; i++){
13184 c[c.length] = {key: k[i], value: items[i], index: i};
13186 c.sort(function(a, b){
13187 var v = fn(a[property], b[property]) * dsc;
13189 v = (a.index < b.index ? -1 : 1);
13193 for(var i = 0, len = c.length; i < len; i++){
13194 items[i] = c[i].value;
13197 this.fireEvent("sort", this);
13201 * Sorts this collection with the passed comparison function
13202 * @param {String} direction (optional) "ASC" or "DESC"
13203 * @param {Function} fn (optional) comparison function
13205 sort : function(dir, fn){
13206 this._sort("value", dir, fn);
13210 * Sorts this collection by keys
13211 * @param {String} direction (optional) "ASC" or "DESC"
13212 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13214 keySort : function(dir, fn){
13215 this._sort("key", dir, fn || function(a, b){
13216 return String(a).toUpperCase()-String(b).toUpperCase();
13221 * Returns a range of items in this collection
13222 * @param {Number} startIndex (optional) defaults to 0
13223 * @param {Number} endIndex (optional) default to the last item
13224 * @return {Array} An array of items
13226 getRange : function(start, end){
13227 var items = this.items;
13228 if(items.length < 1){
13231 start = start || 0;
13232 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13235 for(var i = start; i <= end; i++) {
13236 r[r.length] = items[i];
13239 for(var i = start; i >= end; i--) {
13240 r[r.length] = items[i];
13247 * Filter the <i>objects</i> in this collection by a specific property.
13248 * Returns a new collection that has been filtered.
13249 * @param {String} property A property on your objects
13250 * @param {String/RegExp} value Either string that the property values
13251 * should start with or a RegExp to test against the property
13252 * @return {MixedCollection} The new filtered collection
13254 filter : function(property, value){
13255 if(!value.exec){ // not a regex
13256 value = String(value);
13257 if(value.length == 0){
13258 return this.clone();
13260 value = new RegExp("^" + Roo.escapeRe(value), "i");
13262 return this.filterBy(function(o){
13263 return o && value.test(o[property]);
13268 * Filter by a function. * Returns a new collection that has been filtered.
13269 * The passed function will be called with each
13270 * object in the collection. If the function returns true, the value is included
13271 * otherwise it is filtered.
13272 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13273 * @param {Object} scope (optional) The scope of the function (defaults to this)
13274 * @return {MixedCollection} The new filtered collection
13276 filterBy : function(fn, scope){
13277 var r = new Roo.util.MixedCollection();
13278 r.getKey = this.getKey;
13279 var k = this.keys, it = this.items;
13280 for(var i = 0, len = it.length; i < len; i++){
13281 if(fn.call(scope||this, it[i], k[i])){
13282 r.add(k[i], it[i]);
13289 * Creates a duplicate of this collection
13290 * @return {MixedCollection}
13292 clone : function(){
13293 var r = new Roo.util.MixedCollection();
13294 var k = this.keys, it = this.items;
13295 for(var i = 0, len = it.length; i < len; i++){
13296 r.add(k[i], it[i]);
13298 r.getKey = this.getKey;
13303 * Returns the item associated with the passed key or index.
13305 * @param {String/Number} key The key or index of the item.
13306 * @return {Object} The item associated with the passed key.
13308 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13310 * Ext JS Library 1.1.1
13311 * Copyright(c) 2006-2007, Ext JS, LLC.
13313 * Originally Released Under LGPL - original licence link has changed is not relivant.
13316 * <script type="text/javascript">
13319 * @class Roo.util.JSON
13320 * Modified version of Douglas Crockford"s json.js that doesn"t
13321 * mess with the Object prototype
13322 * http://www.json.org/js.html
13325 Roo.util.JSON = new (function(){
13326 var useHasOwn = {}.hasOwnProperty ? true : false;
13328 // crashes Safari in some instances
13329 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13331 var pad = function(n) {
13332 return n < 10 ? "0" + n : n;
13345 var encodeString = function(s){
13346 if (/["\\\x00-\x1f]/.test(s)) {
13347 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13352 c = b.charCodeAt();
13354 Math.floor(c / 16).toString(16) +
13355 (c % 16).toString(16);
13358 return '"' + s + '"';
13361 var encodeArray = function(o){
13362 var a = ["["], b, i, l = o.length, v;
13363 for (i = 0; i < l; i += 1) {
13365 switch (typeof v) {
13374 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13382 var encodeDate = function(o){
13383 return '"' + o.getFullYear() + "-" +
13384 pad(o.getMonth() + 1) + "-" +
13385 pad(o.getDate()) + "T" +
13386 pad(o.getHours()) + ":" +
13387 pad(o.getMinutes()) + ":" +
13388 pad(o.getSeconds()) + '"';
13392 * Encodes an Object, Array or other value
13393 * @param {Mixed} o The variable to encode
13394 * @return {String} The JSON string
13396 this.encode = function(o)
13398 // should this be extended to fully wrap stringify..
13400 if(typeof o == "undefined" || o === null){
13402 }else if(o instanceof Array){
13403 return encodeArray(o);
13404 }else if(o instanceof Date){
13405 return encodeDate(o);
13406 }else if(typeof o == "string"){
13407 return encodeString(o);
13408 }else if(typeof o == "number"){
13409 return isFinite(o) ? String(o) : "null";
13410 }else if(typeof o == "boolean"){
13413 var a = ["{"], b, i, v;
13415 if(!useHasOwn || o.hasOwnProperty(i)) {
13417 switch (typeof v) {
13426 a.push(this.encode(i), ":",
13427 v === null ? "null" : this.encode(v));
13438 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13439 * @param {String} json The JSON string
13440 * @return {Object} The resulting object
13442 this.decode = function(json){
13444 return /** eval:var:json */ eval("(" + json + ')');
13448 * Shorthand for {@link Roo.util.JSON#encode}
13449 * @member Roo encode
13451 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13453 * Shorthand for {@link Roo.util.JSON#decode}
13454 * @member Roo decode
13456 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13459 * Ext JS Library 1.1.1
13460 * Copyright(c) 2006-2007, Ext JS, LLC.
13462 * Originally Released Under LGPL - original licence link has changed is not relivant.
13465 * <script type="text/javascript">
13469 * @class Roo.util.Format
13470 * Reusable data formatting functions
13473 Roo.util.Format = function(){
13474 var trimRe = /^\s+|\s+$/g;
13477 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13478 * @param {String} value The string to truncate
13479 * @param {Number} length The maximum length to allow before truncating
13480 * @return {String} The converted text
13482 ellipsis : function(value, len){
13483 if(value && value.length > len){
13484 return value.substr(0, len-3)+"...";
13490 * Checks a reference and converts it to empty string if it is undefined
13491 * @param {Mixed} value Reference to check
13492 * @return {Mixed} Empty string if converted, otherwise the original value
13494 undef : function(value){
13495 return typeof value != "undefined" ? value : "";
13499 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13500 * @param {String} value The string to encode
13501 * @return {String} The encoded text
13503 htmlEncode : function(value){
13504 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13508 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13509 * @param {String} value The string to decode
13510 * @return {String} The decoded text
13512 htmlDecode : function(value){
13513 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13517 * Trims any whitespace from either side of a string
13518 * @param {String} value The text to trim
13519 * @return {String} The trimmed text
13521 trim : function(value){
13522 return String(value).replace(trimRe, "");
13526 * Returns a substring from within an original string
13527 * @param {String} value The original text
13528 * @param {Number} start The start index of the substring
13529 * @param {Number} length The length of the substring
13530 * @return {String} The substring
13532 substr : function(value, start, length){
13533 return String(value).substr(start, length);
13537 * Converts a string to all lower case letters
13538 * @param {String} value The text to convert
13539 * @return {String} The converted text
13541 lowercase : function(value){
13542 return String(value).toLowerCase();
13546 * Converts a string to all upper case letters
13547 * @param {String} value The text to convert
13548 * @return {String} The converted text
13550 uppercase : function(value){
13551 return String(value).toUpperCase();
13555 * Converts the first character only of a string to upper case
13556 * @param {String} value The text to convert
13557 * @return {String} The converted text
13559 capitalize : function(value){
13560 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13564 call : function(value, fn){
13565 if(arguments.length > 2){
13566 var args = Array.prototype.slice.call(arguments, 2);
13567 args.unshift(value);
13569 return /** eval:var:value */ eval(fn).apply(window, args);
13571 /** eval:var:value */
13572 return /** eval:var:value */ eval(fn).call(window, value);
13578 * safer version of Math.toFixed..??/
13579 * @param {Number/String} value The numeric value to format
13580 * @param {Number/String} value Decimal places
13581 * @return {String} The formatted currency string
13583 toFixed : function(v, n)
13585 // why not use to fixed - precision is buggered???
13587 return Math.round(v-0);
13589 var fact = Math.pow(10,n+1);
13590 v = (Math.round((v-0)*fact))/fact;
13591 var z = (''+fact).substring(2);
13592 if (v == Math.floor(v)) {
13593 return Math.floor(v) + '.' + z;
13596 // now just padd decimals..
13597 var ps = String(v).split('.');
13598 var fd = (ps[1] + z);
13599 var r = fd.substring(0,n);
13600 var rm = fd.substring(n);
13602 return ps[0] + '.' + r;
13604 r*=1; // turn it into a number;
13606 if (String(r).length != n) {
13609 r = String(r).substring(1); // chop the end off.
13612 return ps[0] + '.' + r;
13617 * Format a number as US currency
13618 * @param {Number/String} value The numeric value to format
13619 * @return {String} The formatted currency string
13621 usMoney : function(v){
13622 return '$' + Roo.util.Format.number(v);
13627 * eventually this should probably emulate php's number_format
13628 * @param {Number/String} value The numeric value to format
13629 * @param {Number} decimals number of decimal places
13630 * @return {String} The formatted currency string
13632 number : function(v,decimals)
13634 // multiply and round.
13635 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13636 var mul = Math.pow(10, decimals);
13637 var zero = String(mul).substring(1);
13638 v = (Math.round((v-0)*mul))/mul;
13640 // if it's '0' number.. then
13642 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13644 var ps = v.split('.');
13648 var r = /(\d+)(\d{3})/;
13650 while (r.test(whole)) {
13651 whole = whole.replace(r, '$1' + ',' + '$2');
13657 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13658 // does not have decimals
13659 (decimals ? ('.' + zero) : '');
13662 return whole + sub ;
13666 * Parse a value into a formatted date using the specified format pattern.
13667 * @param {Mixed} value The value to format
13668 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13669 * @return {String} The formatted date string
13671 date : function(v, format){
13675 if(!(v instanceof Date)){
13676 v = new Date(Date.parse(v));
13678 return v.dateFormat(format || Roo.util.Format.defaults.date);
13682 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13683 * @param {String} format Any valid date format string
13684 * @return {Function} The date formatting function
13686 dateRenderer : function(format){
13687 return function(v){
13688 return Roo.util.Format.date(v, format);
13693 stripTagsRE : /<\/?[^>]+>/gi,
13696 * Strips all HTML tags
13697 * @param {Mixed} value The text from which to strip tags
13698 * @return {String} The stripped text
13700 stripTags : function(v){
13701 return !v ? v : String(v).replace(this.stripTagsRE, "");
13705 Roo.util.Format.defaults = {
13709 * Ext JS Library 1.1.1
13710 * Copyright(c) 2006-2007, Ext JS, LLC.
13712 * Originally Released Under LGPL - original licence link has changed is not relivant.
13715 * <script type="text/javascript">
13722 * @class Roo.MasterTemplate
13723 * @extends Roo.Template
13724 * Provides a template that can have child templates. The syntax is:
13726 var t = new Roo.MasterTemplate(
13727 '<select name="{name}">',
13728 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13731 t.add('options', {value: 'foo', text: 'bar'});
13732 // or you can add multiple child elements in one shot
13733 t.addAll('options', [
13734 {value: 'foo', text: 'bar'},
13735 {value: 'foo2', text: 'bar2'},
13736 {value: 'foo3', text: 'bar3'}
13738 // then append, applying the master template values
13739 t.append('my-form', {name: 'my-select'});
13741 * A name attribute for the child template is not required if you have only one child
13742 * template or you want to refer to them by index.
13744 Roo.MasterTemplate = function(){
13745 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13746 this.originalHtml = this.html;
13748 var m, re = this.subTemplateRe;
13751 while(m = re.exec(this.html)){
13752 var name = m[1], content = m[2];
13757 tpl : new Roo.Template(content)
13760 st[name] = st[subIndex];
13762 st[subIndex].tpl.compile();
13763 st[subIndex].tpl.call = this.call.createDelegate(this);
13766 this.subCount = subIndex;
13769 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13771 * The regular expression used to match sub templates
13775 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13778 * Applies the passed values to a child template.
13779 * @param {String/Number} name (optional) The name or index of the child template
13780 * @param {Array/Object} values The values to be applied to the template
13781 * @return {MasterTemplate} this
13783 add : function(name, values){
13784 if(arguments.length == 1){
13785 values = arguments[0];
13788 var s = this.subs[name];
13789 s.buffer[s.buffer.length] = s.tpl.apply(values);
13794 * Applies all the passed values to a child template.
13795 * @param {String/Number} name (optional) The name or index of the child template
13796 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13797 * @param {Boolean} reset (optional) True to reset the template first
13798 * @return {MasterTemplate} this
13800 fill : function(name, values, reset){
13802 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13810 for(var i = 0, len = values.length; i < len; i++){
13811 this.add(name, values[i]);
13817 * Resets the template for reuse
13818 * @return {MasterTemplate} this
13820 reset : function(){
13822 for(var i = 0; i < this.subCount; i++){
13828 applyTemplate : function(values){
13830 var replaceIndex = -1;
13831 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13832 return s[++replaceIndex].buffer.join("");
13834 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13837 apply : function(){
13838 return this.applyTemplate.apply(this, arguments);
13841 compile : function(){return this;}
13845 * Alias for fill().
13848 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13850 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13851 * var tpl = Roo.MasterTemplate.from('element-id');
13852 * @param {String/HTMLElement} el
13853 * @param {Object} config
13856 Roo.MasterTemplate.from = function(el, config){
13857 el = Roo.getDom(el);
13858 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13861 * Ext JS Library 1.1.1
13862 * Copyright(c) 2006-2007, Ext JS, LLC.
13864 * Originally Released Under LGPL - original licence link has changed is not relivant.
13867 * <script type="text/javascript">
13872 * @class Roo.util.CSS
13873 * Utility class for manipulating CSS rules
13876 Roo.util.CSS = function(){
13878 var doc = document;
13880 var camelRe = /(-[a-z])/gi;
13881 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13885 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13886 * tag and appended to the HEAD of the document.
13887 * @param {String|Object} cssText The text containing the css rules
13888 * @param {String} id An id to add to the stylesheet for later removal
13889 * @return {StyleSheet}
13891 createStyleSheet : function(cssText, id){
13893 var head = doc.getElementsByTagName("head")[0];
13894 var nrules = doc.createElement("style");
13895 nrules.setAttribute("type", "text/css");
13897 nrules.setAttribute("id", id);
13899 if (typeof(cssText) != 'string') {
13900 // support object maps..
13901 // not sure if this a good idea..
13902 // perhaps it should be merged with the general css handling
13903 // and handle js style props.
13904 var cssTextNew = [];
13905 for(var n in cssText) {
13907 for(var k in cssText[n]) {
13908 citems.push( k + ' : ' +cssText[n][k] + ';' );
13910 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13913 cssText = cssTextNew.join("\n");
13919 head.appendChild(nrules);
13920 ss = nrules.styleSheet;
13921 ss.cssText = cssText;
13924 nrules.appendChild(doc.createTextNode(cssText));
13926 nrules.cssText = cssText;
13928 head.appendChild(nrules);
13929 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13931 this.cacheStyleSheet(ss);
13936 * Removes a style or link tag by id
13937 * @param {String} id The id of the tag
13939 removeStyleSheet : function(id){
13940 var existing = doc.getElementById(id);
13942 existing.parentNode.removeChild(existing);
13947 * Dynamically swaps an existing stylesheet reference for a new one
13948 * @param {String} id The id of an existing link tag to remove
13949 * @param {String} url The href of the new stylesheet to include
13951 swapStyleSheet : function(id, url){
13952 this.removeStyleSheet(id);
13953 var ss = doc.createElement("link");
13954 ss.setAttribute("rel", "stylesheet");
13955 ss.setAttribute("type", "text/css");
13956 ss.setAttribute("id", id);
13957 ss.setAttribute("href", url);
13958 doc.getElementsByTagName("head")[0].appendChild(ss);
13962 * Refresh the rule cache if you have dynamically added stylesheets
13963 * @return {Object} An object (hash) of rules indexed by selector
13965 refreshCache : function(){
13966 return this.getRules(true);
13970 cacheStyleSheet : function(stylesheet){
13974 try{// try catch for cross domain access issue
13975 var ssRules = stylesheet.cssRules || stylesheet.rules;
13976 for(var j = ssRules.length-1; j >= 0; --j){
13977 rules[ssRules[j].selectorText] = ssRules[j];
13983 * Gets all css rules for the document
13984 * @param {Boolean} refreshCache true to refresh the internal cache
13985 * @return {Object} An object (hash) of rules indexed by selector
13987 getRules : function(refreshCache){
13988 if(rules == null || refreshCache){
13990 var ds = doc.styleSheets;
13991 for(var i =0, len = ds.length; i < len; i++){
13993 this.cacheStyleSheet(ds[i]);
14001 * Gets an an individual CSS rule by selector(s)
14002 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14003 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14004 * @return {CSSRule} The CSS rule or null if one is not found
14006 getRule : function(selector, refreshCache){
14007 var rs = this.getRules(refreshCache);
14008 if(!(selector instanceof Array)){
14009 return rs[selector];
14011 for(var i = 0; i < selector.length; i++){
14012 if(rs[selector[i]]){
14013 return rs[selector[i]];
14021 * Updates a rule property
14022 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14023 * @param {String} property The css property
14024 * @param {String} value The new value for the property
14025 * @return {Boolean} true If a rule was found and updated
14027 updateRule : function(selector, property, value){
14028 if(!(selector instanceof Array)){
14029 var rule = this.getRule(selector);
14031 rule.style[property.replace(camelRe, camelFn)] = value;
14035 for(var i = 0; i < selector.length; i++){
14036 if(this.updateRule(selector[i], property, value)){
14046 * Ext JS Library 1.1.1
14047 * Copyright(c) 2006-2007, Ext JS, LLC.
14049 * Originally Released Under LGPL - original licence link has changed is not relivant.
14052 * <script type="text/javascript">
14058 * @class Roo.util.ClickRepeater
14059 * @extends Roo.util.Observable
14061 * A wrapper class which can be applied to any element. Fires a "click" event while the
14062 * mouse is pressed. The interval between firings may be specified in the config but
14063 * defaults to 10 milliseconds.
14065 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14067 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14068 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14069 * Similar to an autorepeat key delay.
14070 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14071 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14072 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14073 * "interval" and "delay" are ignored. "immediate" is honored.
14074 * @cfg {Boolean} preventDefault True to prevent the default click event
14075 * @cfg {Boolean} stopDefault True to stop the default click event
14078 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14079 * 2007-02-02 jvs Renamed to ClickRepeater
14080 * 2007-02-03 jvs Modifications for FF Mac and Safari
14083 * @param {String/HTMLElement/Element} el The element to listen on
14084 * @param {Object} config
14086 Roo.util.ClickRepeater = function(el, config)
14088 this.el = Roo.get(el);
14089 this.el.unselectable();
14091 Roo.apply(this, config);
14096 * Fires when the mouse button is depressed.
14097 * @param {Roo.util.ClickRepeater} this
14099 "mousedown" : true,
14102 * Fires on a specified interval during the time the element is pressed.
14103 * @param {Roo.util.ClickRepeater} this
14108 * Fires when the mouse key is released.
14109 * @param {Roo.util.ClickRepeater} this
14114 this.el.on("mousedown", this.handleMouseDown, this);
14115 if(this.preventDefault || this.stopDefault){
14116 this.el.on("click", function(e){
14117 if(this.preventDefault){
14118 e.preventDefault();
14120 if(this.stopDefault){
14126 // allow inline handler
14128 this.on("click", this.handler, this.scope || this);
14131 Roo.util.ClickRepeater.superclass.constructor.call(this);
14134 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14137 preventDefault : true,
14138 stopDefault : false,
14142 handleMouseDown : function(){
14143 clearTimeout(this.timer);
14145 if(this.pressClass){
14146 this.el.addClass(this.pressClass);
14148 this.mousedownTime = new Date();
14150 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14151 this.el.on("mouseout", this.handleMouseOut, this);
14153 this.fireEvent("mousedown", this);
14154 this.fireEvent("click", this);
14156 this.timer = this.click.defer(this.delay || this.interval, this);
14160 click : function(){
14161 this.fireEvent("click", this);
14162 this.timer = this.click.defer(this.getInterval(), this);
14166 getInterval: function(){
14167 if(!this.accelerate){
14168 return this.interval;
14170 var pressTime = this.mousedownTime.getElapsed();
14171 if(pressTime < 500){
14173 }else if(pressTime < 1700){
14175 }else if(pressTime < 2600){
14177 }else if(pressTime < 3500){
14179 }else if(pressTime < 4400){
14181 }else if(pressTime < 5300){
14183 }else if(pressTime < 6200){
14191 handleMouseOut : function(){
14192 clearTimeout(this.timer);
14193 if(this.pressClass){
14194 this.el.removeClass(this.pressClass);
14196 this.el.on("mouseover", this.handleMouseReturn, this);
14200 handleMouseReturn : function(){
14201 this.el.un("mouseover", this.handleMouseReturn);
14202 if(this.pressClass){
14203 this.el.addClass(this.pressClass);
14209 handleMouseUp : function(){
14210 clearTimeout(this.timer);
14211 this.el.un("mouseover", this.handleMouseReturn);
14212 this.el.un("mouseout", this.handleMouseOut);
14213 Roo.get(document).un("mouseup", this.handleMouseUp);
14214 this.el.removeClass(this.pressClass);
14215 this.fireEvent("mouseup", this);
14219 * Ext JS Library 1.1.1
14220 * Copyright(c) 2006-2007, Ext JS, LLC.
14222 * Originally Released Under LGPL - original licence link has changed is not relivant.
14225 * <script type="text/javascript">
14230 * @class Roo.KeyNav
14231 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14232 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14233 * way to implement custom navigation schemes for any UI component.</p>
14234 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14235 * pageUp, pageDown, del, home, end. Usage:</p>
14237 var nav = new Roo.KeyNav("my-element", {
14238 "left" : function(e){
14239 this.moveLeft(e.ctrlKey);
14241 "right" : function(e){
14242 this.moveRight(e.ctrlKey);
14244 "enter" : function(e){
14251 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14252 * @param {Object} config The config
14254 Roo.KeyNav = function(el, config){
14255 this.el = Roo.get(el);
14256 Roo.apply(this, config);
14257 if(!this.disabled){
14258 this.disabled = true;
14263 Roo.KeyNav.prototype = {
14265 * @cfg {Boolean} disabled
14266 * True to disable this KeyNav instance (defaults to false)
14270 * @cfg {String} defaultEventAction
14271 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14272 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14273 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14275 defaultEventAction: "stopEvent",
14277 * @cfg {Boolean} forceKeyDown
14278 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14279 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14280 * handle keydown instead of keypress.
14282 forceKeyDown : false,
14285 prepareEvent : function(e){
14286 var k = e.getKey();
14287 var h = this.keyToHandler[k];
14288 //if(h && this[h]){
14289 // e.stopPropagation();
14291 if(Roo.isSafari && h && k >= 37 && k <= 40){
14297 relay : function(e){
14298 var k = e.getKey();
14299 var h = this.keyToHandler[k];
14301 if(this.doRelay(e, this[h], h) !== true){
14302 e[this.defaultEventAction]();
14308 doRelay : function(e, h, hname){
14309 return h.call(this.scope || this, e);
14312 // possible handlers
14326 // quick lookup hash
14343 * Enable this KeyNav
14345 enable: function(){
14347 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14348 // the EventObject will normalize Safari automatically
14349 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14350 this.el.on("keydown", this.relay, this);
14352 this.el.on("keydown", this.prepareEvent, this);
14353 this.el.on("keypress", this.relay, this);
14355 this.disabled = false;
14360 * Disable this KeyNav
14362 disable: function(){
14363 if(!this.disabled){
14364 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14365 this.el.un("keydown", this.relay);
14367 this.el.un("keydown", this.prepareEvent);
14368 this.el.un("keypress", this.relay);
14370 this.disabled = true;
14375 * Ext JS Library 1.1.1
14376 * Copyright(c) 2006-2007, Ext JS, LLC.
14378 * Originally Released Under LGPL - original licence link has changed is not relivant.
14381 * <script type="text/javascript">
14386 * @class Roo.KeyMap
14387 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14388 * The constructor accepts the same config object as defined by {@link #addBinding}.
14389 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14390 * combination it will call the function with this signature (if the match is a multi-key
14391 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14392 * A KeyMap can also handle a string representation of keys.<br />
14395 // map one key by key code
14396 var map = new Roo.KeyMap("my-element", {
14397 key: 13, // or Roo.EventObject.ENTER
14402 // map multiple keys to one action by string
14403 var map = new Roo.KeyMap("my-element", {
14409 // map multiple keys to multiple actions by strings and array of codes
14410 var map = new Roo.KeyMap("my-element", [
14413 fn: function(){ alert("Return was pressed"); }
14416 fn: function(){ alert('a, b or c was pressed'); }
14421 fn: function(){ alert('Control + shift + tab was pressed.'); }
14425 * <b>Note: A KeyMap starts enabled</b>
14427 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14428 * @param {Object} config The config (see {@link #addBinding})
14429 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14431 Roo.KeyMap = function(el, config, eventName){
14432 this.el = Roo.get(el);
14433 this.eventName = eventName || "keydown";
14434 this.bindings = [];
14436 this.addBinding(config);
14441 Roo.KeyMap.prototype = {
14443 * True to stop the event from bubbling and prevent the default browser action if the
14444 * key was handled by the KeyMap (defaults to false)
14450 * Add a new binding to this KeyMap. The following config object properties are supported:
14452 Property Type Description
14453 ---------- --------------- ----------------------------------------------------------------------
14454 key String/Array A single keycode or an array of keycodes to handle
14455 shift Boolean True to handle key only when shift is pressed (defaults to false)
14456 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14457 alt Boolean True to handle key only when alt is pressed (defaults to false)
14458 fn Function The function to call when KeyMap finds the expected key combination
14459 scope Object The scope of the callback function
14465 var map = new Roo.KeyMap(document, {
14466 key: Roo.EventObject.ENTER,
14471 //Add a new binding to the existing KeyMap later
14479 * @param {Object/Array} config A single KeyMap config or an array of configs
14481 addBinding : function(config){
14482 if(config instanceof Array){
14483 for(var i = 0, len = config.length; i < len; i++){
14484 this.addBinding(config[i]);
14488 var keyCode = config.key,
14489 shift = config.shift,
14490 ctrl = config.ctrl,
14493 scope = config.scope;
14494 if(typeof keyCode == "string"){
14496 var keyString = keyCode.toUpperCase();
14497 for(var j = 0, len = keyString.length; j < len; j++){
14498 ks.push(keyString.charCodeAt(j));
14502 var keyArray = keyCode instanceof Array;
14503 var handler = function(e){
14504 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14505 var k = e.getKey();
14507 for(var i = 0, len = keyCode.length; i < len; i++){
14508 if(keyCode[i] == k){
14509 if(this.stopEvent){
14512 fn.call(scope || window, k, e);
14518 if(this.stopEvent){
14521 fn.call(scope || window, k, e);
14526 this.bindings.push(handler);
14530 * Shorthand for adding a single key listener
14531 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14532 * following options:
14533 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14534 * @param {Function} fn The function to call
14535 * @param {Object} scope (optional) The scope of the function
14537 on : function(key, fn, scope){
14538 var keyCode, shift, ctrl, alt;
14539 if(typeof key == "object" && !(key instanceof Array)){
14558 handleKeyDown : function(e){
14559 if(this.enabled){ //just in case
14560 var b = this.bindings;
14561 for(var i = 0, len = b.length; i < len; i++){
14562 b[i].call(this, e);
14568 * Returns true if this KeyMap is enabled
14569 * @return {Boolean}
14571 isEnabled : function(){
14572 return this.enabled;
14576 * Enables this KeyMap
14578 enable: function(){
14580 this.el.on(this.eventName, this.handleKeyDown, this);
14581 this.enabled = true;
14586 * Disable this KeyMap
14588 disable: function(){
14590 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14591 this.enabled = false;
14596 * Ext JS Library 1.1.1
14597 * Copyright(c) 2006-2007, Ext JS, LLC.
14599 * Originally Released Under LGPL - original licence link has changed is not relivant.
14602 * <script type="text/javascript">
14607 * @class Roo.util.TextMetrics
14608 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14609 * wide, in pixels, a given block of text will be.
14612 Roo.util.TextMetrics = function(){
14616 * Measures the size of the specified text
14617 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14618 * that can affect the size of the rendered text
14619 * @param {String} text The text to measure
14620 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14621 * in order to accurately measure the text height
14622 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14624 measure : function(el, text, fixedWidth){
14626 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14629 shared.setFixedWidth(fixedWidth || 'auto');
14630 return shared.getSize(text);
14634 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14635 * the overhead of multiple calls to initialize the style properties on each measurement.
14636 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14637 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14638 * in order to accurately measure the text height
14639 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14641 createInstance : function(el, fixedWidth){
14642 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14649 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14650 var ml = new Roo.Element(document.createElement('div'));
14651 document.body.appendChild(ml.dom);
14652 ml.position('absolute');
14653 ml.setLeftTop(-1000, -1000);
14657 ml.setWidth(fixedWidth);
14662 * Returns the size of the specified text based on the internal element's style and width properties
14663 * @memberOf Roo.util.TextMetrics.Instance#
14664 * @param {String} text The text to measure
14665 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14667 getSize : function(text){
14669 var s = ml.getSize();
14675 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14676 * that can affect the size of the rendered text
14677 * @memberOf Roo.util.TextMetrics.Instance#
14678 * @param {String/HTMLElement} el The element, dom node or id
14680 bind : function(el){
14682 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14687 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14688 * to set a fixed width in order to accurately measure the text height.
14689 * @memberOf Roo.util.TextMetrics.Instance#
14690 * @param {Number} width The width to set on the element
14692 setFixedWidth : function(width){
14693 ml.setWidth(width);
14697 * Returns the measured width of the specified text
14698 * @memberOf Roo.util.TextMetrics.Instance#
14699 * @param {String} text The text to measure
14700 * @return {Number} width The width in pixels
14702 getWidth : function(text){
14703 ml.dom.style.width = 'auto';
14704 return this.getSize(text).width;
14708 * Returns the measured height of the specified text. For multiline text, be sure to call
14709 * {@link #setFixedWidth} if necessary.
14710 * @memberOf Roo.util.TextMetrics.Instance#
14711 * @param {String} text The text to measure
14712 * @return {Number} height The height in pixels
14714 getHeight : function(text){
14715 return this.getSize(text).height;
14719 instance.bind(bindTo);
14724 // backwards compat
14725 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14727 * Ext JS Library 1.1.1
14728 * Copyright(c) 2006-2007, Ext JS, LLC.
14730 * Originally Released Under LGPL - original licence link has changed is not relivant.
14733 * <script type="text/javascript">
14737 * @class Roo.state.Provider
14738 * Abstract base class for state provider implementations. This class provides methods
14739 * for encoding and decoding <b>typed</b> variables including dates and defines the
14740 * Provider interface.
14742 Roo.state.Provider = function(){
14744 * @event statechange
14745 * Fires when a state change occurs.
14746 * @param {Provider} this This state provider
14747 * @param {String} key The state key which was changed
14748 * @param {String} value The encoded value for the state
14751 "statechange": true
14754 Roo.state.Provider.superclass.constructor.call(this);
14756 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14758 * Returns the current value for a key
14759 * @param {String} name The key name
14760 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14761 * @return {Mixed} The state data
14763 get : function(name, defaultValue){
14764 return typeof this.state[name] == "undefined" ?
14765 defaultValue : this.state[name];
14769 * Clears a value from the state
14770 * @param {String} name The key name
14772 clear : function(name){
14773 delete this.state[name];
14774 this.fireEvent("statechange", this, name, null);
14778 * Sets the value for a key
14779 * @param {String} name The key name
14780 * @param {Mixed} value The value to set
14782 set : function(name, value){
14783 this.state[name] = value;
14784 this.fireEvent("statechange", this, name, value);
14788 * Decodes a string previously encoded with {@link #encodeValue}.
14789 * @param {String} value The value to decode
14790 * @return {Mixed} The decoded value
14792 decodeValue : function(cookie){
14793 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14794 var matches = re.exec(unescape(cookie));
14795 if(!matches || !matches[1]) return; // non state cookie
14796 var type = matches[1];
14797 var v = matches[2];
14800 return parseFloat(v);
14802 return new Date(Date.parse(v));
14807 var values = v.split("^");
14808 for(var i = 0, len = values.length; i < len; i++){
14809 all.push(this.decodeValue(values[i]));
14814 var values = v.split("^");
14815 for(var i = 0, len = values.length; i < len; i++){
14816 var kv = values[i].split("=");
14817 all[kv[0]] = this.decodeValue(kv[1]);
14826 * Encodes a value including type information. Decode with {@link #decodeValue}.
14827 * @param {Mixed} value The value to encode
14828 * @return {String} The encoded value
14830 encodeValue : function(v){
14832 if(typeof v == "number"){
14834 }else if(typeof v == "boolean"){
14835 enc = "b:" + (v ? "1" : "0");
14836 }else if(v instanceof Date){
14837 enc = "d:" + v.toGMTString();
14838 }else if(v instanceof Array){
14840 for(var i = 0, len = v.length; i < len; i++){
14841 flat += this.encodeValue(v[i]);
14842 if(i != len-1) flat += "^";
14845 }else if(typeof v == "object"){
14848 if(typeof v[key] != "function"){
14849 flat += key + "=" + this.encodeValue(v[key]) + "^";
14852 enc = "o:" + flat.substring(0, flat.length-1);
14856 return escape(enc);
14862 * Ext JS Library 1.1.1
14863 * Copyright(c) 2006-2007, Ext JS, LLC.
14865 * Originally Released Under LGPL - original licence link has changed is not relivant.
14868 * <script type="text/javascript">
14871 * @class Roo.state.Manager
14872 * This is the global state manager. By default all components that are "state aware" check this class
14873 * for state information if you don't pass them a custom state provider. In order for this class
14874 * to be useful, it must be initialized with a provider when your application initializes.
14876 // in your initialization function
14878 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14880 // supposed you have a {@link Roo.BorderLayout}
14881 var layout = new Roo.BorderLayout(...);
14882 layout.restoreState();
14883 // or a {Roo.BasicDialog}
14884 var dialog = new Roo.BasicDialog(...);
14885 dialog.restoreState();
14889 Roo.state.Manager = function(){
14890 var provider = new Roo.state.Provider();
14894 * Configures the default state provider for your application
14895 * @param {Provider} stateProvider The state provider to set
14897 setProvider : function(stateProvider){
14898 provider = stateProvider;
14902 * Returns the current value for a key
14903 * @param {String} name The key name
14904 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14905 * @return {Mixed} The state data
14907 get : function(key, defaultValue){
14908 return provider.get(key, defaultValue);
14912 * Sets the value for a key
14913 * @param {String} name The key name
14914 * @param {Mixed} value The state data
14916 set : function(key, value){
14917 provider.set(key, value);
14921 * Clears a value from the state
14922 * @param {String} name The key name
14924 clear : function(key){
14925 provider.clear(key);
14929 * Gets the currently configured state provider
14930 * @return {Provider} The state provider
14932 getProvider : function(){
14939 * Ext JS Library 1.1.1
14940 * Copyright(c) 2006-2007, Ext JS, LLC.
14942 * Originally Released Under LGPL - original licence link has changed is not relivant.
14945 * <script type="text/javascript">
14948 * @class Roo.state.CookieProvider
14949 * @extends Roo.state.Provider
14950 * The default Provider implementation which saves state via cookies.
14953 var cp = new Roo.state.CookieProvider({
14955 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14956 domain: "roojs.com"
14958 Roo.state.Manager.setProvider(cp);
14960 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14961 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14962 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14963 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14964 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14965 * domain the page is running on including the 'www' like 'www.roojs.com')
14966 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14968 * Create a new CookieProvider
14969 * @param {Object} config The configuration object
14971 Roo.state.CookieProvider = function(config){
14972 Roo.state.CookieProvider.superclass.constructor.call(this);
14974 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14975 this.domain = null;
14976 this.secure = false;
14977 Roo.apply(this, config);
14978 this.state = this.readCookies();
14981 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14983 set : function(name, value){
14984 if(typeof value == "undefined" || value === null){
14988 this.setCookie(name, value);
14989 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14993 clear : function(name){
14994 this.clearCookie(name);
14995 Roo.state.CookieProvider.superclass.clear.call(this, name);
14999 readCookies : function(){
15001 var c = document.cookie + ";";
15002 var re = /\s?(.*?)=(.*?);/g;
15004 while((matches = re.exec(c)) != null){
15005 var name = matches[1];
15006 var value = matches[2];
15007 if(name && name.substring(0,3) == "ys-"){
15008 cookies[name.substr(3)] = this.decodeValue(value);
15015 setCookie : function(name, value){
15016 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15017 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15018 ((this.path == null) ? "" : ("; path=" + this.path)) +
15019 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15020 ((this.secure == true) ? "; secure" : "");
15024 clearCookie : function(name){
15025 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15026 ((this.path == null) ? "" : ("; path=" + this.path)) +
15027 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15028 ((this.secure == true) ? "; secure" : "");
15032 * Ext JS Library 1.1.1
15033 * Copyright(c) 2006-2007, Ext JS, LLC.
15035 * Originally Released Under LGPL - original licence link has changed is not relivant.
15038 * <script type="text/javascript">
15043 * @class Roo.ComponentMgr
15044 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15047 Roo.ComponentMgr = function(){
15048 var all = new Roo.util.MixedCollection();
15052 * Registers a component.
15053 * @param {Roo.Component} c The component
15055 register : function(c){
15060 * Unregisters a component.
15061 * @param {Roo.Component} c The component
15063 unregister : function(c){
15068 * Returns a component by id
15069 * @param {String} id The component id
15071 get : function(id){
15072 return all.get(id);
15076 * Registers a function that will be called when a specified component is added to ComponentMgr
15077 * @param {String} id The component id
15078 * @param {Funtction} fn The callback function
15079 * @param {Object} scope The scope of the callback
15081 onAvailable : function(id, fn, scope){
15082 all.on("add", function(index, o){
15084 fn.call(scope || o, o);
15085 all.un("add", fn, scope);
15092 * Ext JS Library 1.1.1
15093 * Copyright(c) 2006-2007, Ext JS, LLC.
15095 * Originally Released Under LGPL - original licence link has changed is not relivant.
15098 * <script type="text/javascript">
15102 * @class Roo.Component
15103 * @extends Roo.util.Observable
15104 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15105 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15106 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15107 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15108 * All visual components (widgets) that require rendering into a layout should subclass Component.
15110 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15111 * 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
15112 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15114 Roo.Component = function(config){
15115 config = config || {};
15116 if(config.tagName || config.dom || typeof config == "string"){ // element object
15117 config = {el: config, id: config.id || config};
15119 this.initialConfig = config;
15121 Roo.apply(this, config);
15125 * Fires after the component is disabled.
15126 * @param {Roo.Component} this
15131 * Fires after the component is enabled.
15132 * @param {Roo.Component} this
15136 * @event beforeshow
15137 * Fires before the component is shown. Return false to stop the show.
15138 * @param {Roo.Component} this
15143 * Fires after the component is shown.
15144 * @param {Roo.Component} this
15148 * @event beforehide
15149 * Fires before the component is hidden. Return false to stop the hide.
15150 * @param {Roo.Component} this
15155 * Fires after the component is hidden.
15156 * @param {Roo.Component} this
15160 * @event beforerender
15161 * Fires before the component is rendered. Return false to stop the render.
15162 * @param {Roo.Component} this
15164 beforerender : true,
15167 * Fires after the component is rendered.
15168 * @param {Roo.Component} this
15172 * @event beforedestroy
15173 * Fires before the component is destroyed. Return false to stop the destroy.
15174 * @param {Roo.Component} this
15176 beforedestroy : true,
15179 * Fires after the component is destroyed.
15180 * @param {Roo.Component} this
15185 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15187 Roo.ComponentMgr.register(this);
15188 Roo.Component.superclass.constructor.call(this);
15189 this.initComponent();
15190 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15191 this.render(this.renderTo);
15192 delete this.renderTo;
15197 Roo.Component.AUTO_ID = 1000;
15199 Roo.extend(Roo.Component, Roo.util.Observable, {
15201 * @scope Roo.Component.prototype
15203 * true if this component is hidden. Read-only.
15208 * true if this component is disabled. Read-only.
15213 * true if this component has been rendered. Read-only.
15217 /** @cfg {String} disableClass
15218 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15220 disabledClass : "x-item-disabled",
15221 /** @cfg {Boolean} allowDomMove
15222 * Whether the component can move the Dom node when rendering (defaults to true).
15224 allowDomMove : true,
15225 /** @cfg {String} hideMode (display|visibility)
15226 * How this component should hidden. Supported values are
15227 * "visibility" (css visibility), "offsets" (negative offset position) and
15228 * "display" (css display) - defaults to "display".
15230 hideMode: 'display',
15233 ctype : "Roo.Component",
15236 * @cfg {String} actionMode
15237 * which property holds the element that used for hide() / show() / disable() / enable()
15243 getActionEl : function(){
15244 return this[this.actionMode];
15247 initComponent : Roo.emptyFn,
15249 * If this is a lazy rendering component, render it to its container element.
15250 * @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.
15252 render : function(container, position){
15253 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15254 if(!container && this.el){
15255 this.el = Roo.get(this.el);
15256 container = this.el.dom.parentNode;
15257 this.allowDomMove = false;
15259 this.container = Roo.get(container);
15260 this.rendered = true;
15261 if(position !== undefined){
15262 if(typeof position == 'number'){
15263 position = this.container.dom.childNodes[position];
15265 position = Roo.getDom(position);
15268 this.onRender(this.container, position || null);
15270 this.el.addClass(this.cls);
15274 this.el.applyStyles(this.style);
15277 this.fireEvent("render", this);
15278 this.afterRender(this.container);
15290 // default function is not really useful
15291 onRender : function(ct, position){
15293 this.el = Roo.get(this.el);
15294 if(this.allowDomMove !== false){
15295 ct.dom.insertBefore(this.el.dom, position);
15301 getAutoCreate : function(){
15302 var cfg = typeof this.autoCreate == "object" ?
15303 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15304 if(this.id && !cfg.id){
15311 afterRender : Roo.emptyFn,
15314 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15315 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15317 destroy : function(){
15318 if(this.fireEvent("beforedestroy", this) !== false){
15319 this.purgeListeners();
15320 this.beforeDestroy();
15322 this.el.removeAllListeners();
15324 if(this.actionMode == "container"){
15325 this.container.remove();
15329 Roo.ComponentMgr.unregister(this);
15330 this.fireEvent("destroy", this);
15335 beforeDestroy : function(){
15340 onDestroy : function(){
15345 * Returns the underlying {@link Roo.Element}.
15346 * @return {Roo.Element} The element
15348 getEl : function(){
15353 * Returns the id of this component.
15356 getId : function(){
15361 * Try to focus this component.
15362 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15363 * @return {Roo.Component} this
15365 focus : function(selectText){
15368 if(selectText === true){
15369 this.el.dom.select();
15384 * Disable this component.
15385 * @return {Roo.Component} this
15387 disable : function(){
15391 this.disabled = true;
15392 this.fireEvent("disable", this);
15397 onDisable : function(){
15398 this.getActionEl().addClass(this.disabledClass);
15399 this.el.dom.disabled = true;
15403 * Enable this component.
15404 * @return {Roo.Component} this
15406 enable : function(){
15410 this.disabled = false;
15411 this.fireEvent("enable", this);
15416 onEnable : function(){
15417 this.getActionEl().removeClass(this.disabledClass);
15418 this.el.dom.disabled = false;
15422 * Convenience function for setting disabled/enabled by boolean.
15423 * @param {Boolean} disabled
15425 setDisabled : function(disabled){
15426 this[disabled ? "disable" : "enable"]();
15430 * Show this component.
15431 * @return {Roo.Component} this
15434 if(this.fireEvent("beforeshow", this) !== false){
15435 this.hidden = false;
15439 this.fireEvent("show", this);
15445 onShow : function(){
15446 var ae = this.getActionEl();
15447 if(this.hideMode == 'visibility'){
15448 ae.dom.style.visibility = "visible";
15449 }else if(this.hideMode == 'offsets'){
15450 ae.removeClass('x-hidden');
15452 ae.dom.style.display = "";
15457 * Hide this component.
15458 * @return {Roo.Component} this
15461 if(this.fireEvent("beforehide", this) !== false){
15462 this.hidden = true;
15466 this.fireEvent("hide", this);
15472 onHide : function(){
15473 var ae = this.getActionEl();
15474 if(this.hideMode == 'visibility'){
15475 ae.dom.style.visibility = "hidden";
15476 }else if(this.hideMode == 'offsets'){
15477 ae.addClass('x-hidden');
15479 ae.dom.style.display = "none";
15484 * Convenience function to hide or show this component by boolean.
15485 * @param {Boolean} visible True to show, false to hide
15486 * @return {Roo.Component} this
15488 setVisible: function(visible){
15498 * Returns true if this component is visible.
15500 isVisible : function(){
15501 return this.getActionEl().isVisible();
15504 cloneConfig : function(overrides){
15505 overrides = overrides || {};
15506 var id = overrides.id || Roo.id();
15507 var cfg = Roo.applyIf(overrides, this.initialConfig);
15508 cfg.id = id; // prevent dup id
15509 return new this.constructor(cfg);
15513 * Ext JS Library 1.1.1
15514 * Copyright(c) 2006-2007, Ext JS, LLC.
15516 * Originally Released Under LGPL - original licence link has changed is not relivant.
15519 * <script type="text/javascript">
15523 * @class Roo.BoxComponent
15524 * @extends Roo.Component
15525 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15526 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15527 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15528 * layout containers.
15530 * @param {Roo.Element/String/Object} config The configuration options.
15532 Roo.BoxComponent = function(config){
15533 Roo.Component.call(this, config);
15537 * Fires after the component is resized.
15538 * @param {Roo.Component} this
15539 * @param {Number} adjWidth The box-adjusted width that was set
15540 * @param {Number} adjHeight The box-adjusted height that was set
15541 * @param {Number} rawWidth The width that was originally specified
15542 * @param {Number} rawHeight The height that was originally specified
15547 * Fires after the component is moved.
15548 * @param {Roo.Component} this
15549 * @param {Number} x The new x position
15550 * @param {Number} y The new y position
15556 Roo.extend(Roo.BoxComponent, Roo.Component, {
15557 // private, set in afterRender to signify that the component has been rendered
15559 // private, used to defer height settings to subclasses
15560 deferHeight: false,
15561 /** @cfg {Number} width
15562 * width (optional) size of component
15564 /** @cfg {Number} height
15565 * height (optional) size of component
15569 * Sets the width and height of the component. This method fires the resize event. This method can accept
15570 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15571 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15572 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15573 * @return {Roo.BoxComponent} this
15575 setSize : function(w, h){
15576 // support for standard size objects
15577 if(typeof w == 'object'){
15582 if(!this.boxReady){
15588 // prevent recalcs when not needed
15589 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15592 this.lastSize = {width: w, height: h};
15594 var adj = this.adjustSize(w, h);
15595 var aw = adj.width, ah = adj.height;
15596 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15597 var rz = this.getResizeEl();
15598 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15599 rz.setSize(aw, ah);
15600 }else if(!this.deferHeight && ah !== undefined){
15602 }else if(aw !== undefined){
15605 this.onResize(aw, ah, w, h);
15606 this.fireEvent('resize', this, aw, ah, w, h);
15612 * Gets the current size of the component's underlying element.
15613 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15615 getSize : function(){
15616 return this.el.getSize();
15620 * Gets the current XY position of the component's underlying element.
15621 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15622 * @return {Array} The XY position of the element (e.g., [100, 200])
15624 getPosition : function(local){
15625 if(local === true){
15626 return [this.el.getLeft(true), this.el.getTop(true)];
15628 return this.xy || this.el.getXY();
15632 * Gets the current box measurements of the component's underlying element.
15633 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15634 * @returns {Object} box An object in the format {x, y, width, height}
15636 getBox : function(local){
15637 var s = this.el.getSize();
15639 s.x = this.el.getLeft(true);
15640 s.y = this.el.getTop(true);
15642 var xy = this.xy || this.el.getXY();
15650 * Sets the current box measurements of the component's underlying element.
15651 * @param {Object} box An object in the format {x, y, width, height}
15652 * @returns {Roo.BoxComponent} this
15654 updateBox : function(box){
15655 this.setSize(box.width, box.height);
15656 this.setPagePosition(box.x, box.y);
15661 getResizeEl : function(){
15662 return this.resizeEl || this.el;
15666 getPositionEl : function(){
15667 return this.positionEl || this.el;
15671 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15672 * This method fires the move event.
15673 * @param {Number} left The new left
15674 * @param {Number} top The new top
15675 * @returns {Roo.BoxComponent} this
15677 setPosition : function(x, y){
15680 if(!this.boxReady){
15683 var adj = this.adjustPosition(x, y);
15684 var ax = adj.x, ay = adj.y;
15686 var el = this.getPositionEl();
15687 if(ax !== undefined || ay !== undefined){
15688 if(ax !== undefined && ay !== undefined){
15689 el.setLeftTop(ax, ay);
15690 }else if(ax !== undefined){
15692 }else if(ay !== undefined){
15695 this.onPosition(ax, ay);
15696 this.fireEvent('move', this, ax, ay);
15702 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15703 * This method fires the move event.
15704 * @param {Number} x The new x position
15705 * @param {Number} y The new y position
15706 * @returns {Roo.BoxComponent} this
15708 setPagePosition : function(x, y){
15711 if(!this.boxReady){
15714 if(x === undefined || y === undefined){ // cannot translate undefined points
15717 var p = this.el.translatePoints(x, y);
15718 this.setPosition(p.left, p.top);
15723 onRender : function(ct, position){
15724 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15726 this.resizeEl = Roo.get(this.resizeEl);
15728 if(this.positionEl){
15729 this.positionEl = Roo.get(this.positionEl);
15734 afterRender : function(){
15735 Roo.BoxComponent.superclass.afterRender.call(this);
15736 this.boxReady = true;
15737 this.setSize(this.width, this.height);
15738 if(this.x || this.y){
15739 this.setPosition(this.x, this.y);
15741 if(this.pageX || this.pageY){
15742 this.setPagePosition(this.pageX, this.pageY);
15747 * Force the component's size to recalculate based on the underlying element's current height and width.
15748 * @returns {Roo.BoxComponent} this
15750 syncSize : function(){
15751 delete this.lastSize;
15752 this.setSize(this.el.getWidth(), this.el.getHeight());
15757 * Called after the component is resized, this method is empty by default but can be implemented by any
15758 * subclass that needs to perform custom logic after a resize occurs.
15759 * @param {Number} adjWidth The box-adjusted width that was set
15760 * @param {Number} adjHeight The box-adjusted height that was set
15761 * @param {Number} rawWidth The width that was originally specified
15762 * @param {Number} rawHeight The height that was originally specified
15764 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15769 * Called after the component is moved, this method is empty by default but can be implemented by any
15770 * subclass that needs to perform custom logic after a move occurs.
15771 * @param {Number} x The new x position
15772 * @param {Number} y The new y position
15774 onPosition : function(x, y){
15779 adjustSize : function(w, h){
15780 if(this.autoWidth){
15783 if(this.autoHeight){
15786 return {width : w, height: h};
15790 adjustPosition : function(x, y){
15791 return {x : x, y: y};
15794 * Original code for Roojs - LGPL
15795 * <script type="text/javascript">
15799 * @class Roo.XComponent
15800 * A delayed Element creator...
15801 * Or a way to group chunks of interface together.
15802 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15803 * used in conjunction with XComponent.build() it will create an instance of each element,
15804 * then call addxtype() to build the User interface.
15806 * Mypart.xyx = new Roo.XComponent({
15808 parent : 'Mypart.xyz', // empty == document.element.!!
15812 disabled : function() {}
15814 tree : function() { // return an tree of xtype declared components
15818 xtype : 'NestedLayoutPanel',
15825 * It can be used to build a big heiracy, with parent etc.
15826 * or you can just use this to render a single compoent to a dom element
15827 * MYPART.render(Roo.Element | String(id) | dom_element )
15834 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15835 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15837 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15839 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15840 * - if mulitple topModules exist, the last one is defined as the top module.
15844 * When the top level or multiple modules are to embedded into a existing HTML page,
15845 * the parent element can container '#id' of the element where the module will be drawn.
15849 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15850 * it relies more on a include mechanism, where sub modules are included into an outer page.
15851 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15853 * Bootstrap Roo Included elements
15855 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15856 * hence confusing the component builder as it thinks there are multiple top level elements.
15860 * @extends Roo.util.Observable
15862 * @param cfg {Object} configuration of component
15865 Roo.XComponent = function(cfg) {
15866 Roo.apply(this, cfg);
15870 * Fires when this the componnt is built
15871 * @param {Roo.XComponent} c the component
15876 this.region = this.region || 'center'; // default..
15877 Roo.XComponent.register(this);
15878 this.modules = false;
15879 this.el = false; // where the layout goes..
15883 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15886 * The created element (with Roo.factory())
15887 * @type {Roo.Layout}
15893 * for BC - use el in new code
15894 * @type {Roo.Layout}
15900 * for BC - use el in new code
15901 * @type {Roo.Layout}
15906 * @cfg {Function|boolean} disabled
15907 * If this module is disabled by some rule, return true from the funtion
15912 * @cfg {String} parent
15913 * Name of parent element which it get xtype added to..
15918 * @cfg {String} order
15919 * Used to set the order in which elements are created (usefull for multiple tabs)
15924 * @cfg {String} name
15925 * String to display while loading.
15929 * @cfg {String} region
15930 * Region to render component to (defaults to center)
15935 * @cfg {Array} items
15936 * A single item array - the first element is the root of the tree..
15937 * It's done this way to stay compatible with the Xtype system...
15943 * The method that retuns the tree of parts that make up this compoennt
15950 * render element to dom or tree
15951 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15954 render : function(el)
15958 var hp = this.parent ? 1 : 0;
15959 Roo.debug && Roo.log(this);
15961 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15962 // if parent is a '#.....' string, then let's use that..
15963 var ename = this.parent.substr(1);
15964 this.parent = false;
15965 Roo.debug && Roo.log(ename);
15967 case 'bootstrap-body' :
15968 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15969 this.parent = { el : new Roo.bootstrap.Body() };
15970 Roo.debug && Roo.log("setting el to doc body");
15973 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15977 this.parent = { el : true};
15980 el = Roo.get(ename);
15985 if (!el && !this.parent) {
15986 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15990 Roo.debug && Roo.log("EL:");
15991 Roo.debug && Roo.log(el);
15992 Roo.debug && Roo.log("this.parent.el:");
15993 Roo.debug && Roo.log(this.parent.el);
15995 var tree = this._tree ? this._tree() : this.tree();
15997 // altertive root elements ??? - we need a better way to indicate these.
15998 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15999 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16001 if (!this.parent && is_alt) {
16002 //el = Roo.get(document.body);
16003 this.parent = { el : true };
16008 if (!this.parent) {
16010 Roo.debug && Roo.log("no parent - creating one");
16012 el = el ? Roo.get(el) : false;
16014 // it's a top level one..
16016 el : new Roo.BorderLayout(el || document.body, {
16022 tabPosition: 'top',
16023 //resizeTabs: true,
16024 alwaysShowTabs: el && hp? false : true,
16025 hideTabs: el || !hp ? true : false,
16032 if (!this.parent.el) {
16033 // probably an old style ctor, which has been disabled.
16037 // The 'tree' method is '_tree now'
16039 tree.region = tree.region || this.region;
16041 if (this.parent.el === true) {
16042 // bootstrap... - body..
16043 this.parent.el = Roo.factory(tree);
16046 this.el = this.parent.el.addxtype(tree);
16047 this.fireEvent('built', this);
16049 this.panel = this.el;
16050 this.layout = this.panel.layout;
16051 this.parentLayout = this.parent.layout || false;
16057 Roo.apply(Roo.XComponent, {
16059 * @property hideProgress
16060 * true to disable the building progress bar.. usefull on single page renders.
16063 hideProgress : false,
16065 * @property buildCompleted
16066 * True when the builder has completed building the interface.
16069 buildCompleted : false,
16072 * @property topModule
16073 * the upper most module - uses document.element as it's constructor.
16080 * @property modules
16081 * array of modules to be created by registration system.
16082 * @type {Array} of Roo.XComponent
16087 * @property elmodules
16088 * array of modules to be created by which use #ID
16089 * @type {Array} of Roo.XComponent
16095 * @property build_from_html
16096 * Build elements from html - used by bootstrap HTML stuff
16097 * - this is cleared after build is completed
16098 * @type {boolean} true (default false)
16101 build_from_html : false,
16104 * Register components to be built later.
16106 * This solves the following issues
16107 * - Building is not done on page load, but after an authentication process has occured.
16108 * - Interface elements are registered on page load
16109 * - Parent Interface elements may not be loaded before child, so this handles that..
16116 module : 'Pman.Tab.projectMgr',
16118 parent : 'Pman.layout',
16119 disabled : false, // or use a function..
16122 * * @param {Object} details about module
16124 register : function(obj) {
16126 Roo.XComponent.event.fireEvent('register', obj);
16127 switch(typeof(obj.disabled) ) {
16133 if ( obj.disabled() ) {
16139 if (obj.disabled) {
16145 this.modules.push(obj);
16149 * convert a string to an object..
16150 * eg. 'AAA.BBB' -> finds AAA.BBB
16154 toObject : function(str)
16156 if (!str || typeof(str) == 'object') {
16159 if (str.substring(0,1) == '#') {
16163 var ar = str.split('.');
16168 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16170 throw "Module not found : " + str;
16174 throw "Module not found : " + str;
16176 Roo.each(ar, function(e) {
16177 if (typeof(o[e]) == 'undefined') {
16178 throw "Module not found : " + str;
16189 * move modules into their correct place in the tree..
16192 preBuild : function ()
16195 Roo.each(this.modules , function (obj)
16197 Roo.XComponent.event.fireEvent('beforebuild', obj);
16199 var opar = obj.parent;
16201 obj.parent = this.toObject(opar);
16203 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16208 Roo.debug && Roo.log("GOT top level module");
16209 Roo.debug && Roo.log(obj);
16210 obj.modules = new Roo.util.MixedCollection(false,
16211 function(o) { return o.order + '' }
16213 this.topModule = obj;
16216 // parent is a string (usually a dom element name..)
16217 if (typeof(obj.parent) == 'string') {
16218 this.elmodules.push(obj);
16221 if (obj.parent.constructor != Roo.XComponent) {
16222 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16224 if (!obj.parent.modules) {
16225 obj.parent.modules = new Roo.util.MixedCollection(false,
16226 function(o) { return o.order + '' }
16229 if (obj.parent.disabled) {
16230 obj.disabled = true;
16232 obj.parent.modules.add(obj);
16237 * make a list of modules to build.
16238 * @return {Array} list of modules.
16241 buildOrder : function()
16244 var cmp = function(a,b) {
16245 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16247 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16248 throw "No top level modules to build";
16251 // make a flat list in order of modules to build.
16252 var mods = this.topModule ? [ this.topModule ] : [];
16255 // elmodules (is a list of DOM based modules )
16256 Roo.each(this.elmodules, function(e) {
16258 if (!this.topModule &&
16259 typeof(e.parent) == 'string' &&
16260 e.parent.substring(0,1) == '#' &&
16261 Roo.get(e.parent.substr(1))
16264 _this.topModule = e;
16270 // add modules to their parents..
16271 var addMod = function(m) {
16272 Roo.debug && Roo.log("build Order: add: " + m.name);
16275 if (m.modules && !m.disabled) {
16276 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16277 m.modules.keySort('ASC', cmp );
16278 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16280 m.modules.each(addMod);
16282 Roo.debug && Roo.log("build Order: no child modules");
16284 // not sure if this is used any more..
16286 m.finalize.name = m.name + " (clean up) ";
16287 mods.push(m.finalize);
16291 if (this.topModule && this.topModule.modules) {
16292 this.topModule.modules.keySort('ASC', cmp );
16293 this.topModule.modules.each(addMod);
16299 * Build the registered modules.
16300 * @param {Object} parent element.
16301 * @param {Function} optional method to call after module has been added.
16305 build : function(opts)
16308 if (typeof(opts) != 'undefined') {
16309 Roo.apply(this,opts);
16313 var mods = this.buildOrder();
16315 //this.allmods = mods;
16316 //Roo.debug && Roo.log(mods);
16318 if (!mods.length) { // should not happen
16319 throw "NO modules!!!";
16323 var msg = "Building Interface...";
16324 // flash it up as modal - so we store the mask!?
16325 if (!this.hideProgress && Roo.MessageBox) {
16326 Roo.MessageBox.show({ title: 'loading' });
16327 Roo.MessageBox.show({
16328 title: "Please wait...",
16337 var total = mods.length;
16340 var progressRun = function() {
16341 if (!mods.length) {
16342 Roo.debug && Roo.log('hide?');
16343 if (!this.hideProgress && Roo.MessageBox) {
16344 Roo.MessageBox.hide();
16346 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16348 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16354 var m = mods.shift();
16357 Roo.debug && Roo.log(m);
16358 // not sure if this is supported any more.. - modules that are are just function
16359 if (typeof(m) == 'function') {
16361 return progressRun.defer(10, _this);
16365 msg = "Building Interface " + (total - mods.length) +
16367 (m.name ? (' - ' + m.name) : '');
16368 Roo.debug && Roo.log(msg);
16369 if (!this.hideProgress && Roo.MessageBox) {
16370 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16374 // is the module disabled?
16375 var disabled = (typeof(m.disabled) == 'function') ?
16376 m.disabled.call(m.module.disabled) : m.disabled;
16380 return progressRun(); // we do not update the display!
16388 // it's 10 on top level, and 1 on others??? why...
16389 return progressRun.defer(10, _this);
16392 progressRun.defer(1, _this);
16406 * wrapper for event.on - aliased later..
16407 * Typically use to register a event handler for register:
16409 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16418 Roo.XComponent.event = new Roo.util.Observable({
16422 * Fires when an Component is registered,
16423 * set the disable property on the Component to stop registration.
16424 * @param {Roo.XComponent} c the component being registerd.
16429 * @event beforebuild
16430 * Fires before each Component is built
16431 * can be used to apply permissions.
16432 * @param {Roo.XComponent} c the component being registerd.
16435 'beforebuild' : true,
16437 * @event buildcomplete
16438 * Fires on the top level element when all elements have been built
16439 * @param {Roo.XComponent} the top level component.
16441 'buildcomplete' : true
16446 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16449 * Ext JS Library 1.1.1
16450 * Copyright(c) 2006-2007, Ext JS, LLC.
16452 * Originally Released Under LGPL - original licence link has changed is not relivant.
16455 * <script type="text/javascript">
16461 * These classes are derivatives of the similarly named classes in the YUI Library.
16462 * The original license:
16463 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16464 * Code licensed under the BSD License:
16465 * http://developer.yahoo.net/yui/license.txt
16470 var Event=Roo.EventManager;
16471 var Dom=Roo.lib.Dom;
16474 * @class Roo.dd.DragDrop
16475 * @extends Roo.util.Observable
16476 * Defines the interface and base operation of items that that can be
16477 * dragged or can be drop targets. It was designed to be extended, overriding
16478 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16479 * Up to three html elements can be associated with a DragDrop instance:
16481 * <li>linked element: the element that is passed into the constructor.
16482 * This is the element which defines the boundaries for interaction with
16483 * other DragDrop objects.</li>
16484 * <li>handle element(s): The drag operation only occurs if the element that
16485 * was clicked matches a handle element. By default this is the linked
16486 * element, but there are times that you will want only a portion of the
16487 * linked element to initiate the drag operation, and the setHandleElId()
16488 * method provides a way to define this.</li>
16489 * <li>drag element: this represents the element that would be moved along
16490 * with the cursor during a drag operation. By default, this is the linked
16491 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16492 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16495 * This class should not be instantiated until the onload event to ensure that
16496 * the associated elements are available.
16497 * The following would define a DragDrop obj that would interact with any
16498 * other DragDrop obj in the "group1" group:
16500 * dd = new Roo.dd.DragDrop("div1", "group1");
16502 * Since none of the event handlers have been implemented, nothing would
16503 * actually happen if you were to run the code above. Normally you would
16504 * override this class or one of the default implementations, but you can
16505 * also override the methods you want on an instance of the class...
16507 * dd.onDragDrop = function(e, id) {
16508 * alert("dd was dropped on " + id);
16512 * @param {String} id of the element that is linked to this instance
16513 * @param {String} sGroup the group of related DragDrop objects
16514 * @param {object} config an object containing configurable attributes
16515 * Valid properties for DragDrop:
16516 * padding, isTarget, maintainOffset, primaryButtonOnly
16518 Roo.dd.DragDrop = function(id, sGroup, config) {
16520 this.init(id, sGroup, config);
16525 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16528 * The id of the element associated with this object. This is what we
16529 * refer to as the "linked element" because the size and position of
16530 * this element is used to determine when the drag and drop objects have
16538 * Configuration attributes passed into the constructor
16545 * The id of the element that will be dragged. By default this is same
16546 * as the linked element , but could be changed to another element. Ex:
16548 * @property dragElId
16555 * the id of the element that initiates the drag operation. By default
16556 * this is the linked element, but could be changed to be a child of this
16557 * element. This lets us do things like only starting the drag when the
16558 * header element within the linked html element is clicked.
16559 * @property handleElId
16566 * An associative array of HTML tags that will be ignored if clicked.
16567 * @property invalidHandleTypes
16568 * @type {string: string}
16570 invalidHandleTypes: null,
16573 * An associative array of ids for elements that will be ignored if clicked
16574 * @property invalidHandleIds
16575 * @type {string: string}
16577 invalidHandleIds: null,
16580 * An indexted array of css class names for elements that will be ignored
16582 * @property invalidHandleClasses
16585 invalidHandleClasses: null,
16588 * The linked element's absolute X position at the time the drag was
16590 * @property startPageX
16597 * The linked element's absolute X position at the time the drag was
16599 * @property startPageY
16606 * The group defines a logical collection of DragDrop objects that are
16607 * related. Instances only get events when interacting with other
16608 * DragDrop object in the same group. This lets us define multiple
16609 * groups using a single DragDrop subclass if we want.
16611 * @type {string: string}
16616 * Individual drag/drop instances can be locked. This will prevent
16617 * onmousedown start drag.
16625 * Lock this instance
16628 lock: function() { this.locked = true; },
16631 * Unlock this instace
16634 unlock: function() { this.locked = false; },
16637 * By default, all insances can be a drop target. This can be disabled by
16638 * setting isTarget to false.
16645 * The padding configured for this drag and drop object for calculating
16646 * the drop zone intersection with this object.
16653 * Cached reference to the linked element
16654 * @property _domRef
16660 * Internal typeof flag
16661 * @property __ygDragDrop
16664 __ygDragDrop: true,
16667 * Set to true when horizontal contraints are applied
16668 * @property constrainX
16675 * Set to true when vertical contraints are applied
16676 * @property constrainY
16683 * The left constraint
16691 * The right constraint
16699 * The up constraint
16708 * The down constraint
16716 * Maintain offsets when we resetconstraints. Set to true when you want
16717 * the position of the element relative to its parent to stay the same
16718 * when the page changes
16720 * @property maintainOffset
16723 maintainOffset: false,
16726 * Array of pixel locations the element will snap to if we specified a
16727 * horizontal graduation/interval. This array is generated automatically
16728 * when you define a tick interval.
16735 * Array of pixel locations the element will snap to if we specified a
16736 * vertical graduation/interval. This array is generated automatically
16737 * when you define a tick interval.
16744 * By default the drag and drop instance will only respond to the primary
16745 * button click (left button for a right-handed mouse). Set to true to
16746 * allow drag and drop to start with any mouse click that is propogated
16748 * @property primaryButtonOnly
16751 primaryButtonOnly: true,
16754 * The availabe property is false until the linked dom element is accessible.
16755 * @property available
16761 * By default, drags can only be initiated if the mousedown occurs in the
16762 * region the linked element is. This is done in part to work around a
16763 * bug in some browsers that mis-report the mousedown if the previous
16764 * mouseup happened outside of the window. This property is set to true
16765 * if outer handles are defined.
16767 * @property hasOuterHandles
16771 hasOuterHandles: false,
16774 * Code that executes immediately before the startDrag event
16775 * @method b4StartDrag
16778 b4StartDrag: function(x, y) { },
16781 * Abstract method called after a drag/drop object is clicked
16782 * and the drag or mousedown time thresholds have beeen met.
16783 * @method startDrag
16784 * @param {int} X click location
16785 * @param {int} Y click location
16787 startDrag: function(x, y) { /* override this */ },
16790 * Code that executes immediately before the onDrag event
16794 b4Drag: function(e) { },
16797 * Abstract method called during the onMouseMove event while dragging an
16800 * @param {Event} e the mousemove event
16802 onDrag: function(e) { /* override this */ },
16805 * Abstract method called when this element fist begins hovering over
16806 * another DragDrop obj
16807 * @method onDragEnter
16808 * @param {Event} e the mousemove event
16809 * @param {String|DragDrop[]} id In POINT mode, the element
16810 * id this is hovering over. In INTERSECT mode, an array of one or more
16811 * dragdrop items being hovered over.
16813 onDragEnter: function(e, id) { /* override this */ },
16816 * Code that executes immediately before the onDragOver event
16817 * @method b4DragOver
16820 b4DragOver: function(e) { },
16823 * Abstract method called when this element is hovering over another
16825 * @method onDragOver
16826 * @param {Event} e the mousemove event
16827 * @param {String|DragDrop[]} id In POINT mode, the element
16828 * id this is hovering over. In INTERSECT mode, an array of dd items
16829 * being hovered over.
16831 onDragOver: function(e, id) { /* override this */ },
16834 * Code that executes immediately before the onDragOut event
16835 * @method b4DragOut
16838 b4DragOut: function(e) { },
16841 * Abstract method called when we are no longer hovering over an element
16842 * @method onDragOut
16843 * @param {Event} e the mousemove event
16844 * @param {String|DragDrop[]} id In POINT mode, the element
16845 * id this was hovering over. In INTERSECT mode, an array of dd items
16846 * that the mouse is no longer over.
16848 onDragOut: function(e, id) { /* override this */ },
16851 * Code that executes immediately before the onDragDrop event
16852 * @method b4DragDrop
16855 b4DragDrop: function(e) { },
16858 * Abstract method called when this item is dropped on another DragDrop
16860 * @method onDragDrop
16861 * @param {Event} e the mouseup event
16862 * @param {String|DragDrop[]} id In POINT mode, the element
16863 * id this was dropped on. In INTERSECT mode, an array of dd items this
16866 onDragDrop: function(e, id) { /* override this */ },
16869 * Abstract method called when this item is dropped on an area with no
16871 * @method onInvalidDrop
16872 * @param {Event} e the mouseup event
16874 onInvalidDrop: function(e) { /* override this */ },
16877 * Code that executes immediately before the endDrag event
16878 * @method b4EndDrag
16881 b4EndDrag: function(e) { },
16884 * Fired when we are done dragging the object
16886 * @param {Event} e the mouseup event
16888 endDrag: function(e) { /* override this */ },
16891 * Code executed immediately before the onMouseDown event
16892 * @method b4MouseDown
16893 * @param {Event} e the mousedown event
16896 b4MouseDown: function(e) { },
16899 * Event handler that fires when a drag/drop obj gets a mousedown
16900 * @method onMouseDown
16901 * @param {Event} e the mousedown event
16903 onMouseDown: function(e) { /* override this */ },
16906 * Event handler that fires when a drag/drop obj gets a mouseup
16907 * @method onMouseUp
16908 * @param {Event} e the mouseup event
16910 onMouseUp: function(e) { /* override this */ },
16913 * Override the onAvailable method to do what is needed after the initial
16914 * position was determined.
16915 * @method onAvailable
16917 onAvailable: function () {
16921 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16924 defaultPadding : {left:0, right:0, top:0, bottom:0},
16927 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16931 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16932 { dragElId: "existingProxyDiv" });
16933 dd.startDrag = function(){
16934 this.constrainTo("parent-id");
16937 * Or you can initalize it using the {@link Roo.Element} object:
16939 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16940 startDrag : function(){
16941 this.constrainTo("parent-id");
16945 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16946 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16947 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16948 * an object containing the sides to pad. For example: {right:10, bottom:10}
16949 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16951 constrainTo : function(constrainTo, pad, inContent){
16952 if(typeof pad == "number"){
16953 pad = {left: pad, right:pad, top:pad, bottom:pad};
16955 pad = pad || this.defaultPadding;
16956 var b = Roo.get(this.getEl()).getBox();
16957 var ce = Roo.get(constrainTo);
16958 var s = ce.getScroll();
16959 var c, cd = ce.dom;
16960 if(cd == document.body){
16961 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16964 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16968 var topSpace = b.y - c.y;
16969 var leftSpace = b.x - c.x;
16971 this.resetConstraints();
16972 this.setXConstraint(leftSpace - (pad.left||0), // left
16973 c.width - leftSpace - b.width - (pad.right||0) //right
16975 this.setYConstraint(topSpace - (pad.top||0), //top
16976 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16981 * Returns a reference to the linked element
16983 * @return {HTMLElement} the html element
16985 getEl: function() {
16986 if (!this._domRef) {
16987 this._domRef = Roo.getDom(this.id);
16990 return this._domRef;
16994 * Returns a reference to the actual element to drag. By default this is
16995 * the same as the html element, but it can be assigned to another
16996 * element. An example of this can be found in Roo.dd.DDProxy
16997 * @method getDragEl
16998 * @return {HTMLElement} the html element
17000 getDragEl: function() {
17001 return Roo.getDom(this.dragElId);
17005 * Sets up the DragDrop object. Must be called in the constructor of any
17006 * Roo.dd.DragDrop subclass
17008 * @param id the id of the linked element
17009 * @param {String} sGroup the group of related items
17010 * @param {object} config configuration attributes
17012 init: function(id, sGroup, config) {
17013 this.initTarget(id, sGroup, config);
17014 if (!Roo.isTouch) {
17015 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17017 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17018 // Event.on(this.id, "selectstart", Event.preventDefault);
17022 * Initializes Targeting functionality only... the object does not
17023 * get a mousedown handler.
17024 * @method initTarget
17025 * @param id the id of the linked element
17026 * @param {String} sGroup the group of related items
17027 * @param {object} config configuration attributes
17029 initTarget: function(id, sGroup, config) {
17031 // configuration attributes
17032 this.config = config || {};
17034 // create a local reference to the drag and drop manager
17035 this.DDM = Roo.dd.DDM;
17036 // initialize the groups array
17039 // assume that we have an element reference instead of an id if the
17040 // parameter is not a string
17041 if (typeof id !== "string") {
17048 // add to an interaction group
17049 this.addToGroup((sGroup) ? sGroup : "default");
17051 // We don't want to register this as the handle with the manager
17052 // so we just set the id rather than calling the setter.
17053 this.handleElId = id;
17055 // the linked element is the element that gets dragged by default
17056 this.setDragElId(id);
17058 // by default, clicked anchors will not start drag operations.
17059 this.invalidHandleTypes = { A: "A" };
17060 this.invalidHandleIds = {};
17061 this.invalidHandleClasses = [];
17063 this.applyConfig();
17065 this.handleOnAvailable();
17069 * Applies the configuration parameters that were passed into the constructor.
17070 * This is supposed to happen at each level through the inheritance chain. So
17071 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17072 * DragDrop in order to get all of the parameters that are available in
17074 * @method applyConfig
17076 applyConfig: function() {
17078 // configurable properties:
17079 // padding, isTarget, maintainOffset, primaryButtonOnly
17080 this.padding = this.config.padding || [0, 0, 0, 0];
17081 this.isTarget = (this.config.isTarget !== false);
17082 this.maintainOffset = (this.config.maintainOffset);
17083 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17088 * Executed when the linked element is available
17089 * @method handleOnAvailable
17092 handleOnAvailable: function() {
17093 this.available = true;
17094 this.resetConstraints();
17095 this.onAvailable();
17099 * Configures the padding for the target zone in px. Effectively expands
17100 * (or reduces) the virtual object size for targeting calculations.
17101 * Supports css-style shorthand; if only one parameter is passed, all sides
17102 * will have that padding, and if only two are passed, the top and bottom
17103 * will have the first param, the left and right the second.
17104 * @method setPadding
17105 * @param {int} iTop Top pad
17106 * @param {int} iRight Right pad
17107 * @param {int} iBot Bot pad
17108 * @param {int} iLeft Left pad
17110 setPadding: function(iTop, iRight, iBot, iLeft) {
17111 // this.padding = [iLeft, iRight, iTop, iBot];
17112 if (!iRight && 0 !== iRight) {
17113 this.padding = [iTop, iTop, iTop, iTop];
17114 } else if (!iBot && 0 !== iBot) {
17115 this.padding = [iTop, iRight, iTop, iRight];
17117 this.padding = [iTop, iRight, iBot, iLeft];
17122 * Stores the initial placement of the linked element.
17123 * @method setInitialPosition
17124 * @param {int} diffX the X offset, default 0
17125 * @param {int} diffY the Y offset, default 0
17127 setInitPosition: function(diffX, diffY) {
17128 var el = this.getEl();
17130 if (!this.DDM.verifyEl(el)) {
17134 var dx = diffX || 0;
17135 var dy = diffY || 0;
17137 var p = Dom.getXY( el );
17139 this.initPageX = p[0] - dx;
17140 this.initPageY = p[1] - dy;
17142 this.lastPageX = p[0];
17143 this.lastPageY = p[1];
17146 this.setStartPosition(p);
17150 * Sets the start position of the element. This is set when the obj
17151 * is initialized, the reset when a drag is started.
17152 * @method setStartPosition
17153 * @param pos current position (from previous lookup)
17156 setStartPosition: function(pos) {
17157 var p = pos || Dom.getXY( this.getEl() );
17158 this.deltaSetXY = null;
17160 this.startPageX = p[0];
17161 this.startPageY = p[1];
17165 * Add this instance to a group of related drag/drop objects. All
17166 * instances belong to at least one group, and can belong to as many
17167 * groups as needed.
17168 * @method addToGroup
17169 * @param sGroup {string} the name of the group
17171 addToGroup: function(sGroup) {
17172 this.groups[sGroup] = true;
17173 this.DDM.regDragDrop(this, sGroup);
17177 * Remove's this instance from the supplied interaction group
17178 * @method removeFromGroup
17179 * @param {string} sGroup The group to drop
17181 removeFromGroup: function(sGroup) {
17182 if (this.groups[sGroup]) {
17183 delete this.groups[sGroup];
17186 this.DDM.removeDDFromGroup(this, sGroup);
17190 * Allows you to specify that an element other than the linked element
17191 * will be moved with the cursor during a drag
17192 * @method setDragElId
17193 * @param id {string} the id of the element that will be used to initiate the drag
17195 setDragElId: function(id) {
17196 this.dragElId = id;
17200 * Allows you to specify a child of the linked element that should be
17201 * used to initiate the drag operation. An example of this would be if
17202 * you have a content div with text and links. Clicking anywhere in the
17203 * content area would normally start the drag operation. Use this method
17204 * to specify that an element inside of the content div is the element
17205 * that starts the drag operation.
17206 * @method setHandleElId
17207 * @param id {string} the id of the element that will be used to
17208 * initiate the drag.
17210 setHandleElId: function(id) {
17211 if (typeof id !== "string") {
17214 this.handleElId = id;
17215 this.DDM.regHandle(this.id, id);
17219 * Allows you to set an element outside of the linked element as a drag
17221 * @method setOuterHandleElId
17222 * @param id the id of the element that will be used to initiate the drag
17224 setOuterHandleElId: function(id) {
17225 if (typeof id !== "string") {
17228 Event.on(id, "mousedown",
17229 this.handleMouseDown, this);
17230 this.setHandleElId(id);
17232 this.hasOuterHandles = true;
17236 * Remove all drag and drop hooks for this element
17239 unreg: function() {
17240 Event.un(this.id, "mousedown",
17241 this.handleMouseDown);
17242 Event.un(this.id, "touchstart",
17243 this.handleMouseDown);
17244 this._domRef = null;
17245 this.DDM._remove(this);
17248 destroy : function(){
17253 * Returns true if this instance is locked, or the drag drop mgr is locked
17254 * (meaning that all drag/drop is disabled on the page.)
17256 * @return {boolean} true if this obj or all drag/drop is locked, else
17259 isLocked: function() {
17260 return (this.DDM.isLocked() || this.locked);
17264 * Fired when this object is clicked
17265 * @method handleMouseDown
17267 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17270 handleMouseDown: function(e, oDD){
17272 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17273 //Roo.log('not touch/ button !=0');
17276 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17277 return; // double touch..
17281 if (this.isLocked()) {
17282 //Roo.log('locked');
17286 this.DDM.refreshCache(this.groups);
17287 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17288 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17289 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17290 //Roo.log('no outer handes or not over target');
17293 // Roo.log('check validator');
17294 if (this.clickValidator(e)) {
17295 // Roo.log('validate success');
17296 // set the initial element position
17297 this.setStartPosition();
17300 this.b4MouseDown(e);
17301 this.onMouseDown(e);
17303 this.DDM.handleMouseDown(e, this);
17305 this.DDM.stopEvent(e);
17313 clickValidator: function(e) {
17314 var target = e.getTarget();
17315 return ( this.isValidHandleChild(target) &&
17316 (this.id == this.handleElId ||
17317 this.DDM.handleWasClicked(target, this.id)) );
17321 * Allows you to specify a tag name that should not start a drag operation
17322 * when clicked. This is designed to facilitate embedding links within a
17323 * drag handle that do something other than start the drag.
17324 * @method addInvalidHandleType
17325 * @param {string} tagName the type of element to exclude
17327 addInvalidHandleType: function(tagName) {
17328 var type = tagName.toUpperCase();
17329 this.invalidHandleTypes[type] = type;
17333 * Lets you to specify an element id for a child of a drag handle
17334 * that should not initiate a drag
17335 * @method addInvalidHandleId
17336 * @param {string} id the element id of the element you wish to ignore
17338 addInvalidHandleId: function(id) {
17339 if (typeof id !== "string") {
17342 this.invalidHandleIds[id] = id;
17346 * Lets you specify a css class of elements that will not initiate a drag
17347 * @method addInvalidHandleClass
17348 * @param {string} cssClass the class of the elements you wish to ignore
17350 addInvalidHandleClass: function(cssClass) {
17351 this.invalidHandleClasses.push(cssClass);
17355 * Unsets an excluded tag name set by addInvalidHandleType
17356 * @method removeInvalidHandleType
17357 * @param {string} tagName the type of element to unexclude
17359 removeInvalidHandleType: function(tagName) {
17360 var type = tagName.toUpperCase();
17361 // this.invalidHandleTypes[type] = null;
17362 delete this.invalidHandleTypes[type];
17366 * Unsets an invalid handle id
17367 * @method removeInvalidHandleId
17368 * @param {string} id the id of the element to re-enable
17370 removeInvalidHandleId: function(id) {
17371 if (typeof id !== "string") {
17374 delete this.invalidHandleIds[id];
17378 * Unsets an invalid css class
17379 * @method removeInvalidHandleClass
17380 * @param {string} cssClass the class of the element(s) you wish to
17383 removeInvalidHandleClass: function(cssClass) {
17384 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17385 if (this.invalidHandleClasses[i] == cssClass) {
17386 delete this.invalidHandleClasses[i];
17392 * Checks the tag exclusion list to see if this click should be ignored
17393 * @method isValidHandleChild
17394 * @param {HTMLElement} node the HTMLElement to evaluate
17395 * @return {boolean} true if this is a valid tag type, false if not
17397 isValidHandleChild: function(node) {
17400 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17403 nodeName = node.nodeName.toUpperCase();
17405 nodeName = node.nodeName;
17407 valid = valid && !this.invalidHandleTypes[nodeName];
17408 valid = valid && !this.invalidHandleIds[node.id];
17410 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17411 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17420 * Create the array of horizontal tick marks if an interval was specified
17421 * in setXConstraint().
17422 * @method setXTicks
17425 setXTicks: function(iStartX, iTickSize) {
17427 this.xTickSize = iTickSize;
17431 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17433 this.xTicks[this.xTicks.length] = i;
17438 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17440 this.xTicks[this.xTicks.length] = i;
17445 this.xTicks.sort(this.DDM.numericSort) ;
17449 * Create the array of vertical tick marks if an interval was specified in
17450 * setYConstraint().
17451 * @method setYTicks
17454 setYTicks: function(iStartY, iTickSize) {
17456 this.yTickSize = iTickSize;
17460 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17462 this.yTicks[this.yTicks.length] = i;
17467 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17469 this.yTicks[this.yTicks.length] = i;
17474 this.yTicks.sort(this.DDM.numericSort) ;
17478 * By default, the element can be dragged any place on the screen. Use
17479 * this method to limit the horizontal travel of the element. Pass in
17480 * 0,0 for the parameters if you want to lock the drag to the y axis.
17481 * @method setXConstraint
17482 * @param {int} iLeft the number of pixels the element can move to the left
17483 * @param {int} iRight the number of pixels the element can move to the
17485 * @param {int} iTickSize optional parameter for specifying that the
17487 * should move iTickSize pixels at a time.
17489 setXConstraint: function(iLeft, iRight, iTickSize) {
17490 this.leftConstraint = iLeft;
17491 this.rightConstraint = iRight;
17493 this.minX = this.initPageX - iLeft;
17494 this.maxX = this.initPageX + iRight;
17495 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17497 this.constrainX = true;
17501 * Clears any constraints applied to this instance. Also clears ticks
17502 * since they can't exist independent of a constraint at this time.
17503 * @method clearConstraints
17505 clearConstraints: function() {
17506 this.constrainX = false;
17507 this.constrainY = false;
17512 * Clears any tick interval defined for this instance
17513 * @method clearTicks
17515 clearTicks: function() {
17516 this.xTicks = null;
17517 this.yTicks = null;
17518 this.xTickSize = 0;
17519 this.yTickSize = 0;
17523 * By default, the element can be dragged any place on the screen. Set
17524 * this to limit the vertical travel of the element. Pass in 0,0 for the
17525 * parameters if you want to lock the drag to the x axis.
17526 * @method setYConstraint
17527 * @param {int} iUp the number of pixels the element can move up
17528 * @param {int} iDown the number of pixels the element can move down
17529 * @param {int} iTickSize optional parameter for specifying that the
17530 * element should move iTickSize pixels at a time.
17532 setYConstraint: function(iUp, iDown, iTickSize) {
17533 this.topConstraint = iUp;
17534 this.bottomConstraint = iDown;
17536 this.minY = this.initPageY - iUp;
17537 this.maxY = this.initPageY + iDown;
17538 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17540 this.constrainY = true;
17545 * resetConstraints must be called if you manually reposition a dd element.
17546 * @method resetConstraints
17547 * @param {boolean} maintainOffset
17549 resetConstraints: function() {
17552 // Maintain offsets if necessary
17553 if (this.initPageX || this.initPageX === 0) {
17554 // figure out how much this thing has moved
17555 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17556 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17558 this.setInitPosition(dx, dy);
17560 // This is the first time we have detected the element's position
17562 this.setInitPosition();
17565 if (this.constrainX) {
17566 this.setXConstraint( this.leftConstraint,
17567 this.rightConstraint,
17571 if (this.constrainY) {
17572 this.setYConstraint( this.topConstraint,
17573 this.bottomConstraint,
17579 * Normally the drag element is moved pixel by pixel, but we can specify
17580 * that it move a number of pixels at a time. This method resolves the
17581 * location when we have it set up like this.
17583 * @param {int} val where we want to place the object
17584 * @param {int[]} tickArray sorted array of valid points
17585 * @return {int} the closest tick
17588 getTick: function(val, tickArray) {
17591 // If tick interval is not defined, it is effectively 1 pixel,
17592 // so we return the value passed to us.
17594 } else if (tickArray[0] >= val) {
17595 // The value is lower than the first tick, so we return the first
17597 return tickArray[0];
17599 for (var i=0, len=tickArray.length; i<len; ++i) {
17601 if (tickArray[next] && tickArray[next] >= val) {
17602 var diff1 = val - tickArray[i];
17603 var diff2 = tickArray[next] - val;
17604 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17608 // The value is larger than the last tick, so we return the last
17610 return tickArray[tickArray.length - 1];
17617 * @return {string} string representation of the dd obj
17619 toString: function() {
17620 return ("DragDrop " + this.id);
17628 * Ext JS Library 1.1.1
17629 * Copyright(c) 2006-2007, Ext JS, LLC.
17631 * Originally Released Under LGPL - original licence link has changed is not relivant.
17634 * <script type="text/javascript">
17639 * The drag and drop utility provides a framework for building drag and drop
17640 * applications. In addition to enabling drag and drop for specific elements,
17641 * the drag and drop elements are tracked by the manager class, and the
17642 * interactions between the various elements are tracked during the drag and
17643 * the implementing code is notified about these important moments.
17646 // Only load the library once. Rewriting the manager class would orphan
17647 // existing drag and drop instances.
17648 if (!Roo.dd.DragDropMgr) {
17651 * @class Roo.dd.DragDropMgr
17652 * DragDropMgr is a singleton that tracks the element interaction for
17653 * all DragDrop items in the window. Generally, you will not call
17654 * this class directly, but it does have helper methods that could
17655 * be useful in your DragDrop implementations.
17658 Roo.dd.DragDropMgr = function() {
17660 var Event = Roo.EventManager;
17665 * Two dimensional Array of registered DragDrop objects. The first
17666 * dimension is the DragDrop item group, the second the DragDrop
17669 * @type {string: string}
17676 * Array of element ids defined as drag handles. Used to determine
17677 * if the element that generated the mousedown event is actually the
17678 * handle and not the html element itself.
17679 * @property handleIds
17680 * @type {string: string}
17687 * the DragDrop object that is currently being dragged
17688 * @property dragCurrent
17696 * the DragDrop object(s) that are being hovered over
17697 * @property dragOvers
17705 * the X distance between the cursor and the object being dragged
17714 * the Y distance between the cursor and the object being dragged
17723 * Flag to determine if we should prevent the default behavior of the
17724 * events we define. By default this is true, but this can be set to
17725 * false if you need the default behavior (not recommended)
17726 * @property preventDefault
17730 preventDefault: true,
17733 * Flag to determine if we should stop the propagation of the events
17734 * we generate. This is true by default but you may want to set it to
17735 * false if the html element contains other features that require the
17737 * @property stopPropagation
17741 stopPropagation: true,
17744 * Internal flag that is set to true when drag and drop has been
17746 * @property initialized
17753 * All drag and drop can be disabled.
17761 * Called the first time an element is registered.
17767 this.initialized = true;
17771 * In point mode, drag and drop interaction is defined by the
17772 * location of the cursor during the drag/drop
17780 * In intersect mode, drag and drop interactio nis defined by the
17781 * overlap of two or more drag and drop objects.
17782 * @property INTERSECT
17789 * The current drag and drop mode. Default: POINT
17797 * Runs method on all drag and drop objects
17798 * @method _execOnAll
17802 _execOnAll: function(sMethod, args) {
17803 for (var i in this.ids) {
17804 for (var j in this.ids[i]) {
17805 var oDD = this.ids[i][j];
17806 if (! this.isTypeOfDD(oDD)) {
17809 oDD[sMethod].apply(oDD, args);
17815 * Drag and drop initialization. Sets up the global event handlers
17820 _onLoad: function() {
17824 if (!Roo.isTouch) {
17825 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17826 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17828 Event.on(document, "touchend", this.handleMouseUp, this, true);
17829 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17831 Event.on(window, "unload", this._onUnload, this, true);
17832 Event.on(window, "resize", this._onResize, this, true);
17833 // Event.on(window, "mouseout", this._test);
17838 * Reset constraints on all drag and drop objs
17839 * @method _onResize
17843 _onResize: function(e) {
17844 this._execOnAll("resetConstraints", []);
17848 * Lock all drag and drop functionality
17852 lock: function() { this.locked = true; },
17855 * Unlock all drag and drop functionality
17859 unlock: function() { this.locked = false; },
17862 * Is drag and drop locked?
17864 * @return {boolean} True if drag and drop is locked, false otherwise.
17867 isLocked: function() { return this.locked; },
17870 * Location cache that is set for all drag drop objects when a drag is
17871 * initiated, cleared when the drag is finished.
17872 * @property locationCache
17879 * Set useCache to false if you want to force object the lookup of each
17880 * drag and drop linked element constantly during a drag.
17881 * @property useCache
17888 * The number of pixels that the mouse needs to move after the
17889 * mousedown before the drag is initiated. Default=3;
17890 * @property clickPixelThresh
17894 clickPixelThresh: 3,
17897 * The number of milliseconds after the mousedown event to initiate the
17898 * drag if we don't get a mouseup event. Default=1000
17899 * @property clickTimeThresh
17903 clickTimeThresh: 350,
17906 * Flag that indicates that either the drag pixel threshold or the
17907 * mousdown time threshold has been met
17908 * @property dragThreshMet
17913 dragThreshMet: false,
17916 * Timeout used for the click time threshold
17917 * @property clickTimeout
17922 clickTimeout: null,
17925 * The X position of the mousedown event stored for later use when a
17926 * drag threshold is met.
17935 * The Y position of the mousedown event stored for later use when a
17936 * drag threshold is met.
17945 * Each DragDrop instance must be registered with the DragDropMgr.
17946 * This is executed in DragDrop.init()
17947 * @method regDragDrop
17948 * @param {DragDrop} oDD the DragDrop object to register
17949 * @param {String} sGroup the name of the group this element belongs to
17952 regDragDrop: function(oDD, sGroup) {
17953 if (!this.initialized) { this.init(); }
17955 if (!this.ids[sGroup]) {
17956 this.ids[sGroup] = {};
17958 this.ids[sGroup][oDD.id] = oDD;
17962 * Removes the supplied dd instance from the supplied group. Executed
17963 * by DragDrop.removeFromGroup, so don't call this function directly.
17964 * @method removeDDFromGroup
17968 removeDDFromGroup: function(oDD, sGroup) {
17969 if (!this.ids[sGroup]) {
17970 this.ids[sGroup] = {};
17973 var obj = this.ids[sGroup];
17974 if (obj && obj[oDD.id]) {
17975 delete obj[oDD.id];
17980 * Unregisters a drag and drop item. This is executed in
17981 * DragDrop.unreg, use that method instead of calling this directly.
17986 _remove: function(oDD) {
17987 for (var g in oDD.groups) {
17988 if (g && this.ids[g][oDD.id]) {
17989 delete this.ids[g][oDD.id];
17992 delete this.handleIds[oDD.id];
17996 * Each DragDrop handle element must be registered. This is done
17997 * automatically when executing DragDrop.setHandleElId()
17998 * @method regHandle
17999 * @param {String} sDDId the DragDrop id this element is a handle for
18000 * @param {String} sHandleId the id of the element that is the drag
18004 regHandle: function(sDDId, sHandleId) {
18005 if (!this.handleIds[sDDId]) {
18006 this.handleIds[sDDId] = {};
18008 this.handleIds[sDDId][sHandleId] = sHandleId;
18012 * Utility function to determine if a given element has been
18013 * registered as a drag drop item.
18014 * @method isDragDrop
18015 * @param {String} id the element id to check
18016 * @return {boolean} true if this element is a DragDrop item,
18020 isDragDrop: function(id) {
18021 return ( this.getDDById(id) ) ? true : false;
18025 * Returns the drag and drop instances that are in all groups the
18026 * passed in instance belongs to.
18027 * @method getRelated
18028 * @param {DragDrop} p_oDD the obj to get related data for
18029 * @param {boolean} bTargetsOnly if true, only return targetable objs
18030 * @return {DragDrop[]} the related instances
18033 getRelated: function(p_oDD, bTargetsOnly) {
18035 for (var i in p_oDD.groups) {
18036 for (j in this.ids[i]) {
18037 var dd = this.ids[i][j];
18038 if (! this.isTypeOfDD(dd)) {
18041 if (!bTargetsOnly || dd.isTarget) {
18042 oDDs[oDDs.length] = dd;
18051 * Returns true if the specified dd target is a legal target for
18052 * the specifice drag obj
18053 * @method isLegalTarget
18054 * @param {DragDrop} the drag obj
18055 * @param {DragDrop} the target
18056 * @return {boolean} true if the target is a legal target for the
18060 isLegalTarget: function (oDD, oTargetDD) {
18061 var targets = this.getRelated(oDD, true);
18062 for (var i=0, len=targets.length;i<len;++i) {
18063 if (targets[i].id == oTargetDD.id) {
18072 * My goal is to be able to transparently determine if an object is
18073 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18074 * returns "object", oDD.constructor.toString() always returns
18075 * "DragDrop" and not the name of the subclass. So for now it just
18076 * evaluates a well-known variable in DragDrop.
18077 * @method isTypeOfDD
18078 * @param {Object} the object to evaluate
18079 * @return {boolean} true if typeof oDD = DragDrop
18082 isTypeOfDD: function (oDD) {
18083 return (oDD && oDD.__ygDragDrop);
18087 * Utility function to determine if a given element has been
18088 * registered as a drag drop handle for the given Drag Drop object.
18090 * @param {String} id the element id to check
18091 * @return {boolean} true if this element is a DragDrop handle, false
18095 isHandle: function(sDDId, sHandleId) {
18096 return ( this.handleIds[sDDId] &&
18097 this.handleIds[sDDId][sHandleId] );
18101 * Returns the DragDrop instance for a given id
18102 * @method getDDById
18103 * @param {String} id the id of the DragDrop object
18104 * @return {DragDrop} the drag drop object, null if it is not found
18107 getDDById: function(id) {
18108 for (var i in this.ids) {
18109 if (this.ids[i][id]) {
18110 return this.ids[i][id];
18117 * Fired after a registered DragDrop object gets the mousedown event.
18118 * Sets up the events required to track the object being dragged
18119 * @method handleMouseDown
18120 * @param {Event} e the event
18121 * @param oDD the DragDrop object being dragged
18125 handleMouseDown: function(e, oDD) {
18127 Roo.QuickTips.disable();
18129 this.currentTarget = e.getTarget();
18131 this.dragCurrent = oDD;
18133 var el = oDD.getEl();
18135 // track start position
18136 this.startX = e.getPageX();
18137 this.startY = e.getPageY();
18139 this.deltaX = this.startX - el.offsetLeft;
18140 this.deltaY = this.startY - el.offsetTop;
18142 this.dragThreshMet = false;
18144 this.clickTimeout = setTimeout(
18146 var DDM = Roo.dd.DDM;
18147 DDM.startDrag(DDM.startX, DDM.startY);
18149 this.clickTimeThresh );
18153 * Fired when either the drag pixel threshol or the mousedown hold
18154 * time threshold has been met.
18155 * @method startDrag
18156 * @param x {int} the X position of the original mousedown
18157 * @param y {int} the Y position of the original mousedown
18160 startDrag: function(x, y) {
18161 clearTimeout(this.clickTimeout);
18162 if (this.dragCurrent) {
18163 this.dragCurrent.b4StartDrag(x, y);
18164 this.dragCurrent.startDrag(x, y);
18166 this.dragThreshMet = true;
18170 * Internal function to handle the mouseup event. Will be invoked
18171 * from the context of the document.
18172 * @method handleMouseUp
18173 * @param {Event} e the event
18177 handleMouseUp: function(e) {
18180 Roo.QuickTips.enable();
18182 if (! this.dragCurrent) {
18186 clearTimeout(this.clickTimeout);
18188 if (this.dragThreshMet) {
18189 this.fireEvents(e, true);
18199 * Utility to stop event propagation and event default, if these
18200 * features are turned on.
18201 * @method stopEvent
18202 * @param {Event} e the event as returned by this.getEvent()
18205 stopEvent: function(e){
18206 if(this.stopPropagation) {
18207 e.stopPropagation();
18210 if (this.preventDefault) {
18211 e.preventDefault();
18216 * Internal function to clean up event handlers after the drag
18217 * operation is complete
18219 * @param {Event} e the event
18223 stopDrag: function(e) {
18224 // Fire the drag end event for the item that was dragged
18225 if (this.dragCurrent) {
18226 if (this.dragThreshMet) {
18227 this.dragCurrent.b4EndDrag(e);
18228 this.dragCurrent.endDrag(e);
18231 this.dragCurrent.onMouseUp(e);
18234 this.dragCurrent = null;
18235 this.dragOvers = {};
18239 * Internal function to handle the mousemove event. Will be invoked
18240 * from the context of the html element.
18242 * @TODO figure out what we can do about mouse events lost when the
18243 * user drags objects beyond the window boundary. Currently we can
18244 * detect this in internet explorer by verifying that the mouse is
18245 * down during the mousemove event. Firefox doesn't give us the
18246 * button state on the mousemove event.
18247 * @method handleMouseMove
18248 * @param {Event} e the event
18252 handleMouseMove: function(e) {
18253 if (! this.dragCurrent) {
18257 // var button = e.which || e.button;
18259 // check for IE mouseup outside of page boundary
18260 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18262 return this.handleMouseUp(e);
18265 if (!this.dragThreshMet) {
18266 var diffX = Math.abs(this.startX - e.getPageX());
18267 var diffY = Math.abs(this.startY - e.getPageY());
18268 if (diffX > this.clickPixelThresh ||
18269 diffY > this.clickPixelThresh) {
18270 this.startDrag(this.startX, this.startY);
18274 if (this.dragThreshMet) {
18275 this.dragCurrent.b4Drag(e);
18276 this.dragCurrent.onDrag(e);
18277 if(!this.dragCurrent.moveOnly){
18278 this.fireEvents(e, false);
18288 * Iterates over all of the DragDrop elements to find ones we are
18289 * hovering over or dropping on
18290 * @method fireEvents
18291 * @param {Event} e the event
18292 * @param {boolean} isDrop is this a drop op or a mouseover op?
18296 fireEvents: function(e, isDrop) {
18297 var dc = this.dragCurrent;
18299 // If the user did the mouse up outside of the window, we could
18300 // get here even though we have ended the drag.
18301 if (!dc || dc.isLocked()) {
18305 var pt = e.getPoint();
18307 // cache the previous dragOver array
18313 var enterEvts = [];
18315 // Check to see if the object(s) we were hovering over is no longer
18316 // being hovered over so we can fire the onDragOut event
18317 for (var i in this.dragOvers) {
18319 var ddo = this.dragOvers[i];
18321 if (! this.isTypeOfDD(ddo)) {
18325 if (! this.isOverTarget(pt, ddo, this.mode)) {
18326 outEvts.push( ddo );
18329 oldOvers[i] = true;
18330 delete this.dragOvers[i];
18333 for (var sGroup in dc.groups) {
18335 if ("string" != typeof sGroup) {
18339 for (i in this.ids[sGroup]) {
18340 var oDD = this.ids[sGroup][i];
18341 if (! this.isTypeOfDD(oDD)) {
18345 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18346 if (this.isOverTarget(pt, oDD, this.mode)) {
18347 // look for drop interactions
18349 dropEvts.push( oDD );
18350 // look for drag enter and drag over interactions
18353 // initial drag over: dragEnter fires
18354 if (!oldOvers[oDD.id]) {
18355 enterEvts.push( oDD );
18356 // subsequent drag overs: dragOver fires
18358 overEvts.push( oDD );
18361 this.dragOvers[oDD.id] = oDD;
18369 if (outEvts.length) {
18370 dc.b4DragOut(e, outEvts);
18371 dc.onDragOut(e, outEvts);
18374 if (enterEvts.length) {
18375 dc.onDragEnter(e, enterEvts);
18378 if (overEvts.length) {
18379 dc.b4DragOver(e, overEvts);
18380 dc.onDragOver(e, overEvts);
18383 if (dropEvts.length) {
18384 dc.b4DragDrop(e, dropEvts);
18385 dc.onDragDrop(e, dropEvts);
18389 // fire dragout events
18391 for (i=0, len=outEvts.length; i<len; ++i) {
18392 dc.b4DragOut(e, outEvts[i].id);
18393 dc.onDragOut(e, outEvts[i].id);
18396 // fire enter events
18397 for (i=0,len=enterEvts.length; i<len; ++i) {
18398 // dc.b4DragEnter(e, oDD.id);
18399 dc.onDragEnter(e, enterEvts[i].id);
18402 // fire over events
18403 for (i=0,len=overEvts.length; i<len; ++i) {
18404 dc.b4DragOver(e, overEvts[i].id);
18405 dc.onDragOver(e, overEvts[i].id);
18408 // fire drop events
18409 for (i=0, len=dropEvts.length; i<len; ++i) {
18410 dc.b4DragDrop(e, dropEvts[i].id);
18411 dc.onDragDrop(e, dropEvts[i].id);
18416 // notify about a drop that did not find a target
18417 if (isDrop && !dropEvts.length) {
18418 dc.onInvalidDrop(e);
18424 * Helper function for getting the best match from the list of drag
18425 * and drop objects returned by the drag and drop events when we are
18426 * in INTERSECT mode. It returns either the first object that the
18427 * cursor is over, or the object that has the greatest overlap with
18428 * the dragged element.
18429 * @method getBestMatch
18430 * @param {DragDrop[]} dds The array of drag and drop objects
18432 * @return {DragDrop} The best single match
18435 getBestMatch: function(dds) {
18437 // Return null if the input is not what we expect
18438 //if (!dds || !dds.length || dds.length == 0) {
18440 // If there is only one item, it wins
18441 //} else if (dds.length == 1) {
18443 var len = dds.length;
18448 // Loop through the targeted items
18449 for (var i=0; i<len; ++i) {
18451 // If the cursor is over the object, it wins. If the
18452 // cursor is over multiple matches, the first one we come
18454 if (dd.cursorIsOver) {
18457 // Otherwise the object with the most overlap wins
18460 winner.overlap.getArea() < dd.overlap.getArea()) {
18471 * Refreshes the cache of the top-left and bottom-right points of the
18472 * drag and drop objects in the specified group(s). This is in the
18473 * format that is stored in the drag and drop instance, so typical
18476 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18480 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18482 * @TODO this really should be an indexed array. Alternatively this
18483 * method could accept both.
18484 * @method refreshCache
18485 * @param {Object} groups an associative array of groups to refresh
18488 refreshCache: function(groups) {
18489 for (var sGroup in groups) {
18490 if ("string" != typeof sGroup) {
18493 for (var i in this.ids[sGroup]) {
18494 var oDD = this.ids[sGroup][i];
18496 if (this.isTypeOfDD(oDD)) {
18497 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18498 var loc = this.getLocation(oDD);
18500 this.locationCache[oDD.id] = loc;
18502 delete this.locationCache[oDD.id];
18503 // this will unregister the drag and drop object if
18504 // the element is not in a usable state
18513 * This checks to make sure an element exists and is in the DOM. The
18514 * main purpose is to handle cases where innerHTML is used to remove
18515 * drag and drop objects from the DOM. IE provides an 'unspecified
18516 * error' when trying to access the offsetParent of such an element
18518 * @param {HTMLElement} el the element to check
18519 * @return {boolean} true if the element looks usable
18522 verifyEl: function(el) {
18527 parent = el.offsetParent;
18530 parent = el.offsetParent;
18541 * Returns a Region object containing the drag and drop element's position
18542 * and size, including the padding configured for it
18543 * @method getLocation
18544 * @param {DragDrop} oDD the drag and drop object to get the
18546 * @return {Roo.lib.Region} a Region object representing the total area
18547 * the element occupies, including any padding
18548 * the instance is configured for.
18551 getLocation: function(oDD) {
18552 if (! this.isTypeOfDD(oDD)) {
18556 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18559 pos= Roo.lib.Dom.getXY(el);
18567 x2 = x1 + el.offsetWidth;
18569 y2 = y1 + el.offsetHeight;
18571 t = y1 - oDD.padding[0];
18572 r = x2 + oDD.padding[1];
18573 b = y2 + oDD.padding[2];
18574 l = x1 - oDD.padding[3];
18576 return new Roo.lib.Region( t, r, b, l );
18580 * Checks the cursor location to see if it over the target
18581 * @method isOverTarget
18582 * @param {Roo.lib.Point} pt The point to evaluate
18583 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18584 * @return {boolean} true if the mouse is over the target
18588 isOverTarget: function(pt, oTarget, intersect) {
18589 // use cache if available
18590 var loc = this.locationCache[oTarget.id];
18591 if (!loc || !this.useCache) {
18592 loc = this.getLocation(oTarget);
18593 this.locationCache[oTarget.id] = loc;
18601 oTarget.cursorIsOver = loc.contains( pt );
18603 // DragDrop is using this as a sanity check for the initial mousedown
18604 // in this case we are done. In POINT mode, if the drag obj has no
18605 // contraints, we are also done. Otherwise we need to evaluate the
18606 // location of the target as related to the actual location of the
18607 // dragged element.
18608 var dc = this.dragCurrent;
18609 if (!dc || !dc.getTargetCoord ||
18610 (!intersect && !dc.constrainX && !dc.constrainY)) {
18611 return oTarget.cursorIsOver;
18614 oTarget.overlap = null;
18616 // Get the current location of the drag element, this is the
18617 // location of the mouse event less the delta that represents
18618 // where the original mousedown happened on the element. We
18619 // need to consider constraints and ticks as well.
18620 var pos = dc.getTargetCoord(pt.x, pt.y);
18622 var el = dc.getDragEl();
18623 var curRegion = new Roo.lib.Region( pos.y,
18624 pos.x + el.offsetWidth,
18625 pos.y + el.offsetHeight,
18628 var overlap = curRegion.intersect(loc);
18631 oTarget.overlap = overlap;
18632 return (intersect) ? true : oTarget.cursorIsOver;
18639 * unload event handler
18640 * @method _onUnload
18644 _onUnload: function(e, me) {
18645 Roo.dd.DragDropMgr.unregAll();
18649 * Cleans up the drag and drop events and objects.
18654 unregAll: function() {
18656 if (this.dragCurrent) {
18658 this.dragCurrent = null;
18661 this._execOnAll("unreg", []);
18663 for (i in this.elementCache) {
18664 delete this.elementCache[i];
18667 this.elementCache = {};
18672 * A cache of DOM elements
18673 * @property elementCache
18680 * Get the wrapper for the DOM element specified
18681 * @method getElWrapper
18682 * @param {String} id the id of the element to get
18683 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18685 * @deprecated This wrapper isn't that useful
18688 getElWrapper: function(id) {
18689 var oWrapper = this.elementCache[id];
18690 if (!oWrapper || !oWrapper.el) {
18691 oWrapper = this.elementCache[id] =
18692 new this.ElementWrapper(Roo.getDom(id));
18698 * Returns the actual DOM element
18699 * @method getElement
18700 * @param {String} id the id of the elment to get
18701 * @return {Object} The element
18702 * @deprecated use Roo.getDom instead
18705 getElement: function(id) {
18706 return Roo.getDom(id);
18710 * Returns the style property for the DOM element (i.e.,
18711 * document.getElById(id).style)
18713 * @param {String} id the id of the elment to get
18714 * @return {Object} The style property of the element
18715 * @deprecated use Roo.getDom instead
18718 getCss: function(id) {
18719 var el = Roo.getDom(id);
18720 return (el) ? el.style : null;
18724 * Inner class for cached elements
18725 * @class DragDropMgr.ElementWrapper
18730 ElementWrapper: function(el) {
18735 this.el = el || null;
18740 this.id = this.el && el.id;
18742 * A reference to the style property
18745 this.css = this.el && el.style;
18749 * Returns the X position of an html element
18751 * @param el the element for which to get the position
18752 * @return {int} the X coordinate
18754 * @deprecated use Roo.lib.Dom.getX instead
18757 getPosX: function(el) {
18758 return Roo.lib.Dom.getX(el);
18762 * Returns the Y position of an html element
18764 * @param el the element for which to get the position
18765 * @return {int} the Y coordinate
18766 * @deprecated use Roo.lib.Dom.getY instead
18769 getPosY: function(el) {
18770 return Roo.lib.Dom.getY(el);
18774 * Swap two nodes. In IE, we use the native method, for others we
18775 * emulate the IE behavior
18777 * @param n1 the first node to swap
18778 * @param n2 the other node to swap
18781 swapNode: function(n1, n2) {
18785 var p = n2.parentNode;
18786 var s = n2.nextSibling;
18789 p.insertBefore(n1, n2);
18790 } else if (n2 == n1.nextSibling) {
18791 p.insertBefore(n2, n1);
18793 n1.parentNode.replaceChild(n2, n1);
18794 p.insertBefore(n1, s);
18800 * Returns the current scroll position
18801 * @method getScroll
18805 getScroll: function () {
18806 var t, l, dde=document.documentElement, db=document.body;
18807 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18809 l = dde.scrollLeft;
18816 return { top: t, left: l };
18820 * Returns the specified element style property
18822 * @param {HTMLElement} el the element
18823 * @param {string} styleProp the style property
18824 * @return {string} The value of the style property
18825 * @deprecated use Roo.lib.Dom.getStyle
18828 getStyle: function(el, styleProp) {
18829 return Roo.fly(el).getStyle(styleProp);
18833 * Gets the scrollTop
18834 * @method getScrollTop
18835 * @return {int} the document's scrollTop
18838 getScrollTop: function () { return this.getScroll().top; },
18841 * Gets the scrollLeft
18842 * @method getScrollLeft
18843 * @return {int} the document's scrollTop
18846 getScrollLeft: function () { return this.getScroll().left; },
18849 * Sets the x/y position of an element to the location of the
18852 * @param {HTMLElement} moveEl The element to move
18853 * @param {HTMLElement} targetEl The position reference element
18856 moveToEl: function (moveEl, targetEl) {
18857 var aCoord = Roo.lib.Dom.getXY(targetEl);
18858 Roo.lib.Dom.setXY(moveEl, aCoord);
18862 * Numeric array sort function
18863 * @method numericSort
18866 numericSort: function(a, b) { return (a - b); },
18870 * @property _timeoutCount
18877 * Trying to make the load order less important. Without this we get
18878 * an error if this file is loaded before the Event Utility.
18879 * @method _addListeners
18883 _addListeners: function() {
18884 var DDM = Roo.dd.DDM;
18885 if ( Roo.lib.Event && document ) {
18888 if (DDM._timeoutCount > 2000) {
18890 setTimeout(DDM._addListeners, 10);
18891 if (document && document.body) {
18892 DDM._timeoutCount += 1;
18899 * Recursively searches the immediate parent and all child nodes for
18900 * the handle element in order to determine wheter or not it was
18902 * @method handleWasClicked
18903 * @param node the html element to inspect
18906 handleWasClicked: function(node, id) {
18907 if (this.isHandle(id, node.id)) {
18910 // check to see if this is a text node child of the one we want
18911 var p = node.parentNode;
18914 if (this.isHandle(id, p.id)) {
18929 // shorter alias, save a few bytes
18930 Roo.dd.DDM = Roo.dd.DragDropMgr;
18931 Roo.dd.DDM._addListeners();
18935 * Ext JS Library 1.1.1
18936 * Copyright(c) 2006-2007, Ext JS, LLC.
18938 * Originally Released Under LGPL - original licence link has changed is not relivant.
18941 * <script type="text/javascript">
18946 * A DragDrop implementation where the linked element follows the
18947 * mouse cursor during a drag.
18948 * @extends Roo.dd.DragDrop
18950 * @param {String} id the id of the linked element
18951 * @param {String} sGroup the group of related DragDrop items
18952 * @param {object} config an object containing configurable attributes
18953 * Valid properties for DD:
18956 Roo.dd.DD = function(id, sGroup, config) {
18958 this.init(id, sGroup, config);
18962 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18965 * When set to true, the utility automatically tries to scroll the browser
18966 * window wehn a drag and drop element is dragged near the viewport boundary.
18967 * Defaults to true.
18974 * Sets the pointer offset to the distance between the linked element's top
18975 * left corner and the location the element was clicked
18976 * @method autoOffset
18977 * @param {int} iPageX the X coordinate of the click
18978 * @param {int} iPageY the Y coordinate of the click
18980 autoOffset: function(iPageX, iPageY) {
18981 var x = iPageX - this.startPageX;
18982 var y = iPageY - this.startPageY;
18983 this.setDelta(x, y);
18987 * Sets the pointer offset. You can call this directly to force the
18988 * offset to be in a particular location (e.g., pass in 0,0 to set it
18989 * to the center of the object)
18991 * @param {int} iDeltaX the distance from the left
18992 * @param {int} iDeltaY the distance from the top
18994 setDelta: function(iDeltaX, iDeltaY) {
18995 this.deltaX = iDeltaX;
18996 this.deltaY = iDeltaY;
19000 * Sets the drag element to the location of the mousedown or click event,
19001 * maintaining the cursor location relative to the location on the element
19002 * that was clicked. Override this if you want to place the element in a
19003 * location other than where the cursor is.
19004 * @method setDragElPos
19005 * @param {int} iPageX the X coordinate of the mousedown or drag event
19006 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19008 setDragElPos: function(iPageX, iPageY) {
19009 // the first time we do this, we are going to check to make sure
19010 // the element has css positioning
19012 var el = this.getDragEl();
19013 this.alignElWithMouse(el, iPageX, iPageY);
19017 * Sets the element to the location of the mousedown or click event,
19018 * maintaining the cursor location relative to the location on the element
19019 * that was clicked. Override this if you want to place the element in a
19020 * location other than where the cursor is.
19021 * @method alignElWithMouse
19022 * @param {HTMLElement} el the element to move
19023 * @param {int} iPageX the X coordinate of the mousedown or drag event
19024 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19026 alignElWithMouse: function(el, iPageX, iPageY) {
19027 var oCoord = this.getTargetCoord(iPageX, iPageY);
19028 var fly = el.dom ? el : Roo.fly(el);
19029 if (!this.deltaSetXY) {
19030 var aCoord = [oCoord.x, oCoord.y];
19032 var newLeft = fly.getLeft(true);
19033 var newTop = fly.getTop(true);
19034 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19036 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19039 this.cachePosition(oCoord.x, oCoord.y);
19040 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19045 * Saves the most recent position so that we can reset the constraints and
19046 * tick marks on-demand. We need to know this so that we can calculate the
19047 * number of pixels the element is offset from its original position.
19048 * @method cachePosition
19049 * @param iPageX the current x position (optional, this just makes it so we
19050 * don't have to look it up again)
19051 * @param iPageY the current y position (optional, this just makes it so we
19052 * don't have to look it up again)
19054 cachePosition: function(iPageX, iPageY) {
19056 this.lastPageX = iPageX;
19057 this.lastPageY = iPageY;
19059 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19060 this.lastPageX = aCoord[0];
19061 this.lastPageY = aCoord[1];
19066 * Auto-scroll the window if the dragged object has been moved beyond the
19067 * visible window boundary.
19068 * @method autoScroll
19069 * @param {int} x the drag element's x position
19070 * @param {int} y the drag element's y position
19071 * @param {int} h the height of the drag element
19072 * @param {int} w the width of the drag element
19075 autoScroll: function(x, y, h, w) {
19078 // The client height
19079 var clientH = Roo.lib.Dom.getViewWidth();
19081 // The client width
19082 var clientW = Roo.lib.Dom.getViewHeight();
19084 // The amt scrolled down
19085 var st = this.DDM.getScrollTop();
19087 // The amt scrolled right
19088 var sl = this.DDM.getScrollLeft();
19090 // Location of the bottom of the element
19093 // Location of the right of the element
19096 // The distance from the cursor to the bottom of the visible area,
19097 // adjusted so that we don't scroll if the cursor is beyond the
19098 // element drag constraints
19099 var toBot = (clientH + st - y - this.deltaY);
19101 // The distance from the cursor to the right of the visible area
19102 var toRight = (clientW + sl - x - this.deltaX);
19105 // How close to the edge the cursor must be before we scroll
19106 // var thresh = (document.all) ? 100 : 40;
19109 // How many pixels to scroll per autoscroll op. This helps to reduce
19110 // clunky scrolling. IE is more sensitive about this ... it needs this
19111 // value to be higher.
19112 var scrAmt = (document.all) ? 80 : 30;
19114 // Scroll down if we are near the bottom of the visible page and the
19115 // obj extends below the crease
19116 if ( bot > clientH && toBot < thresh ) {
19117 window.scrollTo(sl, st + scrAmt);
19120 // Scroll up if the window is scrolled down and the top of the object
19121 // goes above the top border
19122 if ( y < st && st > 0 && y - st < thresh ) {
19123 window.scrollTo(sl, st - scrAmt);
19126 // Scroll right if the obj is beyond the right border and the cursor is
19127 // near the border.
19128 if ( right > clientW && toRight < thresh ) {
19129 window.scrollTo(sl + scrAmt, st);
19132 // Scroll left if the window has been scrolled to the right and the obj
19133 // extends past the left border
19134 if ( x < sl && sl > 0 && x - sl < thresh ) {
19135 window.scrollTo(sl - scrAmt, st);
19141 * Finds the location the element should be placed if we want to move
19142 * it to where the mouse location less the click offset would place us.
19143 * @method getTargetCoord
19144 * @param {int} iPageX the X coordinate of the click
19145 * @param {int} iPageY the Y coordinate of the click
19146 * @return an object that contains the coordinates (Object.x and Object.y)
19149 getTargetCoord: function(iPageX, iPageY) {
19152 var x = iPageX - this.deltaX;
19153 var y = iPageY - this.deltaY;
19155 if (this.constrainX) {
19156 if (x < this.minX) { x = this.minX; }
19157 if (x > this.maxX) { x = this.maxX; }
19160 if (this.constrainY) {
19161 if (y < this.minY) { y = this.minY; }
19162 if (y > this.maxY) { y = this.maxY; }
19165 x = this.getTick(x, this.xTicks);
19166 y = this.getTick(y, this.yTicks);
19173 * Sets up config options specific to this class. Overrides
19174 * Roo.dd.DragDrop, but all versions of this method through the
19175 * inheritance chain are called
19177 applyConfig: function() {
19178 Roo.dd.DD.superclass.applyConfig.call(this);
19179 this.scroll = (this.config.scroll !== false);
19183 * Event that fires prior to the onMouseDown event. Overrides
19186 b4MouseDown: function(e) {
19187 // this.resetConstraints();
19188 this.autoOffset(e.getPageX(),
19193 * Event that fires prior to the onDrag event. Overrides
19196 b4Drag: function(e) {
19197 this.setDragElPos(e.getPageX(),
19201 toString: function() {
19202 return ("DD " + this.id);
19205 //////////////////////////////////////////////////////////////////////////
19206 // Debugging ygDragDrop events that can be overridden
19207 //////////////////////////////////////////////////////////////////////////
19209 startDrag: function(x, y) {
19212 onDrag: function(e) {
19215 onDragEnter: function(e, id) {
19218 onDragOver: function(e, id) {
19221 onDragOut: function(e, id) {
19224 onDragDrop: function(e, id) {
19227 endDrag: function(e) {
19234 * Ext JS Library 1.1.1
19235 * Copyright(c) 2006-2007, Ext JS, LLC.
19237 * Originally Released Under LGPL - original licence link has changed is not relivant.
19240 * <script type="text/javascript">
19244 * @class Roo.dd.DDProxy
19245 * A DragDrop implementation that inserts an empty, bordered div into
19246 * the document that follows the cursor during drag operations. At the time of
19247 * the click, the frame div is resized to the dimensions of the linked html
19248 * element, and moved to the exact location of the linked element.
19250 * References to the "frame" element refer to the single proxy element that
19251 * was created to be dragged in place of all DDProxy elements on the
19254 * @extends Roo.dd.DD
19256 * @param {String} id the id of the linked html element
19257 * @param {String} sGroup the group of related DragDrop objects
19258 * @param {object} config an object containing configurable attributes
19259 * Valid properties for DDProxy in addition to those in DragDrop:
19260 * resizeFrame, centerFrame, dragElId
19262 Roo.dd.DDProxy = function(id, sGroup, config) {
19264 this.init(id, sGroup, config);
19270 * The default drag frame div id
19271 * @property Roo.dd.DDProxy.dragElId
19275 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19277 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19280 * By default we resize the drag frame to be the same size as the element
19281 * we want to drag (this is to get the frame effect). We can turn it off
19282 * if we want a different behavior.
19283 * @property resizeFrame
19289 * By default the frame is positioned exactly where the drag element is, so
19290 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19291 * you do not have constraints on the obj is to have the drag frame centered
19292 * around the cursor. Set centerFrame to true for this effect.
19293 * @property centerFrame
19296 centerFrame: false,
19299 * Creates the proxy element if it does not yet exist
19300 * @method createFrame
19302 createFrame: function() {
19304 var body = document.body;
19306 if (!body || !body.firstChild) {
19307 setTimeout( function() { self.createFrame(); }, 50 );
19311 var div = this.getDragEl();
19314 div = document.createElement("div");
19315 div.id = this.dragElId;
19318 s.position = "absolute";
19319 s.visibility = "hidden";
19321 s.border = "2px solid #aaa";
19324 // appendChild can blow up IE if invoked prior to the window load event
19325 // while rendering a table. It is possible there are other scenarios
19326 // that would cause this to happen as well.
19327 body.insertBefore(div, body.firstChild);
19332 * Initialization for the drag frame element. Must be called in the
19333 * constructor of all subclasses
19334 * @method initFrame
19336 initFrame: function() {
19337 this.createFrame();
19340 applyConfig: function() {
19341 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19343 this.resizeFrame = (this.config.resizeFrame !== false);
19344 this.centerFrame = (this.config.centerFrame);
19345 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19349 * Resizes the drag frame to the dimensions of the clicked object, positions
19350 * it over the object, and finally displays it
19351 * @method showFrame
19352 * @param {int} iPageX X click position
19353 * @param {int} iPageY Y click position
19356 showFrame: function(iPageX, iPageY) {
19357 var el = this.getEl();
19358 var dragEl = this.getDragEl();
19359 var s = dragEl.style;
19361 this._resizeProxy();
19363 if (this.centerFrame) {
19364 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19365 Math.round(parseInt(s.height, 10)/2) );
19368 this.setDragElPos(iPageX, iPageY);
19370 Roo.fly(dragEl).show();
19374 * The proxy is automatically resized to the dimensions of the linked
19375 * element when a drag is initiated, unless resizeFrame is set to false
19376 * @method _resizeProxy
19379 _resizeProxy: function() {
19380 if (this.resizeFrame) {
19381 var el = this.getEl();
19382 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19386 // overrides Roo.dd.DragDrop
19387 b4MouseDown: function(e) {
19388 var x = e.getPageX();
19389 var y = e.getPageY();
19390 this.autoOffset(x, y);
19391 this.setDragElPos(x, y);
19394 // overrides Roo.dd.DragDrop
19395 b4StartDrag: function(x, y) {
19396 // show the drag frame
19397 this.showFrame(x, y);
19400 // overrides Roo.dd.DragDrop
19401 b4EndDrag: function(e) {
19402 Roo.fly(this.getDragEl()).hide();
19405 // overrides Roo.dd.DragDrop
19406 // By default we try to move the element to the last location of the frame.
19407 // This is so that the default behavior mirrors that of Roo.dd.DD.
19408 endDrag: function(e) {
19410 var lel = this.getEl();
19411 var del = this.getDragEl();
19413 // Show the drag frame briefly so we can get its position
19414 del.style.visibility = "";
19417 // Hide the linked element before the move to get around a Safari
19419 lel.style.visibility = "hidden";
19420 Roo.dd.DDM.moveToEl(lel, del);
19421 del.style.visibility = "hidden";
19422 lel.style.visibility = "";
19427 beforeMove : function(){
19431 afterDrag : function(){
19435 toString: function() {
19436 return ("DDProxy " + this.id);
19442 * Ext JS Library 1.1.1
19443 * Copyright(c) 2006-2007, Ext JS, LLC.
19445 * Originally Released Under LGPL - original licence link has changed is not relivant.
19448 * <script type="text/javascript">
19452 * @class Roo.dd.DDTarget
19453 * A DragDrop implementation that does not move, but can be a drop
19454 * target. You would get the same result by simply omitting implementation
19455 * for the event callbacks, but this way we reduce the processing cost of the
19456 * event listener and the callbacks.
19457 * @extends Roo.dd.DragDrop
19459 * @param {String} id the id of the element that is a drop target
19460 * @param {String} sGroup the group of related DragDrop objects
19461 * @param {object} config an object containing configurable attributes
19462 * Valid properties for DDTarget in addition to those in
19466 Roo.dd.DDTarget = function(id, sGroup, config) {
19468 this.initTarget(id, sGroup, config);
19470 if (config.listeners || config.events) {
19471 Roo.dd.DragDrop.superclass.constructor.call(this, {
19472 listeners : config.listeners || {},
19473 events : config.events || {}
19478 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19479 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19480 toString: function() {
19481 return ("DDTarget " + this.id);
19486 * Ext JS Library 1.1.1
19487 * Copyright(c) 2006-2007, Ext JS, LLC.
19489 * Originally Released Under LGPL - original licence link has changed is not relivant.
19492 * <script type="text/javascript">
19497 * @class Roo.dd.ScrollManager
19498 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19499 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19502 Roo.dd.ScrollManager = function(){
19503 var ddm = Roo.dd.DragDropMgr;
19510 var onStop = function(e){
19515 var triggerRefresh = function(){
19516 if(ddm.dragCurrent){
19517 ddm.refreshCache(ddm.dragCurrent.groups);
19521 var doScroll = function(){
19522 if(ddm.dragCurrent){
19523 var dds = Roo.dd.ScrollManager;
19525 if(proc.el.scroll(proc.dir, dds.increment)){
19529 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19534 var clearProc = function(){
19536 clearInterval(proc.id);
19543 var startProc = function(el, dir){
19544 Roo.log('scroll startproc');
19548 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19551 var onFire = function(e, isDrop){
19553 if(isDrop || !ddm.dragCurrent){ return; }
19554 var dds = Roo.dd.ScrollManager;
19555 if(!dragEl || dragEl != ddm.dragCurrent){
19556 dragEl = ddm.dragCurrent;
19557 // refresh regions on drag start
19558 dds.refreshCache();
19561 var xy = Roo.lib.Event.getXY(e);
19562 var pt = new Roo.lib.Point(xy[0], xy[1]);
19563 for(var id in els){
19564 var el = els[id], r = el._region;
19565 if(r && r.contains(pt) && el.isScrollable()){
19566 if(r.bottom - pt.y <= dds.thresh){
19568 startProc(el, "down");
19571 }else if(r.right - pt.x <= dds.thresh){
19573 startProc(el, "left");
19576 }else if(pt.y - r.top <= dds.thresh){
19578 startProc(el, "up");
19581 }else if(pt.x - r.left <= dds.thresh){
19583 startProc(el, "right");
19592 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19593 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19597 * Registers new overflow element(s) to auto scroll
19598 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19600 register : function(el){
19601 if(el instanceof Array){
19602 for(var i = 0, len = el.length; i < len; i++) {
19603 this.register(el[i]);
19609 Roo.dd.ScrollManager.els = els;
19613 * Unregisters overflow element(s) so they are no longer scrolled
19614 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19616 unregister : function(el){
19617 if(el instanceof Array){
19618 for(var i = 0, len = el.length; i < len; i++) {
19619 this.unregister(el[i]);
19628 * The number of pixels from the edge of a container the pointer needs to be to
19629 * trigger scrolling (defaults to 25)
19635 * The number of pixels to scroll in each scroll increment (defaults to 50)
19641 * The frequency of scrolls in milliseconds (defaults to 500)
19647 * True to animate the scroll (defaults to true)
19653 * The animation duration in seconds -
19654 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19660 * Manually trigger a cache refresh.
19662 refreshCache : function(){
19663 for(var id in els){
19664 if(typeof els[id] == 'object'){ // for people extending the object prototype
19665 els[id]._region = els[id].getRegion();
19672 * Ext JS Library 1.1.1
19673 * Copyright(c) 2006-2007, Ext JS, LLC.
19675 * Originally Released Under LGPL - original licence link has changed is not relivant.
19678 * <script type="text/javascript">
19683 * @class Roo.dd.Registry
19684 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19685 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19688 Roo.dd.Registry = function(){
19691 var autoIdSeed = 0;
19693 var getId = function(el, autogen){
19694 if(typeof el == "string"){
19698 if(!id && autogen !== false){
19699 id = "roodd-" + (++autoIdSeed);
19707 * Register a drag drop element
19708 * @param {String|HTMLElement} element The id or DOM node to register
19709 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19710 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19711 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19712 * populated in the data object (if applicable):
19714 Value Description<br />
19715 --------- ------------------------------------------<br />
19716 handles Array of DOM nodes that trigger dragging<br />
19717 for the element being registered<br />
19718 isHandle True if the element passed in triggers<br />
19719 dragging itself, else false
19722 register : function(el, data){
19724 if(typeof el == "string"){
19725 el = document.getElementById(el);
19728 elements[getId(el)] = data;
19729 if(data.isHandle !== false){
19730 handles[data.ddel.id] = data;
19733 var hs = data.handles;
19734 for(var i = 0, len = hs.length; i < len; i++){
19735 handles[getId(hs[i])] = data;
19741 * Unregister a drag drop element
19742 * @param {String|HTMLElement} element The id or DOM node to unregister
19744 unregister : function(el){
19745 var id = getId(el, false);
19746 var data = elements[id];
19748 delete elements[id];
19750 var hs = data.handles;
19751 for(var i = 0, len = hs.length; i < len; i++){
19752 delete handles[getId(hs[i], false)];
19759 * Returns the handle registered for a DOM Node by id
19760 * @param {String|HTMLElement} id The DOM node or id to look up
19761 * @return {Object} handle The custom handle data
19763 getHandle : function(id){
19764 if(typeof id != "string"){ // must be element?
19767 return handles[id];
19771 * Returns the handle that is registered for the DOM node that is the target of the event
19772 * @param {Event} e The event
19773 * @return {Object} handle The custom handle data
19775 getHandleFromEvent : function(e){
19776 var t = Roo.lib.Event.getTarget(e);
19777 return t ? handles[t.id] : null;
19781 * Returns a custom data object that is registered for a DOM node by id
19782 * @param {String|HTMLElement} id The DOM node or id to look up
19783 * @return {Object} data The custom data
19785 getTarget : function(id){
19786 if(typeof id != "string"){ // must be element?
19789 return elements[id];
19793 * Returns a custom data object that is registered for the DOM node that is the target of the event
19794 * @param {Event} e The event
19795 * @return {Object} data The custom data
19797 getTargetFromEvent : function(e){
19798 var t = Roo.lib.Event.getTarget(e);
19799 return t ? elements[t.id] || handles[t.id] : null;
19804 * Ext JS Library 1.1.1
19805 * Copyright(c) 2006-2007, Ext JS, LLC.
19807 * Originally Released Under LGPL - original licence link has changed is not relivant.
19810 * <script type="text/javascript">
19815 * @class Roo.dd.StatusProxy
19816 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19817 * default drag proxy used by all Roo.dd components.
19819 * @param {Object} config
19821 Roo.dd.StatusProxy = function(config){
19822 Roo.apply(this, config);
19823 this.id = this.id || Roo.id();
19824 this.el = new Roo.Layer({
19826 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19827 {tag: "div", cls: "x-dd-drop-icon"},
19828 {tag: "div", cls: "x-dd-drag-ghost"}
19831 shadow: !config || config.shadow !== false
19833 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19834 this.dropStatus = this.dropNotAllowed;
19837 Roo.dd.StatusProxy.prototype = {
19839 * @cfg {String} dropAllowed
19840 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19842 dropAllowed : "x-dd-drop-ok",
19844 * @cfg {String} dropNotAllowed
19845 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19847 dropNotAllowed : "x-dd-drop-nodrop",
19850 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19851 * over the current target element.
19852 * @param {String} cssClass The css class for the new drop status indicator image
19854 setStatus : function(cssClass){
19855 cssClass = cssClass || this.dropNotAllowed;
19856 if(this.dropStatus != cssClass){
19857 this.el.replaceClass(this.dropStatus, cssClass);
19858 this.dropStatus = cssClass;
19863 * Resets the status indicator to the default dropNotAllowed value
19864 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19866 reset : function(clearGhost){
19867 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19868 this.dropStatus = this.dropNotAllowed;
19870 this.ghost.update("");
19875 * Updates the contents of the ghost element
19876 * @param {String} html The html that will replace the current innerHTML of the ghost element
19878 update : function(html){
19879 if(typeof html == "string"){
19880 this.ghost.update(html);
19882 this.ghost.update("");
19883 html.style.margin = "0";
19884 this.ghost.dom.appendChild(html);
19886 // ensure float = none set?? cant remember why though.
19887 var el = this.ghost.dom.firstChild;
19889 Roo.fly(el).setStyle('float', 'none');
19894 * Returns the underlying proxy {@link Roo.Layer}
19895 * @return {Roo.Layer} el
19897 getEl : function(){
19902 * Returns the ghost element
19903 * @return {Roo.Element} el
19905 getGhost : function(){
19911 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19913 hide : function(clear){
19921 * Stops the repair animation if it's currently running
19924 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19930 * Displays this proxy
19937 * Force the Layer to sync its shadow and shim positions to the element
19944 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19945 * invalid drop operation by the item being dragged.
19946 * @param {Array} xy The XY position of the element ([x, y])
19947 * @param {Function} callback The function to call after the repair is complete
19948 * @param {Object} scope The scope in which to execute the callback
19950 repair : function(xy, callback, scope){
19951 this.callback = callback;
19952 this.scope = scope;
19953 if(xy && this.animRepair !== false){
19954 this.el.addClass("x-dd-drag-repair");
19955 this.el.hideUnders(true);
19956 this.anim = this.el.shift({
19957 duration: this.repairDuration || .5,
19961 callback: this.afterRepair,
19965 this.afterRepair();
19970 afterRepair : function(){
19972 if(typeof this.callback == "function"){
19973 this.callback.call(this.scope || this);
19975 this.callback = null;
19980 * Ext JS Library 1.1.1
19981 * Copyright(c) 2006-2007, Ext JS, LLC.
19983 * Originally Released Under LGPL - original licence link has changed is not relivant.
19986 * <script type="text/javascript">
19990 * @class Roo.dd.DragSource
19991 * @extends Roo.dd.DDProxy
19992 * A simple class that provides the basic implementation needed to make any element draggable.
19994 * @param {String/HTMLElement/Element} el The container element
19995 * @param {Object} config
19997 Roo.dd.DragSource = function(el, config){
19998 this.el = Roo.get(el);
19999 this.dragData = {};
20001 Roo.apply(this, config);
20004 this.proxy = new Roo.dd.StatusProxy();
20007 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20008 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20010 this.dragging = false;
20013 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20015 * @cfg {String} dropAllowed
20016 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20018 dropAllowed : "x-dd-drop-ok",
20020 * @cfg {String} dropNotAllowed
20021 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20023 dropNotAllowed : "x-dd-drop-nodrop",
20026 * Returns the data object associated with this drag source
20027 * @return {Object} data An object containing arbitrary data
20029 getDragData : function(e){
20030 return this.dragData;
20034 onDragEnter : function(e, id){
20035 var target = Roo.dd.DragDropMgr.getDDById(id);
20036 this.cachedTarget = target;
20037 if(this.beforeDragEnter(target, e, id) !== false){
20038 if(target.isNotifyTarget){
20039 var status = target.notifyEnter(this, e, this.dragData);
20040 this.proxy.setStatus(status);
20042 this.proxy.setStatus(this.dropAllowed);
20045 if(this.afterDragEnter){
20047 * An empty function by default, but provided so that you can perform a custom action
20048 * when the dragged item enters the drop target by providing an implementation.
20049 * @param {Roo.dd.DragDrop} target The drop target
20050 * @param {Event} e The event object
20051 * @param {String} id The id of the dragged element
20052 * @method afterDragEnter
20054 this.afterDragEnter(target, e, id);
20060 * An empty function by default, but provided so that you can perform a custom action
20061 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20062 * @param {Roo.dd.DragDrop} target The drop target
20063 * @param {Event} e The event object
20064 * @param {String} id The id of the dragged element
20065 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20067 beforeDragEnter : function(target, e, id){
20072 alignElWithMouse: function() {
20073 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20078 onDragOver : function(e, id){
20079 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20080 if(this.beforeDragOver(target, e, id) !== false){
20081 if(target.isNotifyTarget){
20082 var status = target.notifyOver(this, e, this.dragData);
20083 this.proxy.setStatus(status);
20086 if(this.afterDragOver){
20088 * An empty function by default, but provided so that you can perform a custom action
20089 * while the dragged item is over the drop target by providing an implementation.
20090 * @param {Roo.dd.DragDrop} target The drop target
20091 * @param {Event} e The event object
20092 * @param {String} id The id of the dragged element
20093 * @method afterDragOver
20095 this.afterDragOver(target, e, id);
20101 * An empty function by default, but provided so that you can perform a custom action
20102 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20103 * @param {Roo.dd.DragDrop} target The drop target
20104 * @param {Event} e The event object
20105 * @param {String} id The id of the dragged element
20106 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20108 beforeDragOver : function(target, e, id){
20113 onDragOut : function(e, id){
20114 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20115 if(this.beforeDragOut(target, e, id) !== false){
20116 if(target.isNotifyTarget){
20117 target.notifyOut(this, e, this.dragData);
20119 this.proxy.reset();
20120 if(this.afterDragOut){
20122 * An empty function by default, but provided so that you can perform a custom action
20123 * after the dragged item is dragged out of the target without dropping.
20124 * @param {Roo.dd.DragDrop} target The drop target
20125 * @param {Event} e The event object
20126 * @param {String} id The id of the dragged element
20127 * @method afterDragOut
20129 this.afterDragOut(target, e, id);
20132 this.cachedTarget = null;
20136 * An empty function by default, but provided so that you can perform a custom action before the dragged
20137 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20138 * @param {Roo.dd.DragDrop} target The drop target
20139 * @param {Event} e The event object
20140 * @param {String} id The id of the dragged element
20141 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20143 beforeDragOut : function(target, e, id){
20148 onDragDrop : function(e, id){
20149 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20150 if(this.beforeDragDrop(target, e, id) !== false){
20151 if(target.isNotifyTarget){
20152 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20153 this.onValidDrop(target, e, id);
20155 this.onInvalidDrop(target, e, id);
20158 this.onValidDrop(target, e, id);
20161 if(this.afterDragDrop){
20163 * An empty function by default, but provided so that you can perform a custom action
20164 * after a valid drag drop has occurred by providing an implementation.
20165 * @param {Roo.dd.DragDrop} target The drop target
20166 * @param {Event} e The event object
20167 * @param {String} id The id of the dropped element
20168 * @method afterDragDrop
20170 this.afterDragDrop(target, e, id);
20173 delete this.cachedTarget;
20177 * An empty function by default, but provided so that you can perform a custom action before the dragged
20178 * item is dropped onto the target and optionally cancel the onDragDrop.
20179 * @param {Roo.dd.DragDrop} target The drop target
20180 * @param {Event} e The event object
20181 * @param {String} id The id of the dragged element
20182 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20184 beforeDragDrop : function(target, e, id){
20189 onValidDrop : function(target, e, id){
20191 if(this.afterValidDrop){
20193 * An empty function by default, but provided so that you can perform a custom action
20194 * after a valid drop has occurred by providing an implementation.
20195 * @param {Object} target The target DD
20196 * @param {Event} e The event object
20197 * @param {String} id The id of the dropped element
20198 * @method afterInvalidDrop
20200 this.afterValidDrop(target, e, id);
20205 getRepairXY : function(e, data){
20206 return this.el.getXY();
20210 onInvalidDrop : function(target, e, id){
20211 this.beforeInvalidDrop(target, e, id);
20212 if(this.cachedTarget){
20213 if(this.cachedTarget.isNotifyTarget){
20214 this.cachedTarget.notifyOut(this, e, this.dragData);
20216 this.cacheTarget = null;
20218 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20220 if(this.afterInvalidDrop){
20222 * An empty function by default, but provided so that you can perform a custom action
20223 * after an invalid drop has occurred by providing an implementation.
20224 * @param {Event} e The event object
20225 * @param {String} id The id of the dropped element
20226 * @method afterInvalidDrop
20228 this.afterInvalidDrop(e, id);
20233 afterRepair : function(){
20235 this.el.highlight(this.hlColor || "c3daf9");
20237 this.dragging = false;
20241 * An empty function by default, but provided so that you can perform a custom action after an invalid
20242 * drop has occurred.
20243 * @param {Roo.dd.DragDrop} target The drop target
20244 * @param {Event} e The event object
20245 * @param {String} id The id of the dragged element
20246 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20248 beforeInvalidDrop : function(target, e, id){
20253 handleMouseDown : function(e){
20254 if(this.dragging) {
20257 var data = this.getDragData(e);
20258 if(data && this.onBeforeDrag(data, e) !== false){
20259 this.dragData = data;
20261 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20266 * An empty function by default, but provided so that you can perform a custom action before the initial
20267 * drag event begins and optionally cancel it.
20268 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20269 * @param {Event} e The event object
20270 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20272 onBeforeDrag : function(data, e){
20277 * An empty function by default, but provided so that you can perform a custom action once the initial
20278 * drag event has begun. The drag cannot be canceled from this function.
20279 * @param {Number} x The x position of the click on the dragged object
20280 * @param {Number} y The y position of the click on the dragged object
20282 onStartDrag : Roo.emptyFn,
20284 // private - YUI override
20285 startDrag : function(x, y){
20286 this.proxy.reset();
20287 this.dragging = true;
20288 this.proxy.update("");
20289 this.onInitDrag(x, y);
20294 onInitDrag : function(x, y){
20295 var clone = this.el.dom.cloneNode(true);
20296 clone.id = Roo.id(); // prevent duplicate ids
20297 this.proxy.update(clone);
20298 this.onStartDrag(x, y);
20303 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20304 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20306 getProxy : function(){
20311 * Hides the drag source's {@link Roo.dd.StatusProxy}
20313 hideProxy : function(){
20315 this.proxy.reset(true);
20316 this.dragging = false;
20320 triggerCacheRefresh : function(){
20321 Roo.dd.DDM.refreshCache(this.groups);
20324 // private - override to prevent hiding
20325 b4EndDrag: function(e) {
20328 // private - override to prevent moving
20329 endDrag : function(e){
20330 this.onEndDrag(this.dragData, e);
20334 onEndDrag : function(data, e){
20337 // private - pin to cursor
20338 autoOffset : function(x, y) {
20339 this.setDelta(-12, -20);
20343 * Ext JS Library 1.1.1
20344 * Copyright(c) 2006-2007, Ext JS, LLC.
20346 * Originally Released Under LGPL - original licence link has changed is not relivant.
20349 * <script type="text/javascript">
20354 * @class Roo.dd.DropTarget
20355 * @extends Roo.dd.DDTarget
20356 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20357 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20359 * @param {String/HTMLElement/Element} el The container element
20360 * @param {Object} config
20362 Roo.dd.DropTarget = function(el, config){
20363 this.el = Roo.get(el);
20365 var listeners = false; ;
20366 if (config && config.listeners) {
20367 listeners= config.listeners;
20368 delete config.listeners;
20370 Roo.apply(this, config);
20372 if(this.containerScroll){
20373 Roo.dd.ScrollManager.register(this.el);
20377 * @scope Roo.dd.DropTarget
20382 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20383 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20384 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20386 * IMPORTANT : it should set this.overClass and this.dropAllowed
20388 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20389 * @param {Event} e The event
20390 * @param {Object} data An object containing arbitrary data supplied by the drag source
20396 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20397 * This method will be called on every mouse movement while the drag source is over the drop target.
20398 * This default implementation simply returns the dropAllowed config value.
20400 * IMPORTANT : it should set this.dropAllowed
20402 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20403 * @param {Event} e The event
20404 * @param {Object} data An object containing arbitrary data supplied by the drag source
20410 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20411 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20412 * overClass (if any) from the drop element.
20414 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20415 * @param {Event} e The event
20416 * @param {Object} data An object containing arbitrary data supplied by the drag source
20422 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20423 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20424 * implementation that does something to process the drop event and returns true so that the drag source's
20425 * repair action does not run.
20427 * IMPORTANT : it should set this.success
20429 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20430 * @param {Event} e The event
20431 * @param {Object} data An object containing arbitrary data supplied by the drag source
20437 Roo.dd.DropTarget.superclass.constructor.call( this,
20439 this.ddGroup || this.group,
20442 listeners : listeners || {}
20450 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20452 * @cfg {String} overClass
20453 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20456 * @cfg {String} ddGroup
20457 * The drag drop group to handle drop events for
20461 * @cfg {String} dropAllowed
20462 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20464 dropAllowed : "x-dd-drop-ok",
20466 * @cfg {String} dropNotAllowed
20467 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20469 dropNotAllowed : "x-dd-drop-nodrop",
20471 * @cfg {boolean} success
20472 * set this after drop listener..
20476 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20477 * if the drop point is valid for over/enter..
20484 isNotifyTarget : true,
20489 notifyEnter : function(dd, e, data)
20492 this.fireEvent('enter', dd, e, data);
20493 if(this.overClass){
20494 this.el.addClass(this.overClass);
20496 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20497 this.valid ? this.dropAllowed : this.dropNotAllowed
20504 notifyOver : function(dd, e, data)
20507 this.fireEvent('over', dd, e, data);
20508 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20509 this.valid ? this.dropAllowed : this.dropNotAllowed
20516 notifyOut : function(dd, e, data)
20518 this.fireEvent('out', dd, e, data);
20519 if(this.overClass){
20520 this.el.removeClass(this.overClass);
20527 notifyDrop : function(dd, e, data)
20529 this.success = false;
20530 this.fireEvent('drop', dd, e, data);
20531 return this.success;
20535 * Ext JS Library 1.1.1
20536 * Copyright(c) 2006-2007, Ext JS, LLC.
20538 * Originally Released Under LGPL - original licence link has changed is not relivant.
20541 * <script type="text/javascript">
20546 * @class Roo.dd.DragZone
20547 * @extends Roo.dd.DragSource
20548 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20549 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20551 * @param {String/HTMLElement/Element} el The container element
20552 * @param {Object} config
20554 Roo.dd.DragZone = function(el, config){
20555 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20556 if(this.containerScroll){
20557 Roo.dd.ScrollManager.register(this.el);
20561 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20563 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20564 * for auto scrolling during drag operations.
20567 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20568 * method after a failed drop (defaults to "c3daf9" - light blue)
20572 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20573 * for a valid target to drag based on the mouse down. Override this method
20574 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20575 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20576 * @param {EventObject} e The mouse down event
20577 * @return {Object} The dragData
20579 getDragData : function(e){
20580 return Roo.dd.Registry.getHandleFromEvent(e);
20584 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20585 * this.dragData.ddel
20586 * @param {Number} x The x position of the click on the dragged object
20587 * @param {Number} y The y position of the click on the dragged object
20588 * @return {Boolean} true to continue the drag, false to cancel
20590 onInitDrag : function(x, y){
20591 this.proxy.update(this.dragData.ddel.cloneNode(true));
20592 this.onStartDrag(x, y);
20597 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20599 afterRepair : function(){
20601 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20603 this.dragging = false;
20607 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20608 * the XY of this.dragData.ddel
20609 * @param {EventObject} e The mouse up event
20610 * @return {Array} The xy location (e.g. [100, 200])
20612 getRepairXY : function(e){
20613 return Roo.Element.fly(this.dragData.ddel).getXY();
20617 * Ext JS Library 1.1.1
20618 * Copyright(c) 2006-2007, Ext JS, LLC.
20620 * Originally Released Under LGPL - original licence link has changed is not relivant.
20623 * <script type="text/javascript">
20626 * @class Roo.dd.DropZone
20627 * @extends Roo.dd.DropTarget
20628 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20629 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20631 * @param {String/HTMLElement/Element} el The container element
20632 * @param {Object} config
20634 Roo.dd.DropZone = function(el, config){
20635 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20638 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20640 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20641 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20642 * provide your own custom lookup.
20643 * @param {Event} e The event
20644 * @return {Object} data The custom data
20646 getTargetFromEvent : function(e){
20647 return Roo.dd.Registry.getTargetFromEvent(e);
20651 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20652 * that it has registered. This method has no default implementation and should be overridden to provide
20653 * node-specific processing if necessary.
20654 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20655 * {@link #getTargetFromEvent} for this node)
20656 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20657 * @param {Event} e The event
20658 * @param {Object} data An object containing arbitrary data supplied by the drag source
20660 onNodeEnter : function(n, dd, e, data){
20665 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20666 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20667 * overridden to provide the proper feedback.
20668 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20669 * {@link #getTargetFromEvent} for this node)
20670 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20671 * @param {Event} e The event
20672 * @param {Object} data An object containing arbitrary data supplied by the drag source
20673 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20674 * underlying {@link Roo.dd.StatusProxy} can be updated
20676 onNodeOver : function(n, dd, e, data){
20677 return this.dropAllowed;
20681 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20682 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20683 * node-specific processing if necessary.
20684 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20685 * {@link #getTargetFromEvent} for this node)
20686 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20687 * @param {Event} e The event
20688 * @param {Object} data An object containing arbitrary data supplied by the drag source
20690 onNodeOut : function(n, dd, e, data){
20695 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20696 * the drop node. The default implementation returns false, so it should be overridden to provide the
20697 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20698 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20699 * {@link #getTargetFromEvent} for this node)
20700 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20701 * @param {Event} e The event
20702 * @param {Object} data An object containing arbitrary data supplied by the drag source
20703 * @return {Boolean} True if the drop was valid, else false
20705 onNodeDrop : function(n, dd, e, data){
20710 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20711 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20712 * it should be overridden to provide the proper feedback if necessary.
20713 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20714 * @param {Event} e The event
20715 * @param {Object} data An object containing arbitrary data supplied by the drag source
20716 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20717 * underlying {@link Roo.dd.StatusProxy} can be updated
20719 onContainerOver : function(dd, e, data){
20720 return this.dropNotAllowed;
20724 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20725 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20726 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20727 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20728 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20729 * @param {Event} e The event
20730 * @param {Object} data An object containing arbitrary data supplied by the drag source
20731 * @return {Boolean} True if the drop was valid, else false
20733 onContainerDrop : function(dd, e, data){
20738 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20739 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20740 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20741 * you should override this method and provide a custom implementation.
20742 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20743 * @param {Event} e The event
20744 * @param {Object} data An object containing arbitrary data supplied by the drag source
20745 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20746 * underlying {@link Roo.dd.StatusProxy} can be updated
20748 notifyEnter : function(dd, e, data){
20749 return this.dropNotAllowed;
20753 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20754 * This method will be called on every mouse movement while the drag source is over the drop zone.
20755 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20756 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20757 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20758 * registered node, it will call {@link #onContainerOver}.
20759 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20760 * @param {Event} e The event
20761 * @param {Object} data An object containing arbitrary data supplied by the drag source
20762 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20763 * underlying {@link Roo.dd.StatusProxy} can be updated
20765 notifyOver : function(dd, e, data){
20766 var n = this.getTargetFromEvent(e);
20767 if(!n){ // not over valid drop target
20768 if(this.lastOverNode){
20769 this.onNodeOut(this.lastOverNode, dd, e, data);
20770 this.lastOverNode = null;
20772 return this.onContainerOver(dd, e, data);
20774 if(this.lastOverNode != n){
20775 if(this.lastOverNode){
20776 this.onNodeOut(this.lastOverNode, dd, e, data);
20778 this.onNodeEnter(n, dd, e, data);
20779 this.lastOverNode = n;
20781 return this.onNodeOver(n, dd, e, data);
20785 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20786 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20787 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20788 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20789 * @param {Event} e The event
20790 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20792 notifyOut : function(dd, e, data){
20793 if(this.lastOverNode){
20794 this.onNodeOut(this.lastOverNode, dd, e, data);
20795 this.lastOverNode = null;
20800 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20801 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20802 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20803 * otherwise it will call {@link #onContainerDrop}.
20804 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20805 * @param {Event} e The event
20806 * @param {Object} data An object containing arbitrary data supplied by the drag source
20807 * @return {Boolean} True if the drop was valid, else false
20809 notifyDrop : function(dd, e, data){
20810 if(this.lastOverNode){
20811 this.onNodeOut(this.lastOverNode, dd, e, data);
20812 this.lastOverNode = null;
20814 var n = this.getTargetFromEvent(e);
20816 this.onNodeDrop(n, dd, e, data) :
20817 this.onContainerDrop(dd, e, data);
20821 triggerCacheRefresh : function(){
20822 Roo.dd.DDM.refreshCache(this.groups);
20826 * Ext JS Library 1.1.1
20827 * Copyright(c) 2006-2007, Ext JS, LLC.
20829 * Originally Released Under LGPL - original licence link has changed is not relivant.
20832 * <script type="text/javascript">
20837 * @class Roo.data.SortTypes
20839 * Defines the default sorting (casting?) comparison functions used when sorting data.
20841 Roo.data.SortTypes = {
20843 * Default sort that does nothing
20844 * @param {Mixed} s The value being converted
20845 * @return {Mixed} The comparison value
20847 none : function(s){
20852 * The regular expression used to strip tags
20856 stripTagsRE : /<\/?[^>]+>/gi,
20859 * Strips all HTML tags to sort on text only
20860 * @param {Mixed} s The value being converted
20861 * @return {String} The comparison value
20863 asText : function(s){
20864 return String(s).replace(this.stripTagsRE, "");
20868 * Strips all HTML tags to sort on text only - Case insensitive
20869 * @param {Mixed} s The value being converted
20870 * @return {String} The comparison value
20872 asUCText : function(s){
20873 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20877 * Case insensitive string
20878 * @param {Mixed} s The value being converted
20879 * @return {String} The comparison value
20881 asUCString : function(s) {
20882 return String(s).toUpperCase();
20887 * @param {Mixed} s The value being converted
20888 * @return {Number} The comparison value
20890 asDate : function(s) {
20894 if(s instanceof Date){
20895 return s.getTime();
20897 return Date.parse(String(s));
20902 * @param {Mixed} s The value being converted
20903 * @return {Float} The comparison value
20905 asFloat : function(s) {
20906 var val = parseFloat(String(s).replace(/,/g, ""));
20907 if(isNaN(val)) val = 0;
20913 * @param {Mixed} s The value being converted
20914 * @return {Number} The comparison value
20916 asInt : function(s) {
20917 var val = parseInt(String(s).replace(/,/g, ""));
20918 if(isNaN(val)) val = 0;
20923 * Ext JS Library 1.1.1
20924 * Copyright(c) 2006-2007, Ext JS, LLC.
20926 * Originally Released Under LGPL - original licence link has changed is not relivant.
20929 * <script type="text/javascript">
20933 * @class Roo.data.Record
20934 * Instances of this class encapsulate both record <em>definition</em> information, and record
20935 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20936 * to access Records cached in an {@link Roo.data.Store} object.<br>
20938 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20939 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20942 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20944 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20945 * {@link #create}. The parameters are the same.
20946 * @param {Array} data An associative Array of data values keyed by the field name.
20947 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20948 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20949 * not specified an integer id is generated.
20951 Roo.data.Record = function(data, id){
20952 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20957 * Generate a constructor for a specific record layout.
20958 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20959 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20960 * Each field definition object may contain the following properties: <ul>
20961 * <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,
20962 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20963 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20964 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20965 * is being used, then this is a string containing the javascript expression to reference the data relative to
20966 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20967 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20968 * this may be omitted.</p></li>
20969 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20970 * <ul><li>auto (Default, implies no conversion)</li>
20975 * <li>date</li></ul></p></li>
20976 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20977 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20978 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20979 * by the Reader into an object that will be stored in the Record. It is passed the
20980 * following parameters:<ul>
20981 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20983 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20985 * <br>usage:<br><pre><code>
20986 var TopicRecord = Roo.data.Record.create(
20987 {name: 'title', mapping: 'topic_title'},
20988 {name: 'author', mapping: 'username'},
20989 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20990 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20991 {name: 'lastPoster', mapping: 'user2'},
20992 {name: 'excerpt', mapping: 'post_text'}
20995 var myNewRecord = new TopicRecord({
20996 title: 'Do my job please',
20999 lastPost: new Date(),
21000 lastPoster: 'Animal',
21001 excerpt: 'No way dude!'
21003 myStore.add(myNewRecord);
21008 Roo.data.Record.create = function(o){
21009 var f = function(){
21010 f.superclass.constructor.apply(this, arguments);
21012 Roo.extend(f, Roo.data.Record);
21013 var p = f.prototype;
21014 p.fields = new Roo.util.MixedCollection(false, function(field){
21017 for(var i = 0, len = o.length; i < len; i++){
21018 p.fields.add(new Roo.data.Field(o[i]));
21020 f.getField = function(name){
21021 return p.fields.get(name);
21026 Roo.data.Record.AUTO_ID = 1000;
21027 Roo.data.Record.EDIT = 'edit';
21028 Roo.data.Record.REJECT = 'reject';
21029 Roo.data.Record.COMMIT = 'commit';
21031 Roo.data.Record.prototype = {
21033 * Readonly flag - true if this record has been modified.
21042 join : function(store){
21043 this.store = store;
21047 * Set the named field to the specified value.
21048 * @param {String} name The name of the field to set.
21049 * @param {Object} value The value to set the field to.
21051 set : function(name, value){
21052 if(this.data[name] == value){
21056 if(!this.modified){
21057 this.modified = {};
21059 if(typeof this.modified[name] == 'undefined'){
21060 this.modified[name] = this.data[name];
21062 this.data[name] = value;
21063 if(!this.editing && this.store){
21064 this.store.afterEdit(this);
21069 * Get the value of the named field.
21070 * @param {String} name The name of the field to get the value of.
21071 * @return {Object} The value of the field.
21073 get : function(name){
21074 return this.data[name];
21078 beginEdit : function(){
21079 this.editing = true;
21080 this.modified = {};
21084 cancelEdit : function(){
21085 this.editing = false;
21086 delete this.modified;
21090 endEdit : function(){
21091 this.editing = false;
21092 if(this.dirty && this.store){
21093 this.store.afterEdit(this);
21098 * Usually called by the {@link Roo.data.Store} which owns the Record.
21099 * Rejects all changes made to the Record since either creation, or the last commit operation.
21100 * Modified fields are reverted to their original values.
21102 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21103 * of reject operations.
21105 reject : function(){
21106 var m = this.modified;
21108 if(typeof m[n] != "function"){
21109 this.data[n] = m[n];
21112 this.dirty = false;
21113 delete this.modified;
21114 this.editing = false;
21116 this.store.afterReject(this);
21121 * Usually called by the {@link Roo.data.Store} which owns the Record.
21122 * Commits all changes made to the Record since either creation, or the last commit operation.
21124 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21125 * of commit operations.
21127 commit : function(){
21128 this.dirty = false;
21129 delete this.modified;
21130 this.editing = false;
21132 this.store.afterCommit(this);
21137 hasError : function(){
21138 return this.error != null;
21142 clearError : function(){
21147 * Creates a copy of this record.
21148 * @param {String} id (optional) A new record id if you don't want to use this record's id
21151 copy : function(newId) {
21152 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21156 * Ext JS Library 1.1.1
21157 * Copyright(c) 2006-2007, Ext JS, LLC.
21159 * Originally Released Under LGPL - original licence link has changed is not relivant.
21162 * <script type="text/javascript">
21168 * @class Roo.data.Store
21169 * @extends Roo.util.Observable
21170 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21171 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21173 * 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
21174 * has no knowledge of the format of the data returned by the Proxy.<br>
21176 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21177 * instances from the data object. These records are cached and made available through accessor functions.
21179 * Creates a new Store.
21180 * @param {Object} config A config object containing the objects needed for the Store to access data,
21181 * and read the data into Records.
21183 Roo.data.Store = function(config){
21184 this.data = new Roo.util.MixedCollection(false);
21185 this.data.getKey = function(o){
21188 this.baseParams = {};
21190 this.paramNames = {
21195 "multisort" : "_multisort"
21198 if(config && config.data){
21199 this.inlineData = config.data;
21200 delete config.data;
21203 Roo.apply(this, config);
21205 if(this.reader){ // reader passed
21206 this.reader = Roo.factory(this.reader, Roo.data);
21207 this.reader.xmodule = this.xmodule || false;
21208 if(!this.recordType){
21209 this.recordType = this.reader.recordType;
21211 if(this.reader.onMetaChange){
21212 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21216 if(this.recordType){
21217 this.fields = this.recordType.prototype.fields;
21219 this.modified = [];
21223 * @event datachanged
21224 * Fires when the data cache has changed, and a widget which is using this Store
21225 * as a Record cache should refresh its view.
21226 * @param {Store} this
21228 datachanged : true,
21230 * @event metachange
21231 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21232 * @param {Store} this
21233 * @param {Object} meta The JSON metadata
21238 * Fires when Records have been added to the Store
21239 * @param {Store} this
21240 * @param {Roo.data.Record[]} records The array of Records added
21241 * @param {Number} index The index at which the record(s) were added
21246 * Fires when a Record has been removed from the Store
21247 * @param {Store} this
21248 * @param {Roo.data.Record} record The Record that was removed
21249 * @param {Number} index The index at which the record was removed
21254 * Fires when a Record has been updated
21255 * @param {Store} this
21256 * @param {Roo.data.Record} record The Record that was updated
21257 * @param {String} operation The update operation being performed. Value may be one of:
21259 Roo.data.Record.EDIT
21260 Roo.data.Record.REJECT
21261 Roo.data.Record.COMMIT
21267 * Fires when the data cache has been cleared.
21268 * @param {Store} this
21272 * @event beforeload
21273 * Fires before a request is made for a new data object. If the beforeload handler returns false
21274 * the load action will be canceled.
21275 * @param {Store} this
21276 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21280 * @event beforeloadadd
21281 * Fires after a new set of Records has been loaded.
21282 * @param {Store} this
21283 * @param {Roo.data.Record[]} records The Records that were loaded
21284 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21286 beforeloadadd : true,
21289 * Fires after a new set of Records has been loaded, before they are added to the store.
21290 * @param {Store} this
21291 * @param {Roo.data.Record[]} records The Records that were loaded
21292 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21293 * @params {Object} return from reader
21297 * @event loadexception
21298 * Fires if an exception occurs in the Proxy during loading.
21299 * Called with the signature of the Proxy's "loadexception" event.
21300 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21303 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21304 * @param {Object} load options
21305 * @param {Object} jsonData from your request (normally this contains the Exception)
21307 loadexception : true
21311 this.proxy = Roo.factory(this.proxy, Roo.data);
21312 this.proxy.xmodule = this.xmodule || false;
21313 this.relayEvents(this.proxy, ["loadexception"]);
21315 this.sortToggle = {};
21316 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21318 Roo.data.Store.superclass.constructor.call(this);
21320 if(this.inlineData){
21321 this.loadData(this.inlineData);
21322 delete this.inlineData;
21326 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21328 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21329 * without a remote query - used by combo/forms at present.
21333 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21336 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21339 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21340 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21343 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21344 * on any HTTP request
21347 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21350 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21354 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21355 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21357 remoteSort : false,
21360 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21361 * loaded or when a record is removed. (defaults to false).
21363 pruneModifiedRecords : false,
21366 lastOptions : null,
21369 * Add Records to the Store and fires the add event.
21370 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21372 add : function(records){
21373 records = [].concat(records);
21374 for(var i = 0, len = records.length; i < len; i++){
21375 records[i].join(this);
21377 var index = this.data.length;
21378 this.data.addAll(records);
21379 this.fireEvent("add", this, records, index);
21383 * Remove a Record from the Store and fires the remove event.
21384 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21386 remove : function(record){
21387 var index = this.data.indexOf(record);
21388 this.data.removeAt(index);
21389 if(this.pruneModifiedRecords){
21390 this.modified.remove(record);
21392 this.fireEvent("remove", this, record, index);
21396 * Remove all Records from the Store and fires the clear event.
21398 removeAll : function(){
21400 if(this.pruneModifiedRecords){
21401 this.modified = [];
21403 this.fireEvent("clear", this);
21407 * Inserts Records to the Store at the given index and fires the add event.
21408 * @param {Number} index The start index at which to insert the passed Records.
21409 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21411 insert : function(index, records){
21412 records = [].concat(records);
21413 for(var i = 0, len = records.length; i < len; i++){
21414 this.data.insert(index, records[i]);
21415 records[i].join(this);
21417 this.fireEvent("add", this, records, index);
21421 * Get the index within the cache of the passed Record.
21422 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21423 * @return {Number} The index of the passed Record. Returns -1 if not found.
21425 indexOf : function(record){
21426 return this.data.indexOf(record);
21430 * Get the index within the cache of the Record with the passed id.
21431 * @param {String} id The id of the Record to find.
21432 * @return {Number} The index of the Record. Returns -1 if not found.
21434 indexOfId : function(id){
21435 return this.data.indexOfKey(id);
21439 * Get the Record with the specified id.
21440 * @param {String} id The id of the Record to find.
21441 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21443 getById : function(id){
21444 return this.data.key(id);
21448 * Get the Record at the specified index.
21449 * @param {Number} index The index of the Record to find.
21450 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21452 getAt : function(index){
21453 return this.data.itemAt(index);
21457 * Returns a range of Records between specified indices.
21458 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21459 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21460 * @return {Roo.data.Record[]} An array of Records
21462 getRange : function(start, end){
21463 return this.data.getRange(start, end);
21467 storeOptions : function(o){
21468 o = Roo.apply({}, o);
21471 this.lastOptions = o;
21475 * Loads the Record cache from the configured Proxy using the configured Reader.
21477 * If using remote paging, then the first load call must specify the <em>start</em>
21478 * and <em>limit</em> properties in the options.params property to establish the initial
21479 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21481 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21482 * and this call will return before the new data has been loaded. Perform any post-processing
21483 * in a callback function, or in a "load" event handler.</strong>
21485 * @param {Object} options An object containing properties which control loading options:<ul>
21486 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21487 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21488 * passed the following arguments:<ul>
21489 * <li>r : Roo.data.Record[]</li>
21490 * <li>options: Options object from the load call</li>
21491 * <li>success: Boolean success indicator</li></ul></li>
21492 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21493 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21496 load : function(options){
21497 options = options || {};
21498 if(this.fireEvent("beforeload", this, options) !== false){
21499 this.storeOptions(options);
21500 var p = Roo.apply(options.params || {}, this.baseParams);
21501 // if meta was not loaded from remote source.. try requesting it.
21502 if (!this.reader.metaFromRemote) {
21503 p._requestMeta = 1;
21505 if(this.sortInfo && this.remoteSort){
21506 var pn = this.paramNames;
21507 p[pn["sort"]] = this.sortInfo.field;
21508 p[pn["dir"]] = this.sortInfo.direction;
21510 if (this.multiSort) {
21511 var pn = this.paramNames;
21512 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21515 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21520 * Reloads the Record cache from the configured Proxy using the configured Reader and
21521 * the options from the last load operation performed.
21522 * @param {Object} options (optional) An object containing properties which may override the options
21523 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21524 * the most recently used options are reused).
21526 reload : function(options){
21527 this.load(Roo.applyIf(options||{}, this.lastOptions));
21531 // Called as a callback by the Reader during a load operation.
21532 loadRecords : function(o, options, success){
21533 if(!o || success === false){
21534 if(success !== false){
21535 this.fireEvent("load", this, [], options, o);
21537 if(options.callback){
21538 options.callback.call(options.scope || this, [], options, false);
21542 // if data returned failure - throw an exception.
21543 if (o.success === false) {
21544 // show a message if no listener is registered.
21545 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21546 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21548 // loadmask wil be hooked into this..
21549 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21552 var r = o.records, t = o.totalRecords || r.length;
21554 this.fireEvent("beforeloadadd", this, r, options, o);
21556 if(!options || options.add !== true){
21557 if(this.pruneModifiedRecords){
21558 this.modified = [];
21560 for(var i = 0, len = r.length; i < len; i++){
21564 this.data = this.snapshot;
21565 delete this.snapshot;
21568 this.data.addAll(r);
21569 this.totalLength = t;
21571 this.fireEvent("datachanged", this);
21573 this.totalLength = Math.max(t, this.data.length+r.length);
21576 this.fireEvent("load", this, r, options, o);
21577 if(options.callback){
21578 options.callback.call(options.scope || this, r, options, true);
21584 * Loads data from a passed data block. A Reader which understands the format of the data
21585 * must have been configured in the constructor.
21586 * @param {Object} data The data block from which to read the Records. The format of the data expected
21587 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21588 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21590 loadData : function(o, append){
21591 var r = this.reader.readRecords(o);
21592 this.loadRecords(r, {add: append}, true);
21596 * Gets the number of cached records.
21598 * <em>If using paging, this may not be the total size of the dataset. If the data object
21599 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21600 * the data set size</em>
21602 getCount : function(){
21603 return this.data.length || 0;
21607 * Gets the total number of records in the dataset as returned by the server.
21609 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21610 * the dataset size</em>
21612 getTotalCount : function(){
21613 return this.totalLength || 0;
21617 * Returns the sort state of the Store as an object with two properties:
21619 field {String} The name of the field by which the Records are sorted
21620 direction {String} The sort order, "ASC" or "DESC"
21623 getSortState : function(){
21624 return this.sortInfo;
21628 applySort : function(){
21629 if(this.sortInfo && !this.remoteSort){
21630 var s = this.sortInfo, f = s.field;
21631 var st = this.fields.get(f).sortType;
21632 var fn = function(r1, r2){
21633 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21634 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21636 this.data.sort(s.direction, fn);
21637 if(this.snapshot && this.snapshot != this.data){
21638 this.snapshot.sort(s.direction, fn);
21644 * Sets the default sort column and order to be used by the next load operation.
21645 * @param {String} fieldName The name of the field to sort by.
21646 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21648 setDefaultSort : function(field, dir){
21649 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21653 * Sort the Records.
21654 * If remote sorting is used, the sort is performed on the server, and the cache is
21655 * reloaded. If local sorting is used, the cache is sorted internally.
21656 * @param {String} fieldName The name of the field to sort by.
21657 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21659 sort : function(fieldName, dir){
21660 var f = this.fields.get(fieldName);
21662 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21664 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21665 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21670 this.sortToggle[f.name] = dir;
21671 this.sortInfo = {field: f.name, direction: dir};
21672 if(!this.remoteSort){
21674 this.fireEvent("datachanged", this);
21676 this.load(this.lastOptions);
21681 * Calls the specified function for each of the Records in the cache.
21682 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21683 * Returning <em>false</em> aborts and exits the iteration.
21684 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21686 each : function(fn, scope){
21687 this.data.each(fn, scope);
21691 * Gets all records modified since the last commit. Modified records are persisted across load operations
21692 * (e.g., during paging).
21693 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21695 getModifiedRecords : function(){
21696 return this.modified;
21700 createFilterFn : function(property, value, anyMatch){
21701 if(!value.exec){ // not a regex
21702 value = String(value);
21703 if(value.length == 0){
21706 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21708 return function(r){
21709 return value.test(r.data[property]);
21714 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21715 * @param {String} property A field on your records
21716 * @param {Number} start The record index to start at (defaults to 0)
21717 * @param {Number} end The last record index to include (defaults to length - 1)
21718 * @return {Number} The sum
21720 sum : function(property, start, end){
21721 var rs = this.data.items, v = 0;
21722 start = start || 0;
21723 end = (end || end === 0) ? end : rs.length-1;
21725 for(var i = start; i <= end; i++){
21726 v += (rs[i].data[property] || 0);
21732 * Filter the records by a specified property.
21733 * @param {String} field A field on your records
21734 * @param {String/RegExp} value Either a string that the field
21735 * should start with or a RegExp to test against the field
21736 * @param {Boolean} anyMatch True to match any part not just the beginning
21738 filter : function(property, value, anyMatch){
21739 var fn = this.createFilterFn(property, value, anyMatch);
21740 return fn ? this.filterBy(fn) : this.clearFilter();
21744 * Filter by a function. The specified function will be called with each
21745 * record in this data source. If the function returns true the record is included,
21746 * otherwise it is filtered.
21747 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21748 * @param {Object} scope (optional) The scope of the function (defaults to this)
21750 filterBy : function(fn, scope){
21751 this.snapshot = this.snapshot || this.data;
21752 this.data = this.queryBy(fn, scope||this);
21753 this.fireEvent("datachanged", this);
21757 * Query the records by a specified property.
21758 * @param {String} field A field on your records
21759 * @param {String/RegExp} value Either a string that the field
21760 * should start with or a RegExp to test against the field
21761 * @param {Boolean} anyMatch True to match any part not just the beginning
21762 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21764 query : function(property, value, anyMatch){
21765 var fn = this.createFilterFn(property, value, anyMatch);
21766 return fn ? this.queryBy(fn) : this.data.clone();
21770 * Query by a function. The specified function will be called with each
21771 * record in this data source. If the function returns true the record is included
21773 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21774 * @param {Object} scope (optional) The scope of the function (defaults to this)
21775 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21777 queryBy : function(fn, scope){
21778 var data = this.snapshot || this.data;
21779 return data.filterBy(fn, scope||this);
21783 * Collects unique values for a particular dataIndex from this store.
21784 * @param {String} dataIndex The property to collect
21785 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21786 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21787 * @return {Array} An array of the unique values
21789 collect : function(dataIndex, allowNull, bypassFilter){
21790 var d = (bypassFilter === true && this.snapshot) ?
21791 this.snapshot.items : this.data.items;
21792 var v, sv, r = [], l = {};
21793 for(var i = 0, len = d.length; i < len; i++){
21794 v = d[i].data[dataIndex];
21796 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21805 * Revert to a view of the Record cache with no filtering applied.
21806 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21808 clearFilter : function(suppressEvent){
21809 if(this.snapshot && this.snapshot != this.data){
21810 this.data = this.snapshot;
21811 delete this.snapshot;
21812 if(suppressEvent !== true){
21813 this.fireEvent("datachanged", this);
21819 afterEdit : function(record){
21820 if(this.modified.indexOf(record) == -1){
21821 this.modified.push(record);
21823 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21827 afterReject : function(record){
21828 this.modified.remove(record);
21829 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21833 afterCommit : function(record){
21834 this.modified.remove(record);
21835 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21839 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21840 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21842 commitChanges : function(){
21843 var m = this.modified.slice(0);
21844 this.modified = [];
21845 for(var i = 0, len = m.length; i < len; i++){
21851 * Cancel outstanding changes on all changed records.
21853 rejectChanges : function(){
21854 var m = this.modified.slice(0);
21855 this.modified = [];
21856 for(var i = 0, len = m.length; i < len; i++){
21861 onMetaChange : function(meta, rtype, o){
21862 this.recordType = rtype;
21863 this.fields = rtype.prototype.fields;
21864 delete this.snapshot;
21865 this.sortInfo = meta.sortInfo || this.sortInfo;
21866 this.modified = [];
21867 this.fireEvent('metachange', this, this.reader.meta);
21870 moveIndex : function(data, type)
21872 var index = this.indexOf(data);
21874 var newIndex = index + type;
21878 this.insert(newIndex, data);
21883 * Ext JS Library 1.1.1
21884 * Copyright(c) 2006-2007, Ext JS, LLC.
21886 * Originally Released Under LGPL - original licence link has changed is not relivant.
21889 * <script type="text/javascript">
21893 * @class Roo.data.SimpleStore
21894 * @extends Roo.data.Store
21895 * Small helper class to make creating Stores from Array data easier.
21896 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21897 * @cfg {Array} fields An array of field definition objects, or field name strings.
21898 * @cfg {Array} data The multi-dimensional array of data
21900 * @param {Object} config
21902 Roo.data.SimpleStore = function(config){
21903 Roo.data.SimpleStore.superclass.constructor.call(this, {
21905 reader: new Roo.data.ArrayReader({
21908 Roo.data.Record.create(config.fields)
21910 proxy : new Roo.data.MemoryProxy(config.data)
21914 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21916 * Ext JS Library 1.1.1
21917 * Copyright(c) 2006-2007, Ext JS, LLC.
21919 * Originally Released Under LGPL - original licence link has changed is not relivant.
21922 * <script type="text/javascript">
21927 * @extends Roo.data.Store
21928 * @class Roo.data.JsonStore
21929 * Small helper class to make creating Stores for JSON data easier. <br/>
21931 var store = new Roo.data.JsonStore({
21932 url: 'get-images.php',
21934 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21937 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21938 * JsonReader and HttpProxy (unless inline data is provided).</b>
21939 * @cfg {Array} fields An array of field definition objects, or field name strings.
21941 * @param {Object} config
21943 Roo.data.JsonStore = function(c){
21944 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21945 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21946 reader: new Roo.data.JsonReader(c, c.fields)
21949 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21951 * Ext JS Library 1.1.1
21952 * Copyright(c) 2006-2007, Ext JS, LLC.
21954 * Originally Released Under LGPL - original licence link has changed is not relivant.
21957 * <script type="text/javascript">
21961 Roo.data.Field = function(config){
21962 if(typeof config == "string"){
21963 config = {name: config};
21965 Roo.apply(this, config);
21968 this.type = "auto";
21971 var st = Roo.data.SortTypes;
21972 // named sortTypes are supported, here we look them up
21973 if(typeof this.sortType == "string"){
21974 this.sortType = st[this.sortType];
21977 // set default sortType for strings and dates
21978 if(!this.sortType){
21981 this.sortType = st.asUCString;
21984 this.sortType = st.asDate;
21987 this.sortType = st.none;
21992 var stripRe = /[\$,%]/g;
21994 // prebuilt conversion function for this field, instead of
21995 // switching every time we're reading a value
21997 var cv, dateFormat = this.dateFormat;
22002 cv = function(v){ return v; };
22005 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22009 return v !== undefined && v !== null && v !== '' ?
22010 parseInt(String(v).replace(stripRe, ""), 10) : '';
22015 return v !== undefined && v !== null && v !== '' ?
22016 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22021 cv = function(v){ return v === true || v === "true" || v == 1; };
22028 if(v instanceof Date){
22032 if(dateFormat == "timestamp"){
22033 return new Date(v*1000);
22035 return Date.parseDate(v, dateFormat);
22037 var parsed = Date.parse(v);
22038 return parsed ? new Date(parsed) : null;
22047 Roo.data.Field.prototype = {
22055 * Ext JS Library 1.1.1
22056 * Copyright(c) 2006-2007, Ext JS, LLC.
22058 * Originally Released Under LGPL - original licence link has changed is not relivant.
22061 * <script type="text/javascript">
22064 // Base class for reading structured data from a data source. This class is intended to be
22065 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22068 * @class Roo.data.DataReader
22069 * Base class for reading structured data from a data source. This class is intended to be
22070 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22073 Roo.data.DataReader = function(meta, recordType){
22077 this.recordType = recordType instanceof Array ?
22078 Roo.data.Record.create(recordType) : recordType;
22081 Roo.data.DataReader.prototype = {
22083 * Create an empty record
22084 * @param {Object} data (optional) - overlay some values
22085 * @return {Roo.data.Record} record created.
22087 newRow : function(d) {
22089 this.recordType.prototype.fields.each(function(c) {
22091 case 'int' : da[c.name] = 0; break;
22092 case 'date' : da[c.name] = new Date(); break;
22093 case 'float' : da[c.name] = 0.0; break;
22094 case 'boolean' : da[c.name] = false; break;
22095 default : da[c.name] = ""; break;
22099 return new this.recordType(Roo.apply(da, d));
22104 * Ext JS Library 1.1.1
22105 * Copyright(c) 2006-2007, Ext JS, LLC.
22107 * Originally Released Under LGPL - original licence link has changed is not relivant.
22110 * <script type="text/javascript">
22114 * @class Roo.data.DataProxy
22115 * @extends Roo.data.Observable
22116 * This class is an abstract base class for implementations which provide retrieval of
22117 * unformatted data objects.<br>
22119 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22120 * (of the appropriate type which knows how to parse the data object) to provide a block of
22121 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22123 * Custom implementations must implement the load method as described in
22124 * {@link Roo.data.HttpProxy#load}.
22126 Roo.data.DataProxy = function(){
22129 * @event beforeload
22130 * Fires before a network request is made to retrieve a data object.
22131 * @param {Object} This DataProxy object.
22132 * @param {Object} params The params parameter to the load function.
22137 * Fires before the load method's callback is called.
22138 * @param {Object} This DataProxy object.
22139 * @param {Object} o The data object.
22140 * @param {Object} arg The callback argument object passed to the load function.
22144 * @event loadexception
22145 * Fires if an Exception occurs during data retrieval.
22146 * @param {Object} This DataProxy object.
22147 * @param {Object} o The data object.
22148 * @param {Object} arg The callback argument object passed to the load function.
22149 * @param {Object} e The Exception.
22151 loadexception : true
22153 Roo.data.DataProxy.superclass.constructor.call(this);
22156 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22159 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22163 * Ext JS Library 1.1.1
22164 * Copyright(c) 2006-2007, Ext JS, LLC.
22166 * Originally Released Under LGPL - original licence link has changed is not relivant.
22169 * <script type="text/javascript">
22172 * @class Roo.data.MemoryProxy
22173 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22174 * to the Reader when its load method is called.
22176 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22178 Roo.data.MemoryProxy = function(data){
22182 Roo.data.MemoryProxy.superclass.constructor.call(this);
22186 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22188 * Load data from the requested source (in this case an in-memory
22189 * data object passed to the constructor), read the data object into
22190 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22191 * process that block using the passed callback.
22192 * @param {Object} params This parameter is not used by the MemoryProxy class.
22193 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22194 * object into a block of Roo.data.Records.
22195 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22196 * The function must be passed <ul>
22197 * <li>The Record block object</li>
22198 * <li>The "arg" argument from the load function</li>
22199 * <li>A boolean success indicator</li>
22201 * @param {Object} scope The scope in which to call the callback
22202 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22204 load : function(params, reader, callback, scope, arg){
22205 params = params || {};
22208 result = reader.readRecords(this.data);
22210 this.fireEvent("loadexception", this, arg, null, e);
22211 callback.call(scope, null, arg, false);
22214 callback.call(scope, result, arg, true);
22218 update : function(params, records){
22223 * Ext JS Library 1.1.1
22224 * Copyright(c) 2006-2007, Ext JS, LLC.
22226 * Originally Released Under LGPL - original licence link has changed is not relivant.
22229 * <script type="text/javascript">
22232 * @class Roo.data.HttpProxy
22233 * @extends Roo.data.DataProxy
22234 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22235 * configured to reference a certain URL.<br><br>
22237 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22238 * from which the running page was served.<br><br>
22240 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22242 * Be aware that to enable the browser to parse an XML document, the server must set
22243 * the Content-Type header in the HTTP response to "text/xml".
22245 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22246 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22247 * will be used to make the request.
22249 Roo.data.HttpProxy = function(conn){
22250 Roo.data.HttpProxy.superclass.constructor.call(this);
22251 // is conn a conn config or a real conn?
22253 this.useAjax = !conn || !conn.events;
22257 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22258 // thse are take from connection...
22261 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22264 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22265 * extra parameters to each request made by this object. (defaults to undefined)
22268 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22269 * to each request made by this object. (defaults to undefined)
22272 * @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)
22275 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22278 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22284 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22288 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22289 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22290 * a finer-grained basis than the DataProxy events.
22292 getConnection : function(){
22293 return this.useAjax ? Roo.Ajax : this.conn;
22297 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22298 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22299 * process that block using the passed callback.
22300 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22301 * for the request to the remote server.
22302 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22303 * object into a block of Roo.data.Records.
22304 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22305 * The function must be passed <ul>
22306 * <li>The Record block object</li>
22307 * <li>The "arg" argument from the load function</li>
22308 * <li>A boolean success indicator</li>
22310 * @param {Object} scope The scope in which to call the callback
22311 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22313 load : function(params, reader, callback, scope, arg){
22314 if(this.fireEvent("beforeload", this, params) !== false){
22316 params : params || {},
22318 callback : callback,
22323 callback : this.loadResponse,
22327 Roo.applyIf(o, this.conn);
22328 if(this.activeRequest){
22329 Roo.Ajax.abort(this.activeRequest);
22331 this.activeRequest = Roo.Ajax.request(o);
22333 this.conn.request(o);
22336 callback.call(scope||this, null, arg, false);
22341 loadResponse : function(o, success, response){
22342 delete this.activeRequest;
22344 this.fireEvent("loadexception", this, o, response);
22345 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22350 result = o.reader.read(response);
22352 this.fireEvent("loadexception", this, o, response, e);
22353 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22357 this.fireEvent("load", this, o, o.request.arg);
22358 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22362 update : function(dataSet){
22367 updateResponse : function(dataSet){
22372 * Ext JS Library 1.1.1
22373 * Copyright(c) 2006-2007, Ext JS, LLC.
22375 * Originally Released Under LGPL - original licence link has changed is not relivant.
22378 * <script type="text/javascript">
22382 * @class Roo.data.ScriptTagProxy
22383 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22384 * other than the originating domain of the running page.<br><br>
22386 * <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
22387 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22389 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22390 * source code that is used as the source inside a <script> tag.<br><br>
22392 * In order for the browser to process the returned data, the server must wrap the data object
22393 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22394 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22395 * depending on whether the callback name was passed:
22398 boolean scriptTag = false;
22399 String cb = request.getParameter("callback");
22402 response.setContentType("text/javascript");
22404 response.setContentType("application/x-json");
22406 Writer out = response.getWriter();
22408 out.write(cb + "(");
22410 out.print(dataBlock.toJsonString());
22417 * @param {Object} config A configuration object.
22419 Roo.data.ScriptTagProxy = function(config){
22420 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22421 Roo.apply(this, config);
22422 this.head = document.getElementsByTagName("head")[0];
22425 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22427 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22429 * @cfg {String} url The URL from which to request the data object.
22432 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22436 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22437 * the server the name of the callback function set up by the load call to process the returned data object.
22438 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22439 * javascript output which calls this named function passing the data object as its only parameter.
22441 callbackParam : "callback",
22443 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22444 * name to the request.
22449 * Load data from the configured URL, read the data object into
22450 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22451 * process that block using the passed callback.
22452 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22453 * for the request to the remote server.
22454 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22455 * object into a block of Roo.data.Records.
22456 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22457 * The function must be passed <ul>
22458 * <li>The Record block object</li>
22459 * <li>The "arg" argument from the load function</li>
22460 * <li>A boolean success indicator</li>
22462 * @param {Object} scope The scope in which to call the callback
22463 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22465 load : function(params, reader, callback, scope, arg){
22466 if(this.fireEvent("beforeload", this, params) !== false){
22468 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22470 var url = this.url;
22471 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22473 url += "&_dc=" + (new Date().getTime());
22475 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22478 cb : "stcCallback"+transId,
22479 scriptId : "stcScript"+transId,
22483 callback : callback,
22489 window[trans.cb] = function(o){
22490 conn.handleResponse(o, trans);
22493 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22495 if(this.autoAbort !== false){
22499 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22501 var script = document.createElement("script");
22502 script.setAttribute("src", url);
22503 script.setAttribute("type", "text/javascript");
22504 script.setAttribute("id", trans.scriptId);
22505 this.head.appendChild(script);
22507 this.trans = trans;
22509 callback.call(scope||this, null, arg, false);
22514 isLoading : function(){
22515 return this.trans ? true : false;
22519 * Abort the current server request.
22521 abort : function(){
22522 if(this.isLoading()){
22523 this.destroyTrans(this.trans);
22528 destroyTrans : function(trans, isLoaded){
22529 this.head.removeChild(document.getElementById(trans.scriptId));
22530 clearTimeout(trans.timeoutId);
22532 window[trans.cb] = undefined;
22534 delete window[trans.cb];
22537 // if hasn't been loaded, wait for load to remove it to prevent script error
22538 window[trans.cb] = function(){
22539 window[trans.cb] = undefined;
22541 delete window[trans.cb];
22548 handleResponse : function(o, trans){
22549 this.trans = false;
22550 this.destroyTrans(trans, true);
22553 result = trans.reader.readRecords(o);
22555 this.fireEvent("loadexception", this, o, trans.arg, e);
22556 trans.callback.call(trans.scope||window, null, trans.arg, false);
22559 this.fireEvent("load", this, o, trans.arg);
22560 trans.callback.call(trans.scope||window, result, trans.arg, true);
22564 handleFailure : function(trans){
22565 this.trans = false;
22566 this.destroyTrans(trans, false);
22567 this.fireEvent("loadexception", this, null, trans.arg);
22568 trans.callback.call(trans.scope||window, null, trans.arg, false);
22572 * Ext JS Library 1.1.1
22573 * Copyright(c) 2006-2007, Ext JS, LLC.
22575 * Originally Released Under LGPL - original licence link has changed is not relivant.
22578 * <script type="text/javascript">
22582 * @class Roo.data.JsonReader
22583 * @extends Roo.data.DataReader
22584 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22585 * based on mappings in a provided Roo.data.Record constructor.
22587 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22588 * in the reply previously.
22593 var RecordDef = Roo.data.Record.create([
22594 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22595 {name: 'occupation'} // This field will use "occupation" as the mapping.
22597 var myReader = new Roo.data.JsonReader({
22598 totalProperty: "results", // The property which contains the total dataset size (optional)
22599 root: "rows", // The property which contains an Array of row objects
22600 id: "id" // The property within each row object that provides an ID for the record (optional)
22604 * This would consume a JSON file like this:
22606 { 'results': 2, 'rows': [
22607 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22608 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22611 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22612 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22613 * paged from the remote server.
22614 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22615 * @cfg {String} root name of the property which contains the Array of row objects.
22616 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22618 * Create a new JsonReader
22619 * @param {Object} meta Metadata configuration options
22620 * @param {Object} recordType Either an Array of field definition objects,
22621 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22623 Roo.data.JsonReader = function(meta, recordType){
22626 // set some defaults:
22627 Roo.applyIf(meta, {
22628 totalProperty: 'total',
22629 successProperty : 'success',
22634 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22636 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22639 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22640 * Used by Store query builder to append _requestMeta to params.
22643 metaFromRemote : false,
22645 * This method is only used by a DataProxy which has retrieved data from a remote server.
22646 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22647 * @return {Object} data A data block which is used by an Roo.data.Store object as
22648 * a cache of Roo.data.Records.
22650 read : function(response){
22651 var json = response.responseText;
22653 var o = /* eval:var:o */ eval("("+json+")");
22655 throw {message: "JsonReader.read: Json object not found"};
22661 this.metaFromRemote = true;
22662 this.meta = o.metaData;
22663 this.recordType = Roo.data.Record.create(o.metaData.fields);
22664 this.onMetaChange(this.meta, this.recordType, o);
22666 return this.readRecords(o);
22669 // private function a store will implement
22670 onMetaChange : function(meta, recordType, o){
22677 simpleAccess: function(obj, subsc) {
22684 getJsonAccessor: function(){
22686 return function(expr) {
22688 return(re.test(expr))
22689 ? new Function("obj", "return obj." + expr)
22694 return Roo.emptyFn;
22699 * Create a data block containing Roo.data.Records from an XML document.
22700 * @param {Object} o An object which contains an Array of row objects in the property specified
22701 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22702 * which contains the total size of the dataset.
22703 * @return {Object} data A data block which is used by an Roo.data.Store object as
22704 * a cache of Roo.data.Records.
22706 readRecords : function(o){
22708 * After any data loads, the raw JSON data is available for further custom processing.
22712 var s = this.meta, Record = this.recordType,
22713 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22715 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22717 if(s.totalProperty) {
22718 this.getTotal = this.getJsonAccessor(s.totalProperty);
22720 if(s.successProperty) {
22721 this.getSuccess = this.getJsonAccessor(s.successProperty);
22723 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22725 var g = this.getJsonAccessor(s.id);
22726 this.getId = function(rec) {
22728 return (r === undefined || r === "") ? null : r;
22731 this.getId = function(){return null;};
22734 for(var jj = 0; jj < fl; jj++){
22736 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22737 this.ef[jj] = this.getJsonAccessor(map);
22741 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22742 if(s.totalProperty){
22743 var vt = parseInt(this.getTotal(o), 10);
22748 if(s.successProperty){
22749 var vs = this.getSuccess(o);
22750 if(vs === false || vs === 'false'){
22755 for(var i = 0; i < c; i++){
22758 var id = this.getId(n);
22759 for(var j = 0; j < fl; j++){
22761 var v = this.ef[j](n);
22763 Roo.log('missing convert for ' + f.name);
22767 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22769 var record = new Record(values, id);
22771 records[i] = record;
22777 totalRecords : totalRecords
22782 * Ext JS Library 1.1.1
22783 * Copyright(c) 2006-2007, Ext JS, LLC.
22785 * Originally Released Under LGPL - original licence link has changed is not relivant.
22788 * <script type="text/javascript">
22792 * @class Roo.data.XmlReader
22793 * @extends Roo.data.DataReader
22794 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22795 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22797 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22798 * header in the HTTP response must be set to "text/xml".</em>
22802 var RecordDef = Roo.data.Record.create([
22803 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22804 {name: 'occupation'} // This field will use "occupation" as the mapping.
22806 var myReader = new Roo.data.XmlReader({
22807 totalRecords: "results", // The element which contains the total dataset size (optional)
22808 record: "row", // The repeated element which contains row information
22809 id: "id" // The element within the row that provides an ID for the record (optional)
22813 * This would consume an XML file like this:
22817 <results>2</results>
22820 <name>Bill</name>
22821 <occupation>Gardener</occupation>
22825 <name>Ben</name>
22826 <occupation>Horticulturalist</occupation>
22830 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22831 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22832 * paged from the remote server.
22833 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22834 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22835 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22836 * a record identifier value.
22838 * Create a new XmlReader
22839 * @param {Object} meta Metadata configuration options
22840 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22841 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22842 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22844 Roo.data.XmlReader = function(meta, recordType){
22846 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22848 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22850 * This method is only used by a DataProxy which has retrieved data from a remote server.
22851 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22852 * to contain a method called 'responseXML' that returns an XML document object.
22853 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22854 * a cache of Roo.data.Records.
22856 read : function(response){
22857 var doc = response.responseXML;
22859 throw {message: "XmlReader.read: XML Document not available"};
22861 return this.readRecords(doc);
22865 * Create a data block containing Roo.data.Records from an XML document.
22866 * @param {Object} doc A parsed XML document.
22867 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22868 * a cache of Roo.data.Records.
22870 readRecords : function(doc){
22872 * After any data loads/reads, the raw XML Document is available for further custom processing.
22873 * @type XMLDocument
22875 this.xmlData = doc;
22876 var root = doc.documentElement || doc;
22877 var q = Roo.DomQuery;
22878 var recordType = this.recordType, fields = recordType.prototype.fields;
22879 var sid = this.meta.id;
22880 var totalRecords = 0, success = true;
22881 if(this.meta.totalRecords){
22882 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22885 if(this.meta.success){
22886 var sv = q.selectValue(this.meta.success, root, true);
22887 success = sv !== false && sv !== 'false';
22890 var ns = q.select(this.meta.record, root);
22891 for(var i = 0, len = ns.length; i < len; i++) {
22894 var id = sid ? q.selectValue(sid, n) : undefined;
22895 for(var j = 0, jlen = fields.length; j < jlen; j++){
22896 var f = fields.items[j];
22897 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22899 values[f.name] = v;
22901 var record = new recordType(values, id);
22903 records[records.length] = record;
22909 totalRecords : totalRecords || records.length
22914 * Ext JS Library 1.1.1
22915 * Copyright(c) 2006-2007, Ext JS, LLC.
22917 * Originally Released Under LGPL - original licence link has changed is not relivant.
22920 * <script type="text/javascript">
22924 * @class Roo.data.ArrayReader
22925 * @extends Roo.data.DataReader
22926 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22927 * Each element of that Array represents a row of data fields. The
22928 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22929 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22933 var RecordDef = Roo.data.Record.create([
22934 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22935 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22937 var myReader = new Roo.data.ArrayReader({
22938 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22942 * This would consume an Array like this:
22944 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22946 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22948 * Create a new JsonReader
22949 * @param {Object} meta Metadata configuration options.
22950 * @param {Object} recordType Either an Array of field definition objects
22951 * as specified to {@link Roo.data.Record#create},
22952 * or an {@link Roo.data.Record} object
22953 * created using {@link Roo.data.Record#create}.
22955 Roo.data.ArrayReader = function(meta, recordType){
22956 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22959 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22961 * Create a data block containing Roo.data.Records from an XML document.
22962 * @param {Object} o An Array of row objects which represents the dataset.
22963 * @return {Object} data A data block which is used by an Roo.data.Store object as
22964 * a cache of Roo.data.Records.
22966 readRecords : function(o){
22967 var sid = this.meta ? this.meta.id : null;
22968 var recordType = this.recordType, fields = recordType.prototype.fields;
22971 for(var i = 0; i < root.length; i++){
22974 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22975 for(var j = 0, jlen = fields.length; j < jlen; j++){
22976 var f = fields.items[j];
22977 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22978 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22980 values[f.name] = v;
22982 var record = new recordType(values, id);
22984 records[records.length] = record;
22988 totalRecords : records.length
22993 * Ext JS Library 1.1.1
22994 * Copyright(c) 2006-2007, Ext JS, LLC.
22996 * Originally Released Under LGPL - original licence link has changed is not relivant.
22999 * <script type="text/javascript">
23004 * @class Roo.data.Tree
23005 * @extends Roo.util.Observable
23006 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23007 * in the tree have most standard DOM functionality.
23009 * @param {Node} root (optional) The root node
23011 Roo.data.Tree = function(root){
23012 this.nodeHash = {};
23014 * The root node for this tree
23019 this.setRootNode(root);
23024 * Fires when a new child node is appended to a node in this tree.
23025 * @param {Tree} tree The owner tree
23026 * @param {Node} parent The parent node
23027 * @param {Node} node The newly appended node
23028 * @param {Number} index The index of the newly appended node
23033 * Fires when a child node is removed from a node in this tree.
23034 * @param {Tree} tree The owner tree
23035 * @param {Node} parent The parent node
23036 * @param {Node} node The child node removed
23041 * Fires when a node is moved to a new location in the tree
23042 * @param {Tree} tree The owner tree
23043 * @param {Node} node The node moved
23044 * @param {Node} oldParent The old parent of this node
23045 * @param {Node} newParent The new parent of this node
23046 * @param {Number} index The index it was moved to
23051 * Fires when a new child node is inserted in a node in this tree.
23052 * @param {Tree} tree The owner tree
23053 * @param {Node} parent The parent node
23054 * @param {Node} node The child node inserted
23055 * @param {Node} refNode The child node the node was inserted before
23059 * @event beforeappend
23060 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23061 * @param {Tree} tree The owner tree
23062 * @param {Node} parent The parent node
23063 * @param {Node} node The child node to be appended
23065 "beforeappend" : true,
23067 * @event beforeremove
23068 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23069 * @param {Tree} tree The owner tree
23070 * @param {Node} parent The parent node
23071 * @param {Node} node The child node to be removed
23073 "beforeremove" : true,
23075 * @event beforemove
23076 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23077 * @param {Tree} tree The owner tree
23078 * @param {Node} node The node being moved
23079 * @param {Node} oldParent The parent of the node
23080 * @param {Node} newParent The new parent the node is moving to
23081 * @param {Number} index The index it is being moved to
23083 "beforemove" : true,
23085 * @event beforeinsert
23086 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23087 * @param {Tree} tree The owner tree
23088 * @param {Node} parent The parent node
23089 * @param {Node} node The child node to be inserted
23090 * @param {Node} refNode The child node the node is being inserted before
23092 "beforeinsert" : true
23095 Roo.data.Tree.superclass.constructor.call(this);
23098 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23099 pathSeparator: "/",
23101 proxyNodeEvent : function(){
23102 return this.fireEvent.apply(this, arguments);
23106 * Returns the root node for this tree.
23109 getRootNode : function(){
23114 * Sets the root node for this tree.
23115 * @param {Node} node
23118 setRootNode : function(node){
23120 node.ownerTree = this;
23121 node.isRoot = true;
23122 this.registerNode(node);
23127 * Gets a node in this tree by its id.
23128 * @param {String} id
23131 getNodeById : function(id){
23132 return this.nodeHash[id];
23135 registerNode : function(node){
23136 this.nodeHash[node.id] = node;
23139 unregisterNode : function(node){
23140 delete this.nodeHash[node.id];
23143 toString : function(){
23144 return "[Tree"+(this.id?" "+this.id:"")+"]";
23149 * @class Roo.data.Node
23150 * @extends Roo.util.Observable
23151 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23152 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23154 * @param {Object} attributes The attributes/config for the node
23156 Roo.data.Node = function(attributes){
23158 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23161 this.attributes = attributes || {};
23162 this.leaf = this.attributes.leaf;
23164 * The node id. @type String
23166 this.id = this.attributes.id;
23168 this.id = Roo.id(null, "ynode-");
23169 this.attributes.id = this.id;
23174 * All child nodes of this node. @type Array
23176 this.childNodes = [];
23177 if(!this.childNodes.indexOf){ // indexOf is a must
23178 this.childNodes.indexOf = function(o){
23179 for(var i = 0, len = this.length; i < len; i++){
23188 * The parent node for this node. @type Node
23190 this.parentNode = null;
23192 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23194 this.firstChild = null;
23196 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23198 this.lastChild = null;
23200 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23202 this.previousSibling = null;
23204 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23206 this.nextSibling = null;
23211 * Fires when a new child node is appended
23212 * @param {Tree} tree The owner tree
23213 * @param {Node} this This node
23214 * @param {Node} node The newly appended node
23215 * @param {Number} index The index of the newly appended node
23220 * Fires when a child node is removed
23221 * @param {Tree} tree The owner tree
23222 * @param {Node} this This node
23223 * @param {Node} node The removed node
23228 * Fires when this node is moved to a new location in the tree
23229 * @param {Tree} tree The owner tree
23230 * @param {Node} this This node
23231 * @param {Node} oldParent The old parent of this node
23232 * @param {Node} newParent The new parent of this node
23233 * @param {Number} index The index it was moved to
23238 * Fires when a new child node is inserted.
23239 * @param {Tree} tree The owner tree
23240 * @param {Node} this This node
23241 * @param {Node} node The child node inserted
23242 * @param {Node} refNode The child node the node was inserted before
23246 * @event beforeappend
23247 * Fires before a new child is appended, return false to cancel the append.
23248 * @param {Tree} tree The owner tree
23249 * @param {Node} this This node
23250 * @param {Node} node The child node to be appended
23252 "beforeappend" : true,
23254 * @event beforeremove
23255 * Fires before a child is removed, return false to cancel the remove.
23256 * @param {Tree} tree The owner tree
23257 * @param {Node} this This node
23258 * @param {Node} node The child node to be removed
23260 "beforeremove" : true,
23262 * @event beforemove
23263 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23264 * @param {Tree} tree The owner tree
23265 * @param {Node} this This node
23266 * @param {Node} oldParent The parent of this node
23267 * @param {Node} newParent The new parent this node is moving to
23268 * @param {Number} index The index it is being moved to
23270 "beforemove" : true,
23272 * @event beforeinsert
23273 * Fires before a new child is inserted, return false to cancel the insert.
23274 * @param {Tree} tree The owner tree
23275 * @param {Node} this This node
23276 * @param {Node} node The child node to be inserted
23277 * @param {Node} refNode The child node the node is being inserted before
23279 "beforeinsert" : true
23281 this.listeners = this.attributes.listeners;
23282 Roo.data.Node.superclass.constructor.call(this);
23285 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23286 fireEvent : function(evtName){
23287 // first do standard event for this node
23288 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23291 // then bubble it up to the tree if the event wasn't cancelled
23292 var ot = this.getOwnerTree();
23294 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23302 * Returns true if this node is a leaf
23303 * @return {Boolean}
23305 isLeaf : function(){
23306 return this.leaf === true;
23310 setFirstChild : function(node){
23311 this.firstChild = node;
23315 setLastChild : function(node){
23316 this.lastChild = node;
23321 * Returns true if this node is the last child of its parent
23322 * @return {Boolean}
23324 isLast : function(){
23325 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23329 * Returns true if this node is the first child of its parent
23330 * @return {Boolean}
23332 isFirst : function(){
23333 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23336 hasChildNodes : function(){
23337 return !this.isLeaf() && this.childNodes.length > 0;
23341 * Insert node(s) as the last child node of this node.
23342 * @param {Node/Array} node The node or Array of nodes to append
23343 * @return {Node} The appended node if single append, or null if an array was passed
23345 appendChild : function(node){
23347 if(node instanceof Array){
23349 }else if(arguments.length > 1){
23352 // if passed an array or multiple args do them one by one
23354 for(var i = 0, len = multi.length; i < len; i++) {
23355 this.appendChild(multi[i]);
23358 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23361 var index = this.childNodes.length;
23362 var oldParent = node.parentNode;
23363 // it's a move, make sure we move it cleanly
23365 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23368 oldParent.removeChild(node);
23370 index = this.childNodes.length;
23372 this.setFirstChild(node);
23374 this.childNodes.push(node);
23375 node.parentNode = this;
23376 var ps = this.childNodes[index-1];
23378 node.previousSibling = ps;
23379 ps.nextSibling = node;
23381 node.previousSibling = null;
23383 node.nextSibling = null;
23384 this.setLastChild(node);
23385 node.setOwnerTree(this.getOwnerTree());
23386 this.fireEvent("append", this.ownerTree, this, node, index);
23388 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23395 * Removes a child node from this node.
23396 * @param {Node} node The node to remove
23397 * @return {Node} The removed node
23399 removeChild : function(node){
23400 var index = this.childNodes.indexOf(node);
23404 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23408 // remove it from childNodes collection
23409 this.childNodes.splice(index, 1);
23412 if(node.previousSibling){
23413 node.previousSibling.nextSibling = node.nextSibling;
23415 if(node.nextSibling){
23416 node.nextSibling.previousSibling = node.previousSibling;
23419 // update child refs
23420 if(this.firstChild == node){
23421 this.setFirstChild(node.nextSibling);
23423 if(this.lastChild == node){
23424 this.setLastChild(node.previousSibling);
23427 node.setOwnerTree(null);
23428 // clear any references from the node
23429 node.parentNode = null;
23430 node.previousSibling = null;
23431 node.nextSibling = null;
23432 this.fireEvent("remove", this.ownerTree, this, node);
23437 * Inserts the first node before the second node in this nodes childNodes collection.
23438 * @param {Node} node The node to insert
23439 * @param {Node} refNode The node to insert before (if null the node is appended)
23440 * @return {Node} The inserted node
23442 insertBefore : function(node, refNode){
23443 if(!refNode){ // like standard Dom, refNode can be null for append
23444 return this.appendChild(node);
23447 if(node == refNode){
23451 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23454 var index = this.childNodes.indexOf(refNode);
23455 var oldParent = node.parentNode;
23456 var refIndex = index;
23458 // when moving internally, indexes will change after remove
23459 if(oldParent == this && this.childNodes.indexOf(node) < index){
23463 // it's a move, make sure we move it cleanly
23465 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23468 oldParent.removeChild(node);
23471 this.setFirstChild(node);
23473 this.childNodes.splice(refIndex, 0, node);
23474 node.parentNode = this;
23475 var ps = this.childNodes[refIndex-1];
23477 node.previousSibling = ps;
23478 ps.nextSibling = node;
23480 node.previousSibling = null;
23482 node.nextSibling = refNode;
23483 refNode.previousSibling = node;
23484 node.setOwnerTree(this.getOwnerTree());
23485 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23487 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23493 * Returns the child node at the specified index.
23494 * @param {Number} index
23497 item : function(index){
23498 return this.childNodes[index];
23502 * Replaces one child node in this node with another.
23503 * @param {Node} newChild The replacement node
23504 * @param {Node} oldChild The node to replace
23505 * @return {Node} The replaced node
23507 replaceChild : function(newChild, oldChild){
23508 this.insertBefore(newChild, oldChild);
23509 this.removeChild(oldChild);
23514 * Returns the index of a child node
23515 * @param {Node} node
23516 * @return {Number} The index of the node or -1 if it was not found
23518 indexOf : function(child){
23519 return this.childNodes.indexOf(child);
23523 * Returns the tree this node is in.
23526 getOwnerTree : function(){
23527 // if it doesn't have one, look for one
23528 if(!this.ownerTree){
23532 this.ownerTree = p.ownerTree;
23538 return this.ownerTree;
23542 * Returns depth of this node (the root node has a depth of 0)
23545 getDepth : function(){
23548 while(p.parentNode){
23556 setOwnerTree : function(tree){
23557 // if it's move, we need to update everyone
23558 if(tree != this.ownerTree){
23559 if(this.ownerTree){
23560 this.ownerTree.unregisterNode(this);
23562 this.ownerTree = tree;
23563 var cs = this.childNodes;
23564 for(var i = 0, len = cs.length; i < len; i++) {
23565 cs[i].setOwnerTree(tree);
23568 tree.registerNode(this);
23574 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23575 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23576 * @return {String} The path
23578 getPath : function(attr){
23579 attr = attr || "id";
23580 var p = this.parentNode;
23581 var b = [this.attributes[attr]];
23583 b.unshift(p.attributes[attr]);
23586 var sep = this.getOwnerTree().pathSeparator;
23587 return sep + b.join(sep);
23591 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23592 * function call will be the scope provided or the current node. The arguments to the function
23593 * will be the args provided or the current node. If the function returns false at any point,
23594 * the bubble is stopped.
23595 * @param {Function} fn The function to call
23596 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23597 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23599 bubble : function(fn, scope, args){
23602 if(fn.call(scope || p, args || p) === false){
23610 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23611 * function call will be the scope provided or the current node. The arguments to the function
23612 * will be the args provided or the current node. If the function returns false at any point,
23613 * the cascade is stopped on that branch.
23614 * @param {Function} fn The function to call
23615 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23616 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23618 cascade : function(fn, scope, args){
23619 if(fn.call(scope || this, args || this) !== false){
23620 var cs = this.childNodes;
23621 for(var i = 0, len = cs.length; i < len; i++) {
23622 cs[i].cascade(fn, scope, args);
23628 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23629 * function call will be the scope provided or the current node. The arguments to the function
23630 * will be the args provided or the current node. If the function returns false at any point,
23631 * the iteration stops.
23632 * @param {Function} fn The function to call
23633 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23634 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23636 eachChild : function(fn, scope, args){
23637 var cs = this.childNodes;
23638 for(var i = 0, len = cs.length; i < len; i++) {
23639 if(fn.call(scope || this, args || cs[i]) === false){
23646 * Finds the first child that has the attribute with the specified value.
23647 * @param {String} attribute The attribute name
23648 * @param {Mixed} value The value to search for
23649 * @return {Node} The found child or null if none was found
23651 findChild : function(attribute, value){
23652 var cs = this.childNodes;
23653 for(var i = 0, len = cs.length; i < len; i++) {
23654 if(cs[i].attributes[attribute] == value){
23662 * Finds the first child by a custom function. The child matches if the function passed
23664 * @param {Function} fn
23665 * @param {Object} scope (optional)
23666 * @return {Node} The found child or null if none was found
23668 findChildBy : function(fn, scope){
23669 var cs = this.childNodes;
23670 for(var i = 0, len = cs.length; i < len; i++) {
23671 if(fn.call(scope||cs[i], cs[i]) === true){
23679 * Sorts this nodes children using the supplied sort function
23680 * @param {Function} fn
23681 * @param {Object} scope (optional)
23683 sort : function(fn, scope){
23684 var cs = this.childNodes;
23685 var len = cs.length;
23687 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23689 for(var i = 0; i < len; i++){
23691 n.previousSibling = cs[i-1];
23692 n.nextSibling = cs[i+1];
23694 this.setFirstChild(n);
23697 this.setLastChild(n);
23704 * Returns true if this node is an ancestor (at any point) of the passed node.
23705 * @param {Node} node
23706 * @return {Boolean}
23708 contains : function(node){
23709 return node.isAncestor(this);
23713 * Returns true if the passed node is an ancestor (at any point) of this node.
23714 * @param {Node} node
23715 * @return {Boolean}
23717 isAncestor : function(node){
23718 var p = this.parentNode;
23728 toString : function(){
23729 return "[Node"+(this.id?" "+this.id:"")+"]";
23733 * Ext JS Library 1.1.1
23734 * Copyright(c) 2006-2007, Ext JS, LLC.
23736 * Originally Released Under LGPL - original licence link has changed is not relivant.
23739 * <script type="text/javascript">
23744 * @extends Roo.Element
23745 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23746 * automatic maintaining of shadow/shim positions.
23747 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23748 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23749 * you can pass a string with a CSS class name. False turns off the shadow.
23750 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23751 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23752 * @cfg {String} cls CSS class to add to the element
23753 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23754 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23756 * @param {Object} config An object with config options.
23757 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23760 Roo.Layer = function(config, existingEl){
23761 config = config || {};
23762 var dh = Roo.DomHelper;
23763 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23765 this.dom = Roo.getDom(existingEl);
23768 var o = config.dh || {tag: "div", cls: "x-layer"};
23769 this.dom = dh.append(pel, o);
23772 this.addClass(config.cls);
23774 this.constrain = config.constrain !== false;
23775 this.visibilityMode = Roo.Element.VISIBILITY;
23777 this.id = this.dom.id = config.id;
23779 this.id = Roo.id(this.dom);
23781 this.zindex = config.zindex || this.getZIndex();
23782 this.position("absolute", this.zindex);
23784 this.shadowOffset = config.shadowOffset || 4;
23785 this.shadow = new Roo.Shadow({
23786 offset : this.shadowOffset,
23787 mode : config.shadow
23790 this.shadowOffset = 0;
23792 this.useShim = config.shim !== false && Roo.useShims;
23793 this.useDisplay = config.useDisplay;
23797 var supr = Roo.Element.prototype;
23799 // shims are shared among layer to keep from having 100 iframes
23802 Roo.extend(Roo.Layer, Roo.Element, {
23804 getZIndex : function(){
23805 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23808 getShim : function(){
23815 var shim = shims.shift();
23817 shim = this.createShim();
23818 shim.enableDisplayMode('block');
23819 shim.dom.style.display = 'none';
23820 shim.dom.style.visibility = 'visible';
23822 var pn = this.dom.parentNode;
23823 if(shim.dom.parentNode != pn){
23824 pn.insertBefore(shim.dom, this.dom);
23826 shim.setStyle('z-index', this.getZIndex()-2);
23831 hideShim : function(){
23833 this.shim.setDisplayed(false);
23834 shims.push(this.shim);
23839 disableShadow : function(){
23841 this.shadowDisabled = true;
23842 this.shadow.hide();
23843 this.lastShadowOffset = this.shadowOffset;
23844 this.shadowOffset = 0;
23848 enableShadow : function(show){
23850 this.shadowDisabled = false;
23851 this.shadowOffset = this.lastShadowOffset;
23852 delete this.lastShadowOffset;
23860 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23861 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23862 sync : function(doShow){
23863 var sw = this.shadow;
23864 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23865 var sh = this.getShim();
23867 var w = this.getWidth(),
23868 h = this.getHeight();
23870 var l = this.getLeft(true),
23871 t = this.getTop(true);
23873 if(sw && !this.shadowDisabled){
23874 if(doShow && !sw.isVisible()){
23877 sw.realign(l, t, w, h);
23883 // fit the shim behind the shadow, so it is shimmed too
23884 var a = sw.adjusts, s = sh.dom.style;
23885 s.left = (Math.min(l, l+a.l))+"px";
23886 s.top = (Math.min(t, t+a.t))+"px";
23887 s.width = (w+a.w)+"px";
23888 s.height = (h+a.h)+"px";
23895 sh.setLeftTop(l, t);
23902 destroy : function(){
23905 this.shadow.hide();
23907 this.removeAllListeners();
23908 var pn = this.dom.parentNode;
23910 pn.removeChild(this.dom);
23912 Roo.Element.uncache(this.id);
23915 remove : function(){
23920 beginUpdate : function(){
23921 this.updating = true;
23925 endUpdate : function(){
23926 this.updating = false;
23931 hideUnders : function(negOffset){
23933 this.shadow.hide();
23939 constrainXY : function(){
23940 if(this.constrain){
23941 var vw = Roo.lib.Dom.getViewWidth(),
23942 vh = Roo.lib.Dom.getViewHeight();
23943 var s = Roo.get(document).getScroll();
23945 var xy = this.getXY();
23946 var x = xy[0], y = xy[1];
23947 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23948 // only move it if it needs it
23950 // first validate right/bottom
23951 if((x + w) > vw+s.left){
23952 x = vw - w - this.shadowOffset;
23955 if((y + h) > vh+s.top){
23956 y = vh - h - this.shadowOffset;
23959 // then make sure top/left isn't negative
23970 var ay = this.avoidY;
23971 if(y <= ay && (y+h) >= ay){
23977 supr.setXY.call(this, xy);
23983 isVisible : function(){
23984 return this.visible;
23988 showAction : function(){
23989 this.visible = true; // track visibility to prevent getStyle calls
23990 if(this.useDisplay === true){
23991 this.setDisplayed("");
23992 }else if(this.lastXY){
23993 supr.setXY.call(this, this.lastXY);
23994 }else if(this.lastLT){
23995 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24000 hideAction : function(){
24001 this.visible = false;
24002 if(this.useDisplay === true){
24003 this.setDisplayed(false);
24005 this.setLeftTop(-10000,-10000);
24009 // overridden Element method
24010 setVisible : function(v, a, d, c, e){
24015 var cb = function(){
24020 }.createDelegate(this);
24021 supr.setVisible.call(this, true, true, d, cb, e);
24024 this.hideUnders(true);
24033 }.createDelegate(this);
24035 supr.setVisible.call(this, v, a, d, cb, e);
24044 storeXY : function(xy){
24045 delete this.lastLT;
24049 storeLeftTop : function(left, top){
24050 delete this.lastXY;
24051 this.lastLT = [left, top];
24055 beforeFx : function(){
24056 this.beforeAction();
24057 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24061 afterFx : function(){
24062 Roo.Layer.superclass.afterFx.apply(this, arguments);
24063 this.sync(this.isVisible());
24067 beforeAction : function(){
24068 if(!this.updating && this.shadow){
24069 this.shadow.hide();
24073 // overridden Element method
24074 setLeft : function(left){
24075 this.storeLeftTop(left, this.getTop(true));
24076 supr.setLeft.apply(this, arguments);
24080 setTop : function(top){
24081 this.storeLeftTop(this.getLeft(true), top);
24082 supr.setTop.apply(this, arguments);
24086 setLeftTop : function(left, top){
24087 this.storeLeftTop(left, top);
24088 supr.setLeftTop.apply(this, arguments);
24092 setXY : function(xy, a, d, c, e){
24094 this.beforeAction();
24096 var cb = this.createCB(c);
24097 supr.setXY.call(this, xy, a, d, cb, e);
24104 createCB : function(c){
24115 // overridden Element method
24116 setX : function(x, a, d, c, e){
24117 this.setXY([x, this.getY()], a, d, c, e);
24120 // overridden Element method
24121 setY : function(y, a, d, c, e){
24122 this.setXY([this.getX(), y], a, d, c, e);
24125 // overridden Element method
24126 setSize : function(w, h, a, d, c, e){
24127 this.beforeAction();
24128 var cb = this.createCB(c);
24129 supr.setSize.call(this, w, h, a, d, cb, e);
24135 // overridden Element method
24136 setWidth : function(w, a, d, c, e){
24137 this.beforeAction();
24138 var cb = this.createCB(c);
24139 supr.setWidth.call(this, w, a, d, cb, e);
24145 // overridden Element method
24146 setHeight : function(h, a, d, c, e){
24147 this.beforeAction();
24148 var cb = this.createCB(c);
24149 supr.setHeight.call(this, h, a, d, cb, e);
24155 // overridden Element method
24156 setBounds : function(x, y, w, h, a, d, c, e){
24157 this.beforeAction();
24158 var cb = this.createCB(c);
24160 this.storeXY([x, y]);
24161 supr.setXY.call(this, [x, y]);
24162 supr.setSize.call(this, w, h, a, d, cb, e);
24165 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24171 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24172 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24173 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24174 * @param {Number} zindex The new z-index to set
24175 * @return {this} The Layer
24177 setZIndex : function(zindex){
24178 this.zindex = zindex;
24179 this.setStyle("z-index", zindex + 2);
24181 this.shadow.setZIndex(zindex + 1);
24184 this.shim.setStyle("z-index", zindex);
24190 * Ext JS Library 1.1.1
24191 * Copyright(c) 2006-2007, Ext JS, LLC.
24193 * Originally Released Under LGPL - original licence link has changed is not relivant.
24196 * <script type="text/javascript">
24201 * @class Roo.Shadow
24202 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24203 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24204 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24206 * Create a new Shadow
24207 * @param {Object} config The config object
24209 Roo.Shadow = function(config){
24210 Roo.apply(this, config);
24211 if(typeof this.mode != "string"){
24212 this.mode = this.defaultMode;
24214 var o = this.offset, a = {h: 0};
24215 var rad = Math.floor(this.offset/2);
24216 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24222 a.l -= this.offset + rad;
24223 a.t -= this.offset + rad;
24234 a.l -= (this.offset - rad);
24235 a.t -= this.offset + rad;
24237 a.w -= (this.offset - rad)*2;
24248 a.l -= (this.offset - rad);
24249 a.t -= (this.offset - rad);
24251 a.w -= (this.offset + rad + 1);
24252 a.h -= (this.offset + rad);
24261 Roo.Shadow.prototype = {
24263 * @cfg {String} mode
24264 * The shadow display mode. Supports the following options:<br />
24265 * sides: Shadow displays on both sides and bottom only<br />
24266 * frame: Shadow displays equally on all four sides<br />
24267 * drop: Traditional bottom-right drop shadow (default)
24270 * @cfg {String} offset
24271 * The number of pixels to offset the shadow from the element (defaults to 4)
24276 defaultMode: "drop",
24279 * Displays the shadow under the target element
24280 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24282 show : function(target){
24283 target = Roo.get(target);
24285 this.el = Roo.Shadow.Pool.pull();
24286 if(this.el.dom.nextSibling != target.dom){
24287 this.el.insertBefore(target);
24290 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24292 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24295 target.getLeft(true),
24296 target.getTop(true),
24300 this.el.dom.style.display = "block";
24304 * Returns true if the shadow is visible, else false
24306 isVisible : function(){
24307 return this.el ? true : false;
24311 * Direct alignment when values are already available. Show must be called at least once before
24312 * calling this method to ensure it is initialized.
24313 * @param {Number} left The target element left position
24314 * @param {Number} top The target element top position
24315 * @param {Number} width The target element width
24316 * @param {Number} height The target element height
24318 realign : function(l, t, w, h){
24322 var a = this.adjusts, d = this.el.dom, s = d.style;
24324 s.left = (l+a.l)+"px";
24325 s.top = (t+a.t)+"px";
24326 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24328 if(s.width != sws || s.height != shs){
24332 var cn = d.childNodes;
24333 var sww = Math.max(0, (sw-12))+"px";
24334 cn[0].childNodes[1].style.width = sww;
24335 cn[1].childNodes[1].style.width = sww;
24336 cn[2].childNodes[1].style.width = sww;
24337 cn[1].style.height = Math.max(0, (sh-12))+"px";
24343 * Hides this shadow
24347 this.el.dom.style.display = "none";
24348 Roo.Shadow.Pool.push(this.el);
24354 * Adjust the z-index of this shadow
24355 * @param {Number} zindex The new z-index
24357 setZIndex : function(z){
24360 this.el.setStyle("z-index", z);
24365 // Private utility class that manages the internal Shadow cache
24366 Roo.Shadow.Pool = function(){
24368 var markup = Roo.isIE ?
24369 '<div class="x-ie-shadow"></div>' :
24370 '<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>';
24373 var sh = p.shift();
24375 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24376 sh.autoBoxAdjust = false;
24381 push : function(sh){
24387 * Ext JS Library 1.1.1
24388 * Copyright(c) 2006-2007, Ext JS, LLC.
24390 * Originally Released Under LGPL - original licence link has changed is not relivant.
24393 * <script type="text/javascript">
24398 * @class Roo.SplitBar
24399 * @extends Roo.util.Observable
24400 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24404 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24405 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24406 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24407 split.minSize = 100;
24408 split.maxSize = 600;
24409 split.animate = true;
24410 split.on('moved', splitterMoved);
24413 * Create a new SplitBar
24414 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24415 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24416 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24417 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24418 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24419 position of the SplitBar).
24421 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24424 this.el = Roo.get(dragElement, true);
24425 this.el.dom.unselectable = "on";
24427 this.resizingEl = Roo.get(resizingElement, true);
24431 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24432 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24435 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24438 * The minimum size of the resizing element. (Defaults to 0)
24444 * The maximum size of the resizing element. (Defaults to 2000)
24447 this.maxSize = 2000;
24450 * Whether to animate the transition to the new size
24453 this.animate = false;
24456 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24459 this.useShim = false;
24464 if(!existingProxy){
24466 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24468 this.proxy = Roo.get(existingProxy).dom;
24471 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24474 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24477 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24480 this.dragSpecs = {};
24483 * @private The adapter to use to positon and resize elements
24485 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24486 this.adapter.init(this);
24488 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24490 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24491 this.el.addClass("x-splitbar-h");
24494 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24495 this.el.addClass("x-splitbar-v");
24501 * Fires when the splitter is moved (alias for {@link #event-moved})
24502 * @param {Roo.SplitBar} this
24503 * @param {Number} newSize the new width or height
24508 * Fires when the splitter is moved
24509 * @param {Roo.SplitBar} this
24510 * @param {Number} newSize the new width or height
24514 * @event beforeresize
24515 * Fires before the splitter is dragged
24516 * @param {Roo.SplitBar} this
24518 "beforeresize" : true,
24520 "beforeapply" : true
24523 Roo.util.Observable.call(this);
24526 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24527 onStartProxyDrag : function(x, y){
24528 this.fireEvent("beforeresize", this);
24530 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24532 o.enableDisplayMode("block");
24533 // all splitbars share the same overlay
24534 Roo.SplitBar.prototype.overlay = o;
24536 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24537 this.overlay.show();
24538 Roo.get(this.proxy).setDisplayed("block");
24539 var size = this.adapter.getElementSize(this);
24540 this.activeMinSize = this.getMinimumSize();;
24541 this.activeMaxSize = this.getMaximumSize();;
24542 var c1 = size - this.activeMinSize;
24543 var c2 = Math.max(this.activeMaxSize - size, 0);
24544 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24545 this.dd.resetConstraints();
24546 this.dd.setXConstraint(
24547 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24548 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24550 this.dd.setYConstraint(0, 0);
24552 this.dd.resetConstraints();
24553 this.dd.setXConstraint(0, 0);
24554 this.dd.setYConstraint(
24555 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24556 this.placement == Roo.SplitBar.TOP ? c2 : c1
24559 this.dragSpecs.startSize = size;
24560 this.dragSpecs.startPoint = [x, y];
24561 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24565 * @private Called after the drag operation by the DDProxy
24567 onEndProxyDrag : function(e){
24568 Roo.get(this.proxy).setDisplayed(false);
24569 var endPoint = Roo.lib.Event.getXY(e);
24571 this.overlay.hide();
24574 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24575 newSize = this.dragSpecs.startSize +
24576 (this.placement == Roo.SplitBar.LEFT ?
24577 endPoint[0] - this.dragSpecs.startPoint[0] :
24578 this.dragSpecs.startPoint[0] - endPoint[0]
24581 newSize = this.dragSpecs.startSize +
24582 (this.placement == Roo.SplitBar.TOP ?
24583 endPoint[1] - this.dragSpecs.startPoint[1] :
24584 this.dragSpecs.startPoint[1] - endPoint[1]
24587 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24588 if(newSize != this.dragSpecs.startSize){
24589 if(this.fireEvent('beforeapply', this, newSize) !== false){
24590 this.adapter.setElementSize(this, newSize);
24591 this.fireEvent("moved", this, newSize);
24592 this.fireEvent("resize", this, newSize);
24598 * Get the adapter this SplitBar uses
24599 * @return The adapter object
24601 getAdapter : function(){
24602 return this.adapter;
24606 * Set the adapter this SplitBar uses
24607 * @param {Object} adapter A SplitBar adapter object
24609 setAdapter : function(adapter){
24610 this.adapter = adapter;
24611 this.adapter.init(this);
24615 * Gets the minimum size for the resizing element
24616 * @return {Number} The minimum size
24618 getMinimumSize : function(){
24619 return this.minSize;
24623 * Sets the minimum size for the resizing element
24624 * @param {Number} minSize The minimum size
24626 setMinimumSize : function(minSize){
24627 this.minSize = minSize;
24631 * Gets the maximum size for the resizing element
24632 * @return {Number} The maximum size
24634 getMaximumSize : function(){
24635 return this.maxSize;
24639 * Sets the maximum size for the resizing element
24640 * @param {Number} maxSize The maximum size
24642 setMaximumSize : function(maxSize){
24643 this.maxSize = maxSize;
24647 * Sets the initialize size for the resizing element
24648 * @param {Number} size The initial size
24650 setCurrentSize : function(size){
24651 var oldAnimate = this.animate;
24652 this.animate = false;
24653 this.adapter.setElementSize(this, size);
24654 this.animate = oldAnimate;
24658 * Destroy this splitbar.
24659 * @param {Boolean} removeEl True to remove the element
24661 destroy : function(removeEl){
24663 this.shim.remove();
24666 this.proxy.parentNode.removeChild(this.proxy);
24674 * @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.
24676 Roo.SplitBar.createProxy = function(dir){
24677 var proxy = new Roo.Element(document.createElement("div"));
24678 proxy.unselectable();
24679 var cls = 'x-splitbar-proxy';
24680 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24681 document.body.appendChild(proxy.dom);
24686 * @class Roo.SplitBar.BasicLayoutAdapter
24687 * Default Adapter. It assumes the splitter and resizing element are not positioned
24688 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24690 Roo.SplitBar.BasicLayoutAdapter = function(){
24693 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24694 // do nothing for now
24695 init : function(s){
24699 * Called before drag operations to get the current size of the resizing element.
24700 * @param {Roo.SplitBar} s The SplitBar using this adapter
24702 getElementSize : function(s){
24703 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24704 return s.resizingEl.getWidth();
24706 return s.resizingEl.getHeight();
24711 * Called after drag operations to set the size of the resizing element.
24712 * @param {Roo.SplitBar} s The SplitBar using this adapter
24713 * @param {Number} newSize The new size to set
24714 * @param {Function} onComplete A function to be invoked when resizing is complete
24716 setElementSize : function(s, newSize, onComplete){
24717 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24719 s.resizingEl.setWidth(newSize);
24721 onComplete(s, newSize);
24724 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24729 s.resizingEl.setHeight(newSize);
24731 onComplete(s, newSize);
24734 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24741 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24742 * @extends Roo.SplitBar.BasicLayoutAdapter
24743 * Adapter that moves the splitter element to align with the resized sizing element.
24744 * Used with an absolute positioned SplitBar.
24745 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24746 * document.body, make sure you assign an id to the body element.
24748 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24749 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24750 this.container = Roo.get(container);
24753 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24754 init : function(s){
24755 this.basic.init(s);
24758 getElementSize : function(s){
24759 return this.basic.getElementSize(s);
24762 setElementSize : function(s, newSize, onComplete){
24763 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24766 moveSplitter : function(s){
24767 var yes = Roo.SplitBar;
24768 switch(s.placement){
24770 s.el.setX(s.resizingEl.getRight());
24773 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24776 s.el.setY(s.resizingEl.getBottom());
24779 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24786 * Orientation constant - Create a vertical SplitBar
24790 Roo.SplitBar.VERTICAL = 1;
24793 * Orientation constant - Create a horizontal SplitBar
24797 Roo.SplitBar.HORIZONTAL = 2;
24800 * Placement constant - The resizing element is to the left of the splitter element
24804 Roo.SplitBar.LEFT = 1;
24807 * Placement constant - The resizing element is to the right of the splitter element
24811 Roo.SplitBar.RIGHT = 2;
24814 * Placement constant - The resizing element is positioned above the splitter element
24818 Roo.SplitBar.TOP = 3;
24821 * Placement constant - The resizing element is positioned under splitter element
24825 Roo.SplitBar.BOTTOM = 4;
24828 * Ext JS Library 1.1.1
24829 * Copyright(c) 2006-2007, Ext JS, LLC.
24831 * Originally Released Under LGPL - original licence link has changed is not relivant.
24834 * <script type="text/javascript">
24839 * @extends Roo.util.Observable
24840 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24841 * This class also supports single and multi selection modes. <br>
24842 * Create a data model bound view:
24844 var store = new Roo.data.Store(...);
24846 var view = new Roo.View({
24848 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24850 singleSelect: true,
24851 selectedClass: "ydataview-selected",
24855 // listen for node click?
24856 view.on("click", function(vw, index, node, e){
24857 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24861 dataModel.load("foobar.xml");
24863 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24865 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24866 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24868 * Note: old style constructor is still suported (container, template, config)
24871 * Create a new View
24872 * @param {Object} config The config object
24875 Roo.View = function(config, depreciated_tpl, depreciated_config){
24877 this.parent = false;
24879 if (typeof(depreciated_tpl) == 'undefined') {
24880 // new way.. - universal constructor.
24881 Roo.apply(this, config);
24882 this.el = Roo.get(this.el);
24885 this.el = Roo.get(config);
24886 this.tpl = depreciated_tpl;
24887 Roo.apply(this, depreciated_config);
24889 this.wrapEl = this.el.wrap().wrap();
24890 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24893 if(typeof(this.tpl) == "string"){
24894 this.tpl = new Roo.Template(this.tpl);
24896 // support xtype ctors..
24897 this.tpl = new Roo.factory(this.tpl, Roo);
24901 this.tpl.compile();
24906 * @event beforeclick
24907 * Fires before a click is processed. Returns false to cancel the default action.
24908 * @param {Roo.View} this
24909 * @param {Number} index The index of the target node
24910 * @param {HTMLElement} node The target node
24911 * @param {Roo.EventObject} e The raw event object
24913 "beforeclick" : true,
24916 * Fires when a template node is clicked.
24917 * @param {Roo.View} this
24918 * @param {Number} index The index of the target node
24919 * @param {HTMLElement} node The target node
24920 * @param {Roo.EventObject} e The raw event object
24925 * Fires when a template node is double clicked.
24926 * @param {Roo.View} this
24927 * @param {Number} index The index of the target node
24928 * @param {HTMLElement} node The target node
24929 * @param {Roo.EventObject} e The raw event object
24933 * @event contextmenu
24934 * Fires when a template node is right clicked.
24935 * @param {Roo.View} this
24936 * @param {Number} index The index of the target node
24937 * @param {HTMLElement} node The target node
24938 * @param {Roo.EventObject} e The raw event object
24940 "contextmenu" : true,
24942 * @event selectionchange
24943 * Fires when the selected nodes change.
24944 * @param {Roo.View} this
24945 * @param {Array} selections Array of the selected nodes
24947 "selectionchange" : true,
24950 * @event beforeselect
24951 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24952 * @param {Roo.View} this
24953 * @param {HTMLElement} node The node to be selected
24954 * @param {Array} selections Array of currently selected nodes
24956 "beforeselect" : true,
24958 * @event preparedata
24959 * Fires on every row to render, to allow you to change the data.
24960 * @param {Roo.View} this
24961 * @param {Object} data to be rendered (change this)
24963 "preparedata" : true
24971 "click": this.onClick,
24972 "dblclick": this.onDblClick,
24973 "contextmenu": this.onContextMenu,
24977 this.selections = [];
24979 this.cmp = new Roo.CompositeElementLite([]);
24981 this.store = Roo.factory(this.store, Roo.data);
24982 this.setStore(this.store, true);
24985 if ( this.footer && this.footer.xtype) {
24987 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24989 this.footer.dataSource = this.store
24990 this.footer.container = fctr;
24991 this.footer = Roo.factory(this.footer, Roo);
24992 fctr.insertFirst(this.el);
24994 // this is a bit insane - as the paging toolbar seems to detach the el..
24995 // dom.parentNode.parentNode.parentNode
24996 // they get detached?
25000 Roo.View.superclass.constructor.call(this);
25005 Roo.extend(Roo.View, Roo.util.Observable, {
25008 * @cfg {Roo.data.Store} store Data store to load data from.
25013 * @cfg {String|Roo.Element} el The container element.
25018 * @cfg {String|Roo.Template} tpl The template used by this View
25022 * @cfg {String} dataName the named area of the template to use as the data area
25023 * Works with domtemplates roo-name="name"
25027 * @cfg {String} selectedClass The css class to add to selected nodes
25029 selectedClass : "x-view-selected",
25031 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25036 * @cfg {String} text to display on mask (default Loading)
25040 * @cfg {Boolean} multiSelect Allow multiple selection
25042 multiSelect : false,
25044 * @cfg {Boolean} singleSelect Allow single selection
25046 singleSelect: false,
25049 * @cfg {Boolean} toggleSelect - selecting
25051 toggleSelect : false,
25054 * @cfg {Boolean} tickable - selecting
25059 * Returns the element this view is bound to.
25060 * @return {Roo.Element}
25062 getEl : function(){
25063 return this.wrapEl;
25069 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25071 refresh : function(){
25072 //Roo.log('refresh');
25075 // if we are using something like 'domtemplate', then
25076 // the what gets used is:
25077 // t.applySubtemplate(NAME, data, wrapping data..)
25078 // the outer template then get' applied with
25079 // the store 'extra data'
25080 // and the body get's added to the
25081 // roo-name="data" node?
25082 // <span class='roo-tpl-{name}'></span> ?????
25086 this.clearSelections();
25087 this.el.update("");
25089 var records = this.store.getRange();
25090 if(records.length < 1) {
25092 // is this valid?? = should it render a template??
25094 this.el.update(this.emptyText);
25098 if (this.dataName) {
25099 this.el.update(t.apply(this.store.meta)); //????
25100 el = this.el.child('.roo-tpl-' + this.dataName);
25103 for(var i = 0, len = records.length; i < len; i++){
25104 var data = this.prepareData(records[i].data, i, records[i]);
25105 this.fireEvent("preparedata", this, data, i, records[i]);
25107 var d = Roo.apply({}, data);
25110 Roo.apply(d, {'roo-id' : Roo.id()});
25114 Roo.each(this.parent.item, function(item){
25115 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25118 Roo.apply(d, {'roo-data-checked' : 'checked'});
25122 html[html.length] = Roo.util.Format.trim(
25124 t.applySubtemplate(this.dataName, d, this.store.meta) :
25131 el.update(html.join(""));
25132 this.nodes = el.dom.childNodes;
25133 this.updateIndexes(0);
25138 * Function to override to reformat the data that is sent to
25139 * the template for each node.
25140 * DEPRICATED - use the preparedata event handler.
25141 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25142 * a JSON object for an UpdateManager bound view).
25144 prepareData : function(data, index, record)
25146 this.fireEvent("preparedata", this, data, index, record);
25150 onUpdate : function(ds, record){
25151 // Roo.log('on update');
25152 this.clearSelections();
25153 var index = this.store.indexOf(record);
25154 var n = this.nodes[index];
25155 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25156 n.parentNode.removeChild(n);
25157 this.updateIndexes(index, index);
25163 onAdd : function(ds, records, index)
25165 //Roo.log(['on Add', ds, records, index] );
25166 this.clearSelections();
25167 if(this.nodes.length == 0){
25171 var n = this.nodes[index];
25172 for(var i = 0, len = records.length; i < len; i++){
25173 var d = this.prepareData(records[i].data, i, records[i]);
25175 this.tpl.insertBefore(n, d);
25178 this.tpl.append(this.el, d);
25181 this.updateIndexes(index);
25184 onRemove : function(ds, record, index){
25185 // Roo.log('onRemove');
25186 this.clearSelections();
25187 var el = this.dataName ?
25188 this.el.child('.roo-tpl-' + this.dataName) :
25191 el.dom.removeChild(this.nodes[index]);
25192 this.updateIndexes(index);
25196 * Refresh an individual node.
25197 * @param {Number} index
25199 refreshNode : function(index){
25200 this.onUpdate(this.store, this.store.getAt(index));
25203 updateIndexes : function(startIndex, endIndex){
25204 var ns = this.nodes;
25205 startIndex = startIndex || 0;
25206 endIndex = endIndex || ns.length - 1;
25207 for(var i = startIndex; i <= endIndex; i++){
25208 ns[i].nodeIndex = i;
25213 * Changes the data store this view uses and refresh the view.
25214 * @param {Store} store
25216 setStore : function(store, initial){
25217 if(!initial && this.store){
25218 this.store.un("datachanged", this.refresh);
25219 this.store.un("add", this.onAdd);
25220 this.store.un("remove", this.onRemove);
25221 this.store.un("update", this.onUpdate);
25222 this.store.un("clear", this.refresh);
25223 this.store.un("beforeload", this.onBeforeLoad);
25224 this.store.un("load", this.onLoad);
25225 this.store.un("loadexception", this.onLoad);
25229 store.on("datachanged", this.refresh, this);
25230 store.on("add", this.onAdd, this);
25231 store.on("remove", this.onRemove, this);
25232 store.on("update", this.onUpdate, this);
25233 store.on("clear", this.refresh, this);
25234 store.on("beforeload", this.onBeforeLoad, this);
25235 store.on("load", this.onLoad, this);
25236 store.on("loadexception", this.onLoad, this);
25244 * onbeforeLoad - masks the loading area.
25247 onBeforeLoad : function(store,opts)
25249 //Roo.log('onBeforeLoad');
25251 this.el.update("");
25253 this.el.mask(this.mask ? this.mask : "Loading" );
25255 onLoad : function ()
25262 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25263 * @param {HTMLElement} node
25264 * @return {HTMLElement} The template node
25266 findItemFromChild : function(node){
25267 var el = this.dataName ?
25268 this.el.child('.roo-tpl-' + this.dataName,true) :
25271 if(!node || node.parentNode == el){
25274 var p = node.parentNode;
25275 while(p && p != el){
25276 if(p.parentNode == el){
25285 onClick : function(e){
25286 var item = this.findItemFromChild(e.getTarget());
25288 var index = this.indexOf(item);
25289 if(this.onItemClick(item, index, e) !== false){
25290 this.fireEvent("click", this, index, item, e);
25293 this.clearSelections();
25298 onContextMenu : function(e){
25299 var item = this.findItemFromChild(e.getTarget());
25301 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25306 onDblClick : function(e){
25307 var item = this.findItemFromChild(e.getTarget());
25309 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25313 onItemClick : function(item, index, e)
25315 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25318 if (this.toggleSelect) {
25319 var m = this.isSelected(item) ? 'unselect' : 'select';
25322 _t[m](item, true, false);
25325 if(this.multiSelect || this.singleSelect){
25326 if(this.multiSelect && e.shiftKey && this.lastSelection){
25327 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25329 this.select(item, this.multiSelect && e.ctrlKey);
25330 this.lastSelection = item;
25333 if(!this.tickable){
25334 e.preventDefault();
25342 * Get the number of selected nodes.
25345 getSelectionCount : function(){
25346 return this.selections.length;
25350 * Get the currently selected nodes.
25351 * @return {Array} An array of HTMLElements
25353 getSelectedNodes : function(){
25354 return this.selections;
25358 * Get the indexes of the selected nodes.
25361 getSelectedIndexes : function(){
25362 var indexes = [], s = this.selections;
25363 for(var i = 0, len = s.length; i < len; i++){
25364 indexes.push(s[i].nodeIndex);
25370 * Clear all selections
25371 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25373 clearSelections : function(suppressEvent){
25374 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25375 this.cmp.elements = this.selections;
25376 this.cmp.removeClass(this.selectedClass);
25377 this.selections = [];
25378 if(!suppressEvent){
25379 this.fireEvent("selectionchange", this, this.selections);
25385 * Returns true if the passed node is selected
25386 * @param {HTMLElement/Number} node The node or node index
25387 * @return {Boolean}
25389 isSelected : function(node){
25390 var s = this.selections;
25394 node = this.getNode(node);
25395 return s.indexOf(node) !== -1;
25400 * @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
25401 * @param {Boolean} keepExisting (optional) true to keep existing selections
25402 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25404 select : function(nodeInfo, keepExisting, suppressEvent){
25405 if(nodeInfo instanceof Array){
25407 this.clearSelections(true);
25409 for(var i = 0, len = nodeInfo.length; i < len; i++){
25410 this.select(nodeInfo[i], true, true);
25414 var node = this.getNode(nodeInfo);
25415 if(!node || this.isSelected(node)){
25416 return; // already selected.
25419 this.clearSelections(true);
25422 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25423 Roo.fly(node).addClass(this.selectedClass);
25424 this.selections.push(node);
25425 if(!suppressEvent){
25426 this.fireEvent("selectionchange", this, this.selections);
25434 * @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
25435 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25436 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25438 unselect : function(nodeInfo, keepExisting, suppressEvent)
25440 if(nodeInfo instanceof Array){
25441 Roo.each(this.selections, function(s) {
25442 this.unselect(s, nodeInfo);
25446 var node = this.getNode(nodeInfo);
25447 if(!node || !this.isSelected(node)){
25448 //Roo.log("not selected");
25449 return; // not selected.
25453 Roo.each(this.selections, function(s) {
25455 Roo.fly(node).removeClass(this.selectedClass);
25462 this.selections= ns;
25463 this.fireEvent("selectionchange", this, this.selections);
25467 * Gets a template node.
25468 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25469 * @return {HTMLElement} The node or null if it wasn't found
25471 getNode : function(nodeInfo){
25472 if(typeof nodeInfo == "string"){
25473 return document.getElementById(nodeInfo);
25474 }else if(typeof nodeInfo == "number"){
25475 return this.nodes[nodeInfo];
25481 * Gets a range template nodes.
25482 * @param {Number} startIndex
25483 * @param {Number} endIndex
25484 * @return {Array} An array of nodes
25486 getNodes : function(start, end){
25487 var ns = this.nodes;
25488 start = start || 0;
25489 end = typeof end == "undefined" ? ns.length - 1 : end;
25492 for(var i = start; i <= end; i++){
25496 for(var i = start; i >= end; i--){
25504 * Finds the index of the passed node
25505 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25506 * @return {Number} The index of the node or -1
25508 indexOf : function(node){
25509 node = this.getNode(node);
25510 if(typeof node.nodeIndex == "number"){
25511 return node.nodeIndex;
25513 var ns = this.nodes;
25514 for(var i = 0, len = ns.length; i < len; i++){
25524 * Ext JS Library 1.1.1
25525 * Copyright(c) 2006-2007, Ext JS, LLC.
25527 * Originally Released Under LGPL - original licence link has changed is not relivant.
25530 * <script type="text/javascript">
25534 * @class Roo.JsonView
25535 * @extends Roo.View
25536 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25538 var view = new Roo.JsonView({
25539 container: "my-element",
25540 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25545 // listen for node click?
25546 view.on("click", function(vw, index, node, e){
25547 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25550 // direct load of JSON data
25551 view.load("foobar.php");
25553 // Example from my blog list
25554 var tpl = new Roo.Template(
25555 '<div class="entry">' +
25556 '<a class="entry-title" href="{link}">{title}</a>' +
25557 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25558 "</div><hr />"
25561 var moreView = new Roo.JsonView({
25562 container : "entry-list",
25566 moreView.on("beforerender", this.sortEntries, this);
25568 url: "/blog/get-posts.php",
25569 params: "allposts=true",
25570 text: "Loading Blog Entries..."
25574 * Note: old code is supported with arguments : (container, template, config)
25578 * Create a new JsonView
25580 * @param {Object} config The config object
25583 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25586 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25588 var um = this.el.getUpdateManager();
25589 um.setRenderer(this);
25590 um.on("update", this.onLoad, this);
25591 um.on("failure", this.onLoadException, this);
25594 * @event beforerender
25595 * Fires before rendering of the downloaded JSON data.
25596 * @param {Roo.JsonView} this
25597 * @param {Object} data The JSON data loaded
25601 * Fires when data is loaded.
25602 * @param {Roo.JsonView} this
25603 * @param {Object} data The JSON data loaded
25604 * @param {Object} response The raw Connect response object
25607 * @event loadexception
25608 * Fires when loading fails.
25609 * @param {Roo.JsonView} this
25610 * @param {Object} response The raw Connect response object
25613 'beforerender' : true,
25615 'loadexception' : true
25618 Roo.extend(Roo.JsonView, Roo.View, {
25620 * @type {String} The root property in the loaded JSON object that contains the data
25625 * Refreshes the view.
25627 refresh : function(){
25628 this.clearSelections();
25629 this.el.update("");
25631 var o = this.jsonData;
25632 if(o && o.length > 0){
25633 for(var i = 0, len = o.length; i < len; i++){
25634 var data = this.prepareData(o[i], i, o);
25635 html[html.length] = this.tpl.apply(data);
25638 html.push(this.emptyText);
25640 this.el.update(html.join(""));
25641 this.nodes = this.el.dom.childNodes;
25642 this.updateIndexes(0);
25646 * 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.
25647 * @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:
25650 url: "your-url.php",
25651 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25652 callback: yourFunction,
25653 scope: yourObject, //(optional scope)
25656 text: "Loading...",
25661 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25662 * 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.
25663 * @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}
25664 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25665 * @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.
25668 var um = this.el.getUpdateManager();
25669 um.update.apply(um, arguments);
25672 render : function(el, response){
25673 this.clearSelections();
25674 this.el.update("");
25677 o = Roo.util.JSON.decode(response.responseText);
25680 o = o[this.jsonRoot];
25685 * The current JSON data or null
25688 this.beforeRender();
25693 * Get the number of records in the current JSON dataset
25696 getCount : function(){
25697 return this.jsonData ? this.jsonData.length : 0;
25701 * Returns the JSON object for the specified node(s)
25702 * @param {HTMLElement/Array} node The node or an array of nodes
25703 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25704 * you get the JSON object for the node
25706 getNodeData : function(node){
25707 if(node instanceof Array){
25709 for(var i = 0, len = node.length; i < len; i++){
25710 data.push(this.getNodeData(node[i]));
25714 return this.jsonData[this.indexOf(node)] || null;
25717 beforeRender : function(){
25718 this.snapshot = this.jsonData;
25720 this.sort.apply(this, this.sortInfo);
25722 this.fireEvent("beforerender", this, this.jsonData);
25725 onLoad : function(el, o){
25726 this.fireEvent("load", this, this.jsonData, o);
25729 onLoadException : function(el, o){
25730 this.fireEvent("loadexception", this, o);
25734 * Filter the data by a specific property.
25735 * @param {String} property A property on your JSON objects
25736 * @param {String/RegExp} value Either string that the property values
25737 * should start with, or a RegExp to test against the property
25739 filter : function(property, value){
25742 var ss = this.snapshot;
25743 if(typeof value == "string"){
25744 var vlen = value.length;
25746 this.clearFilter();
25749 value = value.toLowerCase();
25750 for(var i = 0, len = ss.length; i < len; i++){
25752 if(o[property].substr(0, vlen).toLowerCase() == value){
25756 } else if(value.exec){ // regex?
25757 for(var i = 0, len = ss.length; i < len; i++){
25759 if(value.test(o[property])){
25766 this.jsonData = data;
25772 * Filter by a function. The passed function will be called with each
25773 * object in the current dataset. If the function returns true the value is kept,
25774 * otherwise it is filtered.
25775 * @param {Function} fn
25776 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25778 filterBy : function(fn, scope){
25781 var ss = this.snapshot;
25782 for(var i = 0, len = ss.length; i < len; i++){
25784 if(fn.call(scope || this, o)){
25788 this.jsonData = data;
25794 * Clears the current filter.
25796 clearFilter : function(){
25797 if(this.snapshot && this.jsonData != this.snapshot){
25798 this.jsonData = this.snapshot;
25805 * Sorts the data for this view and refreshes it.
25806 * @param {String} property A property on your JSON objects to sort on
25807 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25808 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25810 sort : function(property, dir, sortType){
25811 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25814 var dsc = dir && dir.toLowerCase() == "desc";
25815 var f = function(o1, o2){
25816 var v1 = sortType ? sortType(o1[p]) : o1[p];
25817 var v2 = sortType ? sortType(o2[p]) : o2[p];
25820 return dsc ? +1 : -1;
25821 } else if(v1 > v2){
25822 return dsc ? -1 : +1;
25827 this.jsonData.sort(f);
25829 if(this.jsonData != this.snapshot){
25830 this.snapshot.sort(f);
25836 * Ext JS Library 1.1.1
25837 * Copyright(c) 2006-2007, Ext JS, LLC.
25839 * Originally Released Under LGPL - original licence link has changed is not relivant.
25842 * <script type="text/javascript">
25847 * @class Roo.ColorPalette
25848 * @extends Roo.Component
25849 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25850 * Here's an example of typical usage:
25852 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25853 cp.render('my-div');
25855 cp.on('select', function(palette, selColor){
25856 // do something with selColor
25860 * Create a new ColorPalette
25861 * @param {Object} config The config object
25863 Roo.ColorPalette = function(config){
25864 Roo.ColorPalette.superclass.constructor.call(this, config);
25868 * Fires when a color is selected
25869 * @param {ColorPalette} this
25870 * @param {String} color The 6-digit color hex code (without the # symbol)
25876 this.on("select", this.handler, this.scope, true);
25879 Roo.extend(Roo.ColorPalette, Roo.Component, {
25881 * @cfg {String} itemCls
25882 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25884 itemCls : "x-color-palette",
25886 * @cfg {String} value
25887 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25888 * the hex codes are case-sensitive.
25891 clickEvent:'click',
25893 ctype: "Roo.ColorPalette",
25896 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25898 allowReselect : false,
25901 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25902 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25903 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25904 * of colors with the width setting until the box is symmetrical.</p>
25905 * <p>You can override individual colors if needed:</p>
25907 var cp = new Roo.ColorPalette();
25908 cp.colors[0] = "FF0000"; // change the first box to red
25911 Or you can provide a custom array of your own for complete control:
25913 var cp = new Roo.ColorPalette();
25914 cp.colors = ["000000", "993300", "333300"];
25919 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25920 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25921 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25922 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25923 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25927 onRender : function(container, position){
25928 var t = new Roo.MasterTemplate(
25929 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25931 var c = this.colors;
25932 for(var i = 0, len = c.length; i < len; i++){
25935 var el = document.createElement("div");
25936 el.className = this.itemCls;
25938 container.dom.insertBefore(el, position);
25939 this.el = Roo.get(el);
25940 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25941 if(this.clickEvent != 'click'){
25942 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25947 afterRender : function(){
25948 Roo.ColorPalette.superclass.afterRender.call(this);
25950 var s = this.value;
25957 handleClick : function(e, t){
25958 e.preventDefault();
25959 if(!this.disabled){
25960 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25961 this.select(c.toUpperCase());
25966 * Selects the specified color in the palette (fires the select event)
25967 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25969 select : function(color){
25970 color = color.replace("#", "");
25971 if(color != this.value || this.allowReselect){
25974 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25976 el.child("a.color-"+color).addClass("x-color-palette-sel");
25977 this.value = color;
25978 this.fireEvent("select", this, color);
25983 * Ext JS Library 1.1.1
25984 * Copyright(c) 2006-2007, Ext JS, LLC.
25986 * Originally Released Under LGPL - original licence link has changed is not relivant.
25989 * <script type="text/javascript">
25993 * @class Roo.DatePicker
25994 * @extends Roo.Component
25995 * Simple date picker class.
25997 * Create a new DatePicker
25998 * @param {Object} config The config object
26000 Roo.DatePicker = function(config){
26001 Roo.DatePicker.superclass.constructor.call(this, config);
26003 this.value = config && config.value ?
26004 config.value.clearTime() : new Date().clearTime();
26009 * Fires when a date is selected
26010 * @param {DatePicker} this
26011 * @param {Date} date The selected date
26015 * @event monthchange
26016 * Fires when the displayed month changes
26017 * @param {DatePicker} this
26018 * @param {Date} date The selected month
26020 'monthchange': true
26024 this.on("select", this.handler, this.scope || this);
26026 // build the disabledDatesRE
26027 if(!this.disabledDatesRE && this.disabledDates){
26028 var dd = this.disabledDates;
26030 for(var i = 0; i < dd.length; i++){
26032 if(i != dd.length-1) re += "|";
26034 this.disabledDatesRE = new RegExp(re + ")");
26038 Roo.extend(Roo.DatePicker, Roo.Component, {
26040 * @cfg {String} todayText
26041 * The text to display on the button that selects the current date (defaults to "Today")
26043 todayText : "Today",
26045 * @cfg {String} okText
26046 * The text to display on the ok button
26048 okText : " OK ", //   to give the user extra clicking room
26050 * @cfg {String} cancelText
26051 * The text to display on the cancel button
26053 cancelText : "Cancel",
26055 * @cfg {String} todayTip
26056 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26058 todayTip : "{0} (Spacebar)",
26060 * @cfg {Date} minDate
26061 * Minimum allowable date (JavaScript date object, defaults to null)
26065 * @cfg {Date} maxDate
26066 * Maximum allowable date (JavaScript date object, defaults to null)
26070 * @cfg {String} minText
26071 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26073 minText : "This date is before the minimum date",
26075 * @cfg {String} maxText
26076 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26078 maxText : "This date is after the maximum date",
26080 * @cfg {String} format
26081 * The default date format string which can be overriden for localization support. The format must be
26082 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26086 * @cfg {Array} disabledDays
26087 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26089 disabledDays : null,
26091 * @cfg {String} disabledDaysText
26092 * The tooltip to display when the date falls on a disabled day (defaults to "")
26094 disabledDaysText : "",
26096 * @cfg {RegExp} disabledDatesRE
26097 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26099 disabledDatesRE : null,
26101 * @cfg {String} disabledDatesText
26102 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26104 disabledDatesText : "",
26106 * @cfg {Boolean} constrainToViewport
26107 * True to constrain the date picker to the viewport (defaults to true)
26109 constrainToViewport : true,
26111 * @cfg {Array} monthNames
26112 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26114 monthNames : Date.monthNames,
26116 * @cfg {Array} dayNames
26117 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26119 dayNames : Date.dayNames,
26121 * @cfg {String} nextText
26122 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26124 nextText: 'Next Month (Control+Right)',
26126 * @cfg {String} prevText
26127 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26129 prevText: 'Previous Month (Control+Left)',
26131 * @cfg {String} monthYearText
26132 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26134 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26136 * @cfg {Number} startDay
26137 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26141 * @cfg {Bool} showClear
26142 * Show a clear button (usefull for date form elements that can be blank.)
26148 * Sets the value of the date field
26149 * @param {Date} value The date to set
26151 setValue : function(value){
26152 var old = this.value;
26154 if (typeof(value) == 'string') {
26156 value = Date.parseDate(value, this.format);
26159 value = new Date();
26162 this.value = value.clearTime(true);
26164 this.update(this.value);
26169 * Gets the current selected value of the date field
26170 * @return {Date} The selected date
26172 getValue : function(){
26177 focus : function(){
26179 this.update(this.activeDate);
26184 onRender : function(container, position){
26187 '<table cellspacing="0">',
26188 '<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>',
26189 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26190 var dn = this.dayNames;
26191 for(var i = 0; i < 7; i++){
26192 var d = this.startDay+i;
26196 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26198 m[m.length] = "</tr></thead><tbody><tr>";
26199 for(var i = 0; i < 42; i++) {
26200 if(i % 7 == 0 && i != 0){
26201 m[m.length] = "</tr><tr>";
26203 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26205 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26206 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26208 var el = document.createElement("div");
26209 el.className = "x-date-picker";
26210 el.innerHTML = m.join("");
26212 container.dom.insertBefore(el, position);
26214 this.el = Roo.get(el);
26215 this.eventEl = Roo.get(el.firstChild);
26217 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26218 handler: this.showPrevMonth,
26220 preventDefault:true,
26224 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26225 handler: this.showNextMonth,
26227 preventDefault:true,
26231 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26233 this.monthPicker = this.el.down('div.x-date-mp');
26234 this.monthPicker.enableDisplayMode('block');
26236 var kn = new Roo.KeyNav(this.eventEl, {
26237 "left" : function(e){
26239 this.showPrevMonth() :
26240 this.update(this.activeDate.add("d", -1));
26243 "right" : function(e){
26245 this.showNextMonth() :
26246 this.update(this.activeDate.add("d", 1));
26249 "up" : function(e){
26251 this.showNextYear() :
26252 this.update(this.activeDate.add("d", -7));
26255 "down" : function(e){
26257 this.showPrevYear() :
26258 this.update(this.activeDate.add("d", 7));
26261 "pageUp" : function(e){
26262 this.showNextMonth();
26265 "pageDown" : function(e){
26266 this.showPrevMonth();
26269 "enter" : function(e){
26270 e.stopPropagation();
26277 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26279 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26281 this.el.unselectable();
26283 this.cells = this.el.select("table.x-date-inner tbody td");
26284 this.textNodes = this.el.query("table.x-date-inner tbody span");
26286 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26288 tooltip: this.monthYearText
26291 this.mbtn.on('click', this.showMonthPicker, this);
26292 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26295 var today = (new Date()).dateFormat(this.format);
26297 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26298 if (this.showClear) {
26299 baseTb.add( new Roo.Toolbar.Fill());
26302 text: String.format(this.todayText, today),
26303 tooltip: String.format(this.todayTip, today),
26304 handler: this.selectToday,
26308 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26311 if (this.showClear) {
26313 baseTb.add( new Roo.Toolbar.Fill());
26316 cls: 'x-btn-icon x-btn-clear',
26317 handler: function() {
26319 this.fireEvent("select", this, '');
26329 this.update(this.value);
26332 createMonthPicker : function(){
26333 if(!this.monthPicker.dom.firstChild){
26334 var buf = ['<table border="0" cellspacing="0">'];
26335 for(var i = 0; i < 6; i++){
26337 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26338 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26340 '<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>' :
26341 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26345 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26347 '</button><button type="button" class="x-date-mp-cancel">',
26349 '</button></td></tr>',
26352 this.monthPicker.update(buf.join(''));
26353 this.monthPicker.on('click', this.onMonthClick, this);
26354 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26356 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26357 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26359 this.mpMonths.each(function(m, a, i){
26362 m.dom.xmonth = 5 + Math.round(i * .5);
26364 m.dom.xmonth = Math.round((i-1) * .5);
26370 showMonthPicker : function(){
26371 this.createMonthPicker();
26372 var size = this.el.getSize();
26373 this.monthPicker.setSize(size);
26374 this.monthPicker.child('table').setSize(size);
26376 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26377 this.updateMPMonth(this.mpSelMonth);
26378 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26379 this.updateMPYear(this.mpSelYear);
26381 this.monthPicker.slideIn('t', {duration:.2});
26384 updateMPYear : function(y){
26386 var ys = this.mpYears.elements;
26387 for(var i = 1; i <= 10; i++){
26388 var td = ys[i-1], y2;
26390 y2 = y + Math.round(i * .5);
26391 td.firstChild.innerHTML = y2;
26394 y2 = y - (5-Math.round(i * .5));
26395 td.firstChild.innerHTML = y2;
26398 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26402 updateMPMonth : function(sm){
26403 this.mpMonths.each(function(m, a, i){
26404 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26408 selectMPMonth: function(m){
26412 onMonthClick : function(e, t){
26414 var el = new Roo.Element(t), pn;
26415 if(el.is('button.x-date-mp-cancel')){
26416 this.hideMonthPicker();
26418 else if(el.is('button.x-date-mp-ok')){
26419 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26420 this.hideMonthPicker();
26422 else if(pn = el.up('td.x-date-mp-month', 2)){
26423 this.mpMonths.removeClass('x-date-mp-sel');
26424 pn.addClass('x-date-mp-sel');
26425 this.mpSelMonth = pn.dom.xmonth;
26427 else if(pn = el.up('td.x-date-mp-year', 2)){
26428 this.mpYears.removeClass('x-date-mp-sel');
26429 pn.addClass('x-date-mp-sel');
26430 this.mpSelYear = pn.dom.xyear;
26432 else if(el.is('a.x-date-mp-prev')){
26433 this.updateMPYear(this.mpyear-10);
26435 else if(el.is('a.x-date-mp-next')){
26436 this.updateMPYear(this.mpyear+10);
26440 onMonthDblClick : function(e, t){
26442 var el = new Roo.Element(t), pn;
26443 if(pn = el.up('td.x-date-mp-month', 2)){
26444 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26445 this.hideMonthPicker();
26447 else if(pn = el.up('td.x-date-mp-year', 2)){
26448 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26449 this.hideMonthPicker();
26453 hideMonthPicker : function(disableAnim){
26454 if(this.monthPicker){
26455 if(disableAnim === true){
26456 this.monthPicker.hide();
26458 this.monthPicker.slideOut('t', {duration:.2});
26464 showPrevMonth : function(e){
26465 this.update(this.activeDate.add("mo", -1));
26469 showNextMonth : function(e){
26470 this.update(this.activeDate.add("mo", 1));
26474 showPrevYear : function(){
26475 this.update(this.activeDate.add("y", -1));
26479 showNextYear : function(){
26480 this.update(this.activeDate.add("y", 1));
26484 handleMouseWheel : function(e){
26485 var delta = e.getWheelDelta();
26487 this.showPrevMonth();
26489 } else if(delta < 0){
26490 this.showNextMonth();
26496 handleDateClick : function(e, t){
26498 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26499 this.setValue(new Date(t.dateValue));
26500 this.fireEvent("select", this, this.value);
26505 selectToday : function(){
26506 this.setValue(new Date().clearTime());
26507 this.fireEvent("select", this, this.value);
26511 update : function(date)
26513 var vd = this.activeDate;
26514 this.activeDate = date;
26516 var t = date.getTime();
26517 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26518 this.cells.removeClass("x-date-selected");
26519 this.cells.each(function(c){
26520 if(c.dom.firstChild.dateValue == t){
26521 c.addClass("x-date-selected");
26522 setTimeout(function(){
26523 try{c.dom.firstChild.focus();}catch(e){}
26532 var days = date.getDaysInMonth();
26533 var firstOfMonth = date.getFirstDateOfMonth();
26534 var startingPos = firstOfMonth.getDay()-this.startDay;
26536 if(startingPos <= this.startDay){
26540 var pm = date.add("mo", -1);
26541 var prevStart = pm.getDaysInMonth()-startingPos;
26543 var cells = this.cells.elements;
26544 var textEls = this.textNodes;
26545 days += startingPos;
26547 // convert everything to numbers so it's fast
26548 var day = 86400000;
26549 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26550 var today = new Date().clearTime().getTime();
26551 var sel = date.clearTime().getTime();
26552 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26553 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26554 var ddMatch = this.disabledDatesRE;
26555 var ddText = this.disabledDatesText;
26556 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26557 var ddaysText = this.disabledDaysText;
26558 var format = this.format;
26560 var setCellClass = function(cal, cell){
26562 var t = d.getTime();
26563 cell.firstChild.dateValue = t;
26565 cell.className += " x-date-today";
26566 cell.title = cal.todayText;
26569 cell.className += " x-date-selected";
26570 setTimeout(function(){
26571 try{cell.firstChild.focus();}catch(e){}
26576 cell.className = " x-date-disabled";
26577 cell.title = cal.minText;
26581 cell.className = " x-date-disabled";
26582 cell.title = cal.maxText;
26586 if(ddays.indexOf(d.getDay()) != -1){
26587 cell.title = ddaysText;
26588 cell.className = " x-date-disabled";
26591 if(ddMatch && format){
26592 var fvalue = d.dateFormat(format);
26593 if(ddMatch.test(fvalue)){
26594 cell.title = ddText.replace("%0", fvalue);
26595 cell.className = " x-date-disabled";
26601 for(; i < startingPos; i++) {
26602 textEls[i].innerHTML = (++prevStart);
26603 d.setDate(d.getDate()+1);
26604 cells[i].className = "x-date-prevday";
26605 setCellClass(this, cells[i]);
26607 for(; i < days; i++){
26608 intDay = i - startingPos + 1;
26609 textEls[i].innerHTML = (intDay);
26610 d.setDate(d.getDate()+1);
26611 cells[i].className = "x-date-active";
26612 setCellClass(this, cells[i]);
26615 for(; i < 42; i++) {
26616 textEls[i].innerHTML = (++extraDays);
26617 d.setDate(d.getDate()+1);
26618 cells[i].className = "x-date-nextday";
26619 setCellClass(this, cells[i]);
26622 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26623 this.fireEvent('monthchange', this, date);
26625 if(!this.internalRender){
26626 var main = this.el.dom.firstChild;
26627 var w = main.offsetWidth;
26628 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26629 Roo.fly(main).setWidth(w);
26630 this.internalRender = true;
26631 // opera does not respect the auto grow header center column
26632 // then, after it gets a width opera refuses to recalculate
26633 // without a second pass
26634 if(Roo.isOpera && !this.secondPass){
26635 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26636 this.secondPass = true;
26637 this.update.defer(10, this, [date]);
26645 * Ext JS Library 1.1.1
26646 * Copyright(c) 2006-2007, Ext JS, LLC.
26648 * Originally Released Under LGPL - original licence link has changed is not relivant.
26651 * <script type="text/javascript">
26654 * @class Roo.TabPanel
26655 * @extends Roo.util.Observable
26656 * A lightweight tab container.
26660 // basic tabs 1, built from existing content
26661 var tabs = new Roo.TabPanel("tabs1");
26662 tabs.addTab("script", "View Script");
26663 tabs.addTab("markup", "View Markup");
26664 tabs.activate("script");
26666 // more advanced tabs, built from javascript
26667 var jtabs = new Roo.TabPanel("jtabs");
26668 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26670 // set up the UpdateManager
26671 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26672 var updater = tab2.getUpdateManager();
26673 updater.setDefaultUrl("ajax1.htm");
26674 tab2.on('activate', updater.refresh, updater, true);
26676 // Use setUrl for Ajax loading
26677 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26678 tab3.setUrl("ajax2.htm", null, true);
26681 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26684 jtabs.activate("jtabs-1");
26687 * Create a new TabPanel.
26688 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26689 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26691 Roo.TabPanel = function(container, config){
26693 * The container element for this TabPanel.
26694 * @type Roo.Element
26696 this.el = Roo.get(container, true);
26698 if(typeof config == "boolean"){
26699 this.tabPosition = config ? "bottom" : "top";
26701 Roo.apply(this, config);
26704 if(this.tabPosition == "bottom"){
26705 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26706 this.el.addClass("x-tabs-bottom");
26708 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26709 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26710 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26712 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26714 if(this.tabPosition != "bottom"){
26715 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26716 * @type Roo.Element
26718 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26719 this.el.addClass("x-tabs-top");
26723 this.bodyEl.setStyle("position", "relative");
26725 this.active = null;
26726 this.activateDelegate = this.activate.createDelegate(this);
26731 * Fires when the active tab changes
26732 * @param {Roo.TabPanel} this
26733 * @param {Roo.TabPanelItem} activePanel The new active tab
26737 * @event beforetabchange
26738 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26739 * @param {Roo.TabPanel} this
26740 * @param {Object} e Set cancel to true on this object to cancel the tab change
26741 * @param {Roo.TabPanelItem} tab The tab being changed to
26743 "beforetabchange" : true
26746 Roo.EventManager.onWindowResize(this.onResize, this);
26747 this.cpad = this.el.getPadding("lr");
26748 this.hiddenCount = 0;
26751 // toolbar on the tabbar support...
26752 if (this.toolbar) {
26753 var tcfg = this.toolbar;
26754 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26755 this.toolbar = new Roo.Toolbar(tcfg);
26756 if (Roo.isSafari) {
26757 var tbl = tcfg.container.child('table', true);
26758 tbl.setAttribute('width', '100%');
26765 Roo.TabPanel.superclass.constructor.call(this);
26768 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26770 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26772 tabPosition : "top",
26774 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26776 currentTabWidth : 0,
26778 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26782 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26786 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26788 preferredTabWidth : 175,
26790 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26792 resizeTabs : false,
26794 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26796 monitorResize : true,
26798 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26803 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26804 * @param {String} id The id of the div to use <b>or create</b>
26805 * @param {String} text The text for the tab
26806 * @param {String} content (optional) Content to put in the TabPanelItem body
26807 * @param {Boolean} closable (optional) True to create a close icon on the tab
26808 * @return {Roo.TabPanelItem} The created TabPanelItem
26810 addTab : function(id, text, content, closable){
26811 var item = new Roo.TabPanelItem(this, id, text, closable);
26812 this.addTabItem(item);
26814 item.setContent(content);
26820 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26821 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26822 * @return {Roo.TabPanelItem}
26824 getTab : function(id){
26825 return this.items[id];
26829 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26830 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26832 hideTab : function(id){
26833 var t = this.items[id];
26836 this.hiddenCount++;
26837 this.autoSizeTabs();
26842 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26843 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26845 unhideTab : function(id){
26846 var t = this.items[id];
26848 t.setHidden(false);
26849 this.hiddenCount--;
26850 this.autoSizeTabs();
26855 * Adds an existing {@link Roo.TabPanelItem}.
26856 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26858 addTabItem : function(item){
26859 this.items[item.id] = item;
26860 this.items.push(item);
26861 if(this.resizeTabs){
26862 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26863 this.autoSizeTabs();
26870 * Removes a {@link Roo.TabPanelItem}.
26871 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26873 removeTab : function(id){
26874 var items = this.items;
26875 var tab = items[id];
26876 if(!tab) { return; }
26877 var index = items.indexOf(tab);
26878 if(this.active == tab && items.length > 1){
26879 var newTab = this.getNextAvailable(index);
26884 this.stripEl.dom.removeChild(tab.pnode.dom);
26885 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26886 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26888 items.splice(index, 1);
26889 delete this.items[tab.id];
26890 tab.fireEvent("close", tab);
26891 tab.purgeListeners();
26892 this.autoSizeTabs();
26895 getNextAvailable : function(start){
26896 var items = this.items;
26898 // look for a next tab that will slide over to
26899 // replace the one being removed
26900 while(index < items.length){
26901 var item = items[++index];
26902 if(item && !item.isHidden()){
26906 // if one isn't found select the previous tab (on the left)
26909 var item = items[--index];
26910 if(item && !item.isHidden()){
26918 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26919 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26921 disableTab : function(id){
26922 var tab = this.items[id];
26923 if(tab && this.active != tab){
26929 * Enables a {@link Roo.TabPanelItem} that is disabled.
26930 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26932 enableTab : function(id){
26933 var tab = this.items[id];
26938 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26939 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26940 * @return {Roo.TabPanelItem} The TabPanelItem.
26942 activate : function(id){
26943 var tab = this.items[id];
26947 if(tab == this.active || tab.disabled){
26951 this.fireEvent("beforetabchange", this, e, tab);
26952 if(e.cancel !== true && !tab.disabled){
26954 this.active.hide();
26956 this.active = this.items[id];
26957 this.active.show();
26958 this.fireEvent("tabchange", this, this.active);
26964 * Gets the active {@link Roo.TabPanelItem}.
26965 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26967 getActiveTab : function(){
26968 return this.active;
26972 * Updates the tab body element to fit the height of the container element
26973 * for overflow scrolling
26974 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26976 syncHeight : function(targetHeight){
26977 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26978 var bm = this.bodyEl.getMargins();
26979 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26980 this.bodyEl.setHeight(newHeight);
26984 onResize : function(){
26985 if(this.monitorResize){
26986 this.autoSizeTabs();
26991 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26993 beginUpdate : function(){
26994 this.updating = true;
26998 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27000 endUpdate : function(){
27001 this.updating = false;
27002 this.autoSizeTabs();
27006 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27008 autoSizeTabs : function(){
27009 var count = this.items.length;
27010 var vcount = count - this.hiddenCount;
27011 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
27012 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27013 var availWidth = Math.floor(w / vcount);
27014 var b = this.stripBody;
27015 if(b.getWidth() > w){
27016 var tabs = this.items;
27017 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27018 if(availWidth < this.minTabWidth){
27019 /*if(!this.sleft){ // incomplete scrolling code
27020 this.createScrollButtons();
27023 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27026 if(this.currentTabWidth < this.preferredTabWidth){
27027 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27033 * Returns the number of tabs in this TabPanel.
27036 getCount : function(){
27037 return this.items.length;
27041 * Resizes all the tabs to the passed width
27042 * @param {Number} The new width
27044 setTabWidth : function(width){
27045 this.currentTabWidth = width;
27046 for(var i = 0, len = this.items.length; i < len; i++) {
27047 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27052 * Destroys this TabPanel
27053 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27055 destroy : function(removeEl){
27056 Roo.EventManager.removeResizeListener(this.onResize, this);
27057 for(var i = 0, len = this.items.length; i < len; i++){
27058 this.items[i].purgeListeners();
27060 if(removeEl === true){
27061 this.el.update("");
27068 * @class Roo.TabPanelItem
27069 * @extends Roo.util.Observable
27070 * Represents an individual item (tab plus body) in a TabPanel.
27071 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27072 * @param {String} id The id of this TabPanelItem
27073 * @param {String} text The text for the tab of this TabPanelItem
27074 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27076 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27078 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27079 * @type Roo.TabPanel
27081 this.tabPanel = tabPanel;
27083 * The id for this TabPanelItem
27088 this.disabled = false;
27092 this.loaded = false;
27093 this.closable = closable;
27096 * The body element for this TabPanelItem.
27097 * @type Roo.Element
27099 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27100 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27101 this.bodyEl.setStyle("display", "block");
27102 this.bodyEl.setStyle("zoom", "1");
27105 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27107 this.el = Roo.get(els.el, true);
27108 this.inner = Roo.get(els.inner, true);
27109 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27110 this.pnode = Roo.get(els.el.parentNode, true);
27111 this.el.on("mousedown", this.onTabMouseDown, this);
27112 this.el.on("click", this.onTabClick, this);
27115 var c = Roo.get(els.close, true);
27116 c.dom.title = this.closeText;
27117 c.addClassOnOver("close-over");
27118 c.on("click", this.closeClick, this);
27124 * Fires when this tab becomes the active tab.
27125 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27126 * @param {Roo.TabPanelItem} this
27130 * @event beforeclose
27131 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27132 * @param {Roo.TabPanelItem} this
27133 * @param {Object} e Set cancel to true on this object to cancel the close.
27135 "beforeclose": true,
27138 * Fires when this tab is closed.
27139 * @param {Roo.TabPanelItem} this
27143 * @event deactivate
27144 * Fires when this tab is no longer the active tab.
27145 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27146 * @param {Roo.TabPanelItem} this
27148 "deactivate" : true
27150 this.hidden = false;
27152 Roo.TabPanelItem.superclass.constructor.call(this);
27155 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27156 purgeListeners : function(){
27157 Roo.util.Observable.prototype.purgeListeners.call(this);
27158 this.el.removeAllListeners();
27161 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27164 this.pnode.addClass("on");
27167 this.tabPanel.stripWrap.repaint();
27169 this.fireEvent("activate", this.tabPanel, this);
27173 * Returns true if this tab is the active tab.
27174 * @return {Boolean}
27176 isActive : function(){
27177 return this.tabPanel.getActiveTab() == this;
27181 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27184 this.pnode.removeClass("on");
27186 this.fireEvent("deactivate", this.tabPanel, this);
27189 hideAction : function(){
27190 this.bodyEl.hide();
27191 this.bodyEl.setStyle("position", "absolute");
27192 this.bodyEl.setLeft("-20000px");
27193 this.bodyEl.setTop("-20000px");
27196 showAction : function(){
27197 this.bodyEl.setStyle("position", "relative");
27198 this.bodyEl.setTop("");
27199 this.bodyEl.setLeft("");
27200 this.bodyEl.show();
27204 * Set the tooltip for the tab.
27205 * @param {String} tooltip The tab's tooltip
27207 setTooltip : function(text){
27208 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27209 this.textEl.dom.qtip = text;
27210 this.textEl.dom.removeAttribute('title');
27212 this.textEl.dom.title = text;
27216 onTabClick : function(e){
27217 e.preventDefault();
27218 this.tabPanel.activate(this.id);
27221 onTabMouseDown : function(e){
27222 e.preventDefault();
27223 this.tabPanel.activate(this.id);
27226 getWidth : function(){
27227 return this.inner.getWidth();
27230 setWidth : function(width){
27231 var iwidth = width - this.pnode.getPadding("lr");
27232 this.inner.setWidth(iwidth);
27233 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27234 this.pnode.setWidth(width);
27238 * Show or hide the tab
27239 * @param {Boolean} hidden True to hide or false to show.
27241 setHidden : function(hidden){
27242 this.hidden = hidden;
27243 this.pnode.setStyle("display", hidden ? "none" : "");
27247 * Returns true if this tab is "hidden"
27248 * @return {Boolean}
27250 isHidden : function(){
27251 return this.hidden;
27255 * Returns the text for this tab
27258 getText : function(){
27262 autoSize : function(){
27263 //this.el.beginMeasure();
27264 this.textEl.setWidth(1);
27266 * #2804 [new] Tabs in Roojs
27267 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27269 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27270 //this.el.endMeasure();
27274 * Sets the text for the tab (Note: this also sets the tooltip text)
27275 * @param {String} text The tab's text and tooltip
27277 setText : function(text){
27279 this.textEl.update(text);
27280 this.setTooltip(text);
27281 if(!this.tabPanel.resizeTabs){
27286 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27288 activate : function(){
27289 this.tabPanel.activate(this.id);
27293 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27295 disable : function(){
27296 if(this.tabPanel.active != this){
27297 this.disabled = true;
27298 this.pnode.addClass("disabled");
27303 * Enables this TabPanelItem if it was previously disabled.
27305 enable : function(){
27306 this.disabled = false;
27307 this.pnode.removeClass("disabled");
27311 * Sets the content for this TabPanelItem.
27312 * @param {String} content The content
27313 * @param {Boolean} loadScripts true to look for and load scripts
27315 setContent : function(content, loadScripts){
27316 this.bodyEl.update(content, loadScripts);
27320 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27321 * @return {Roo.UpdateManager} The UpdateManager
27323 getUpdateManager : function(){
27324 return this.bodyEl.getUpdateManager();
27328 * Set a URL to be used to load the content for this TabPanelItem.
27329 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27330 * @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)
27331 * @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)
27332 * @return {Roo.UpdateManager} The UpdateManager
27334 setUrl : function(url, params, loadOnce){
27335 if(this.refreshDelegate){
27336 this.un('activate', this.refreshDelegate);
27338 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27339 this.on("activate", this.refreshDelegate);
27340 return this.bodyEl.getUpdateManager();
27344 _handleRefresh : function(url, params, loadOnce){
27345 if(!loadOnce || !this.loaded){
27346 var updater = this.bodyEl.getUpdateManager();
27347 updater.update(url, params, this._setLoaded.createDelegate(this));
27352 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27353 * Will fail silently if the setUrl method has not been called.
27354 * This does not activate the panel, just updates its content.
27356 refresh : function(){
27357 if(this.refreshDelegate){
27358 this.loaded = false;
27359 this.refreshDelegate();
27364 _setLoaded : function(){
27365 this.loaded = true;
27369 closeClick : function(e){
27372 this.fireEvent("beforeclose", this, o);
27373 if(o.cancel !== true){
27374 this.tabPanel.removeTab(this.id);
27378 * The text displayed in the tooltip for the close icon.
27381 closeText : "Close this tab"
27385 Roo.TabPanel.prototype.createStrip = function(container){
27386 var strip = document.createElement("div");
27387 strip.className = "x-tabs-wrap";
27388 container.appendChild(strip);
27392 Roo.TabPanel.prototype.createStripList = function(strip){
27393 // div wrapper for retard IE
27394 // returns the "tr" element.
27395 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27396 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27397 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27398 return strip.firstChild.firstChild.firstChild.firstChild;
27401 Roo.TabPanel.prototype.createBody = function(container){
27402 var body = document.createElement("div");
27403 Roo.id(body, "tab-body");
27404 Roo.fly(body).addClass("x-tabs-body");
27405 container.appendChild(body);
27409 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27410 var body = Roo.getDom(id);
27412 body = document.createElement("div");
27415 Roo.fly(body).addClass("x-tabs-item-body");
27416 bodyEl.insertBefore(body, bodyEl.firstChild);
27420 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27421 var td = document.createElement("td");
27422 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27423 //stripEl.appendChild(td);
27425 td.className = "x-tabs-closable";
27426 if(!this.closeTpl){
27427 this.closeTpl = new Roo.Template(
27428 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27429 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27430 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27433 var el = this.closeTpl.overwrite(td, {"text": text});
27434 var close = el.getElementsByTagName("div")[0];
27435 var inner = el.getElementsByTagName("em")[0];
27436 return {"el": el, "close": close, "inner": inner};
27439 this.tabTpl = new Roo.Template(
27440 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27441 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27444 var el = this.tabTpl.overwrite(td, {"text": text});
27445 var inner = el.getElementsByTagName("em")[0];
27446 return {"el": el, "inner": inner};
27450 * Ext JS Library 1.1.1
27451 * Copyright(c) 2006-2007, Ext JS, LLC.
27453 * Originally Released Under LGPL - original licence link has changed is not relivant.
27456 * <script type="text/javascript">
27460 * @class Roo.Button
27461 * @extends Roo.util.Observable
27462 * Simple Button class
27463 * @cfg {String} text The button text
27464 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27465 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27466 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27467 * @cfg {Object} scope The scope of the handler
27468 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27469 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27470 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27471 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27472 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27473 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27474 applies if enableToggle = true)
27475 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27476 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27477 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27479 * Create a new button
27480 * @param {Object} config The config object
27482 Roo.Button = function(renderTo, config)
27486 renderTo = config.renderTo || false;
27489 Roo.apply(this, config);
27493 * Fires when this button is clicked
27494 * @param {Button} this
27495 * @param {EventObject} e The click event
27500 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27501 * @param {Button} this
27502 * @param {Boolean} pressed
27507 * Fires when the mouse hovers over the button
27508 * @param {Button} this
27509 * @param {Event} e The event object
27511 'mouseover' : true,
27514 * Fires when the mouse exits the button
27515 * @param {Button} this
27516 * @param {Event} e The event object
27521 * Fires when the button is rendered
27522 * @param {Button} this
27527 this.menu = Roo.menu.MenuMgr.get(this.menu);
27529 // register listeners first!! - so render can be captured..
27530 Roo.util.Observable.call(this);
27532 this.render(renderTo);
27538 Roo.extend(Roo.Button, Roo.util.Observable, {
27544 * Read-only. True if this button is hidden
27549 * Read-only. True if this button is disabled
27554 * Read-only. True if this button is pressed (only if enableToggle = true)
27560 * @cfg {Number} tabIndex
27561 * The DOM tabIndex for this button (defaults to undefined)
27563 tabIndex : undefined,
27566 * @cfg {Boolean} enableToggle
27567 * True to enable pressed/not pressed toggling (defaults to false)
27569 enableToggle: false,
27571 * @cfg {Mixed} menu
27572 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27576 * @cfg {String} menuAlign
27577 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27579 menuAlign : "tl-bl?",
27582 * @cfg {String} iconCls
27583 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27585 iconCls : undefined,
27587 * @cfg {String} type
27588 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27593 menuClassTarget: 'tr',
27596 * @cfg {String} clickEvent
27597 * The type of event to map to the button's event handler (defaults to 'click')
27599 clickEvent : 'click',
27602 * @cfg {Boolean} handleMouseEvents
27603 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27605 handleMouseEvents : true,
27608 * @cfg {String} tooltipType
27609 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27611 tooltipType : 'qtip',
27614 * @cfg {String} cls
27615 * A CSS class to apply to the button's main element.
27619 * @cfg {Roo.Template} template (Optional)
27620 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27621 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27622 * require code modifications if required elements (e.g. a button) aren't present.
27626 render : function(renderTo){
27628 if(this.hideParent){
27629 this.parentEl = Roo.get(renderTo);
27631 if(!this.dhconfig){
27632 if(!this.template){
27633 if(!Roo.Button.buttonTemplate){
27634 // hideous table template
27635 Roo.Button.buttonTemplate = new Roo.Template(
27636 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27637 '<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>',
27638 "</tr></tbody></table>");
27640 this.template = Roo.Button.buttonTemplate;
27642 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27643 var btnEl = btn.child("button:first");
27644 btnEl.on('focus', this.onFocus, this);
27645 btnEl.on('blur', this.onBlur, this);
27647 btn.addClass(this.cls);
27650 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27653 btnEl.addClass(this.iconCls);
27655 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27658 if(this.tabIndex !== undefined){
27659 btnEl.dom.tabIndex = this.tabIndex;
27662 if(typeof this.tooltip == 'object'){
27663 Roo.QuickTips.tips(Roo.apply({
27667 btnEl.dom[this.tooltipType] = this.tooltip;
27671 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27675 this.el.dom.id = this.el.id = this.id;
27678 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27679 this.menu.on("show", this.onMenuShow, this);
27680 this.menu.on("hide", this.onMenuHide, this);
27682 btn.addClass("x-btn");
27683 if(Roo.isIE && !Roo.isIE7){
27684 this.autoWidth.defer(1, this);
27688 if(this.handleMouseEvents){
27689 btn.on("mouseover", this.onMouseOver, this);
27690 btn.on("mouseout", this.onMouseOut, this);
27691 btn.on("mousedown", this.onMouseDown, this);
27693 btn.on(this.clickEvent, this.onClick, this);
27694 //btn.on("mouseup", this.onMouseUp, this);
27701 Roo.ButtonToggleMgr.register(this);
27703 this.el.addClass("x-btn-pressed");
27706 var repeater = new Roo.util.ClickRepeater(btn,
27707 typeof this.repeat == "object" ? this.repeat : {}
27709 repeater.on("click", this.onClick, this);
27712 this.fireEvent('render', this);
27716 * Returns the button's underlying element
27717 * @return {Roo.Element} The element
27719 getEl : function(){
27724 * Destroys this Button and removes any listeners.
27726 destroy : function(){
27727 Roo.ButtonToggleMgr.unregister(this);
27728 this.el.removeAllListeners();
27729 this.purgeListeners();
27734 autoWidth : function(){
27736 this.el.setWidth("auto");
27737 if(Roo.isIE7 && Roo.isStrict){
27738 var ib = this.el.child('button');
27739 if(ib && ib.getWidth() > 20){
27741 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27746 this.el.beginMeasure();
27748 if(this.el.getWidth() < this.minWidth){
27749 this.el.setWidth(this.minWidth);
27752 this.el.endMeasure();
27759 * Assigns this button's click handler
27760 * @param {Function} handler The function to call when the button is clicked
27761 * @param {Object} scope (optional) Scope for the function passed in
27763 setHandler : function(handler, scope){
27764 this.handler = handler;
27765 this.scope = scope;
27769 * Sets this button's text
27770 * @param {String} text The button text
27772 setText : function(text){
27775 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27781 * Gets the text for this button
27782 * @return {String} The button text
27784 getText : function(){
27792 this.hidden = false;
27794 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27802 this.hidden = true;
27804 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27809 * Convenience function for boolean show/hide
27810 * @param {Boolean} visible True to show, false to hide
27812 setVisible: function(visible){
27821 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27822 * @param {Boolean} state (optional) Force a particular state
27824 toggle : function(state){
27825 state = state === undefined ? !this.pressed : state;
27826 if(state != this.pressed){
27828 this.el.addClass("x-btn-pressed");
27829 this.pressed = true;
27830 this.fireEvent("toggle", this, true);
27832 this.el.removeClass("x-btn-pressed");
27833 this.pressed = false;
27834 this.fireEvent("toggle", this, false);
27836 if(this.toggleHandler){
27837 this.toggleHandler.call(this.scope || this, this, state);
27845 focus : function(){
27846 this.el.child('button:first').focus();
27850 * Disable this button
27852 disable : function(){
27854 this.el.addClass("x-btn-disabled");
27856 this.disabled = true;
27860 * Enable this button
27862 enable : function(){
27864 this.el.removeClass("x-btn-disabled");
27866 this.disabled = false;
27870 * Convenience function for boolean enable/disable
27871 * @param {Boolean} enabled True to enable, false to disable
27873 setDisabled : function(v){
27874 this[v !== true ? "enable" : "disable"]();
27878 onClick : function(e)
27881 e.preventDefault();
27886 if(!this.disabled){
27887 if(this.enableToggle){
27890 if(this.menu && !this.menu.isVisible()){
27891 this.menu.show(this.el, this.menuAlign);
27893 this.fireEvent("click", this, e);
27895 this.el.removeClass("x-btn-over");
27896 this.handler.call(this.scope || this, this, e);
27901 onMouseOver : function(e){
27902 if(!this.disabled){
27903 this.el.addClass("x-btn-over");
27904 this.fireEvent('mouseover', this, e);
27908 onMouseOut : function(e){
27909 if(!e.within(this.el, true)){
27910 this.el.removeClass("x-btn-over");
27911 this.fireEvent('mouseout', this, e);
27915 onFocus : function(e){
27916 if(!this.disabled){
27917 this.el.addClass("x-btn-focus");
27921 onBlur : function(e){
27922 this.el.removeClass("x-btn-focus");
27925 onMouseDown : function(e){
27926 if(!this.disabled && e.button == 0){
27927 this.el.addClass("x-btn-click");
27928 Roo.get(document).on('mouseup', this.onMouseUp, this);
27932 onMouseUp : function(e){
27934 this.el.removeClass("x-btn-click");
27935 Roo.get(document).un('mouseup', this.onMouseUp, this);
27939 onMenuShow : function(e){
27940 this.el.addClass("x-btn-menu-active");
27943 onMenuHide : function(e){
27944 this.el.removeClass("x-btn-menu-active");
27948 // Private utility class used by Button
27949 Roo.ButtonToggleMgr = function(){
27952 function toggleGroup(btn, state){
27954 var g = groups[btn.toggleGroup];
27955 for(var i = 0, l = g.length; i < l; i++){
27957 g[i].toggle(false);
27964 register : function(btn){
27965 if(!btn.toggleGroup){
27968 var g = groups[btn.toggleGroup];
27970 g = groups[btn.toggleGroup] = [];
27973 btn.on("toggle", toggleGroup);
27976 unregister : function(btn){
27977 if(!btn.toggleGroup){
27980 var g = groups[btn.toggleGroup];
27983 btn.un("toggle", toggleGroup);
27989 * Ext JS Library 1.1.1
27990 * Copyright(c) 2006-2007, Ext JS, LLC.
27992 * Originally Released Under LGPL - original licence link has changed is not relivant.
27995 * <script type="text/javascript">
27999 * @class Roo.SplitButton
28000 * @extends Roo.Button
28001 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28002 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28003 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28004 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28005 * @cfg {String} arrowTooltip The title attribute of the arrow
28007 * Create a new menu button
28008 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28009 * @param {Object} config The config object
28011 Roo.SplitButton = function(renderTo, config){
28012 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28014 * @event arrowclick
28015 * Fires when this button's arrow is clicked
28016 * @param {SplitButton} this
28017 * @param {EventObject} e The click event
28019 this.addEvents({"arrowclick":true});
28022 Roo.extend(Roo.SplitButton, Roo.Button, {
28023 render : function(renderTo){
28024 // this is one sweet looking template!
28025 var tpl = new Roo.Template(
28026 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28027 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28028 '<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>',
28029 "</tbody></table></td><td>",
28030 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28031 '<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>',
28032 "</tbody></table></td></tr></table>"
28034 var btn = tpl.append(renderTo, [this.text, this.type], true);
28035 var btnEl = btn.child("button");
28037 btn.addClass(this.cls);
28040 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28043 btnEl.addClass(this.iconCls);
28045 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28049 if(this.handleMouseEvents){
28050 btn.on("mouseover", this.onMouseOver, this);
28051 btn.on("mouseout", this.onMouseOut, this);
28052 btn.on("mousedown", this.onMouseDown, this);
28053 btn.on("mouseup", this.onMouseUp, this);
28055 btn.on(this.clickEvent, this.onClick, this);
28057 if(typeof this.tooltip == 'object'){
28058 Roo.QuickTips.tips(Roo.apply({
28062 btnEl.dom[this.tooltipType] = this.tooltip;
28065 if(this.arrowTooltip){
28066 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28075 this.el.addClass("x-btn-pressed");
28077 if(Roo.isIE && !Roo.isIE7){
28078 this.autoWidth.defer(1, this);
28083 this.menu.on("show", this.onMenuShow, this);
28084 this.menu.on("hide", this.onMenuHide, this);
28086 this.fireEvent('render', this);
28090 autoWidth : function(){
28092 var tbl = this.el.child("table:first");
28093 var tbl2 = this.el.child("table:last");
28094 this.el.setWidth("auto");
28095 tbl.setWidth("auto");
28096 if(Roo.isIE7 && Roo.isStrict){
28097 var ib = this.el.child('button:first');
28098 if(ib && ib.getWidth() > 20){
28100 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28105 this.el.beginMeasure();
28107 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28108 tbl.setWidth(this.minWidth-tbl2.getWidth());
28111 this.el.endMeasure();
28114 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28118 * Sets this button's click handler
28119 * @param {Function} handler The function to call when the button is clicked
28120 * @param {Object} scope (optional) Scope for the function passed above
28122 setHandler : function(handler, scope){
28123 this.handler = handler;
28124 this.scope = scope;
28128 * Sets this button's arrow click handler
28129 * @param {Function} handler The function to call when the arrow is clicked
28130 * @param {Object} scope (optional) Scope for the function passed above
28132 setArrowHandler : function(handler, scope){
28133 this.arrowHandler = handler;
28134 this.scope = scope;
28140 focus : function(){
28142 this.el.child("button:first").focus();
28147 onClick : function(e){
28148 e.preventDefault();
28149 if(!this.disabled){
28150 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28151 if(this.menu && !this.menu.isVisible()){
28152 this.menu.show(this.el, this.menuAlign);
28154 this.fireEvent("arrowclick", this, e);
28155 if(this.arrowHandler){
28156 this.arrowHandler.call(this.scope || this, this, e);
28159 this.fireEvent("click", this, e);
28161 this.handler.call(this.scope || this, this, e);
28167 onMouseDown : function(e){
28168 if(!this.disabled){
28169 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28173 onMouseUp : function(e){
28174 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28179 // backwards compat
28180 Roo.MenuButton = Roo.SplitButton;/*
28182 * Ext JS Library 1.1.1
28183 * Copyright(c) 2006-2007, Ext JS, LLC.
28185 * Originally Released Under LGPL - original licence link has changed is not relivant.
28188 * <script type="text/javascript">
28192 * @class Roo.Toolbar
28193 * Basic Toolbar class.
28195 * Creates a new Toolbar
28196 * @param {Object} container The config object
28198 Roo.Toolbar = function(container, buttons, config)
28200 /// old consturctor format still supported..
28201 if(container instanceof Array){ // omit the container for later rendering
28202 buttons = container;
28206 if (typeof(container) == 'object' && container.xtype) {
28207 config = container;
28208 container = config.container;
28209 buttons = config.buttons || []; // not really - use items!!
28212 if (config && config.items) {
28213 xitems = config.items;
28214 delete config.items;
28216 Roo.apply(this, config);
28217 this.buttons = buttons;
28220 this.render(container);
28222 this.xitems = xitems;
28223 Roo.each(xitems, function(b) {
28229 Roo.Toolbar.prototype = {
28231 * @cfg {Array} items
28232 * array of button configs or elements to add (will be converted to a MixedCollection)
28236 * @cfg {String/HTMLElement/Element} container
28237 * The id or element that will contain the toolbar
28240 render : function(ct){
28241 this.el = Roo.get(ct);
28243 this.el.addClass(this.cls);
28245 // using a table allows for vertical alignment
28246 // 100% width is needed by Safari...
28247 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28248 this.tr = this.el.child("tr", true);
28250 this.items = new Roo.util.MixedCollection(false, function(o){
28251 return o.id || ("item" + (++autoId));
28254 this.add.apply(this, this.buttons);
28255 delete this.buttons;
28260 * Adds element(s) to the toolbar -- this function takes a variable number of
28261 * arguments of mixed type and adds them to the toolbar.
28262 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28264 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28265 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28266 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28267 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28268 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28269 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28270 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28271 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28272 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28274 * @param {Mixed} arg2
28275 * @param {Mixed} etc.
28278 var a = arguments, l = a.length;
28279 for(var i = 0; i < l; i++){
28284 _add : function(el) {
28287 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28290 if (el.applyTo){ // some kind of form field
28291 return this.addField(el);
28293 if (el.render){ // some kind of Toolbar.Item
28294 return this.addItem(el);
28296 if (typeof el == "string"){ // string
28297 if(el == "separator" || el == "-"){
28298 return this.addSeparator();
28301 return this.addSpacer();
28304 return this.addFill();
28306 return this.addText(el);
28309 if(el.tagName){ // element
28310 return this.addElement(el);
28312 if(typeof el == "object"){ // must be button config?
28313 return this.addButton(el);
28315 // and now what?!?!
28321 * Add an Xtype element
28322 * @param {Object} xtype Xtype Object
28323 * @return {Object} created Object
28325 addxtype : function(e){
28326 return this.add(e);
28330 * Returns the Element for this toolbar.
28331 * @return {Roo.Element}
28333 getEl : function(){
28339 * @return {Roo.Toolbar.Item} The separator item
28341 addSeparator : function(){
28342 return this.addItem(new Roo.Toolbar.Separator());
28346 * Adds a spacer element
28347 * @return {Roo.Toolbar.Spacer} The spacer item
28349 addSpacer : function(){
28350 return this.addItem(new Roo.Toolbar.Spacer());
28354 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28355 * @return {Roo.Toolbar.Fill} The fill item
28357 addFill : function(){
28358 return this.addItem(new Roo.Toolbar.Fill());
28362 * Adds any standard HTML element to the toolbar
28363 * @param {String/HTMLElement/Element} el The element or id of the element to add
28364 * @return {Roo.Toolbar.Item} The element's item
28366 addElement : function(el){
28367 return this.addItem(new Roo.Toolbar.Item(el));
28370 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28371 * @type Roo.util.MixedCollection
28376 * Adds any Toolbar.Item or subclass
28377 * @param {Roo.Toolbar.Item} item
28378 * @return {Roo.Toolbar.Item} The item
28380 addItem : function(item){
28381 var td = this.nextBlock();
28383 this.items.add(item);
28388 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28389 * @param {Object/Array} config A button config or array of configs
28390 * @return {Roo.Toolbar.Button/Array}
28392 addButton : function(config){
28393 if(config instanceof Array){
28395 for(var i = 0, len = config.length; i < len; i++) {
28396 buttons.push(this.addButton(config[i]));
28401 if(!(config instanceof Roo.Toolbar.Button)){
28403 new Roo.Toolbar.SplitButton(config) :
28404 new Roo.Toolbar.Button(config);
28406 var td = this.nextBlock();
28413 * Adds text to the toolbar
28414 * @param {String} text The text to add
28415 * @return {Roo.Toolbar.Item} The element's item
28417 addText : function(text){
28418 return this.addItem(new Roo.Toolbar.TextItem(text));
28422 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28423 * @param {Number} index The index where the item is to be inserted
28424 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28425 * @return {Roo.Toolbar.Button/Item}
28427 insertButton : function(index, item){
28428 if(item instanceof Array){
28430 for(var i = 0, len = item.length; i < len; i++) {
28431 buttons.push(this.insertButton(index + i, item[i]));
28435 if (!(item instanceof Roo.Toolbar.Button)){
28436 item = new Roo.Toolbar.Button(item);
28438 var td = document.createElement("td");
28439 this.tr.insertBefore(td, this.tr.childNodes[index]);
28441 this.items.insert(index, item);
28446 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28447 * @param {Object} config
28448 * @return {Roo.Toolbar.Item} The element's item
28450 addDom : function(config, returnEl){
28451 var td = this.nextBlock();
28452 Roo.DomHelper.overwrite(td, config);
28453 var ti = new Roo.Toolbar.Item(td.firstChild);
28455 this.items.add(ti);
28460 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28461 * @type Roo.util.MixedCollection
28466 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28467 * Note: the field should not have been rendered yet. For a field that has already been
28468 * rendered, use {@link #addElement}.
28469 * @param {Roo.form.Field} field
28470 * @return {Roo.ToolbarItem}
28474 addField : function(field) {
28475 if (!this.fields) {
28477 this.fields = new Roo.util.MixedCollection(false, function(o){
28478 return o.id || ("item" + (++autoId));
28483 var td = this.nextBlock();
28485 var ti = new Roo.Toolbar.Item(td.firstChild);
28487 this.items.add(ti);
28488 this.fields.add(field);
28499 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28500 this.el.child('div').hide();
28508 this.el.child('div').show();
28512 nextBlock : function(){
28513 var td = document.createElement("td");
28514 this.tr.appendChild(td);
28519 destroy : function(){
28520 if(this.items){ // rendered?
28521 Roo.destroy.apply(Roo, this.items.items);
28523 if(this.fields){ // rendered?
28524 Roo.destroy.apply(Roo, this.fields.items);
28526 Roo.Element.uncache(this.el, this.tr);
28531 * @class Roo.Toolbar.Item
28532 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28534 * Creates a new Item
28535 * @param {HTMLElement} el
28537 Roo.Toolbar.Item = function(el){
28539 if (typeof (el.xtype) != 'undefined') {
28544 this.el = Roo.getDom(el);
28545 this.id = Roo.id(this.el);
28546 this.hidden = false;
28551 * Fires when the button is rendered
28552 * @param {Button} this
28556 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28558 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28559 //Roo.Toolbar.Item.prototype = {
28562 * Get this item's HTML Element
28563 * @return {HTMLElement}
28565 getEl : function(){
28570 render : function(td){
28573 td.appendChild(this.el);
28575 this.fireEvent('render', this);
28579 * Removes and destroys this item.
28581 destroy : function(){
28582 this.td.parentNode.removeChild(this.td);
28589 this.hidden = false;
28590 this.td.style.display = "";
28597 this.hidden = true;
28598 this.td.style.display = "none";
28602 * Convenience function for boolean show/hide.
28603 * @param {Boolean} visible true to show/false to hide
28605 setVisible: function(visible){
28614 * Try to focus this item.
28616 focus : function(){
28617 Roo.fly(this.el).focus();
28621 * Disables this item.
28623 disable : function(){
28624 Roo.fly(this.td).addClass("x-item-disabled");
28625 this.disabled = true;
28626 this.el.disabled = true;
28630 * Enables this item.
28632 enable : function(){
28633 Roo.fly(this.td).removeClass("x-item-disabled");
28634 this.disabled = false;
28635 this.el.disabled = false;
28641 * @class Roo.Toolbar.Separator
28642 * @extends Roo.Toolbar.Item
28643 * A simple toolbar separator class
28645 * Creates a new Separator
28647 Roo.Toolbar.Separator = function(cfg){
28649 var s = document.createElement("span");
28650 s.className = "ytb-sep";
28655 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28657 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28658 enable:Roo.emptyFn,
28659 disable:Roo.emptyFn,
28664 * @class Roo.Toolbar.Spacer
28665 * @extends Roo.Toolbar.Item
28666 * A simple element that adds extra horizontal space to a toolbar.
28668 * Creates a new Spacer
28670 Roo.Toolbar.Spacer = function(cfg){
28671 var s = document.createElement("div");
28672 s.className = "ytb-spacer";
28676 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28678 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28679 enable:Roo.emptyFn,
28680 disable:Roo.emptyFn,
28685 * @class Roo.Toolbar.Fill
28686 * @extends Roo.Toolbar.Spacer
28687 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28689 * Creates a new Spacer
28691 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28693 render : function(td){
28694 td.style.width = '100%';
28695 Roo.Toolbar.Fill.superclass.render.call(this, td);
28700 * @class Roo.Toolbar.TextItem
28701 * @extends Roo.Toolbar.Item
28702 * A simple class that renders text directly into a toolbar.
28704 * Creates a new TextItem
28705 * @param {String} text
28707 Roo.Toolbar.TextItem = function(cfg){
28708 var text = cfg || "";
28709 if (typeof(cfg) == 'object') {
28710 text = cfg.text || "";
28714 var s = document.createElement("span");
28715 s.className = "ytb-text";
28716 s.innerHTML = text;
28721 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28723 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28726 enable:Roo.emptyFn,
28727 disable:Roo.emptyFn,
28732 * @class Roo.Toolbar.Button
28733 * @extends Roo.Button
28734 * A button that renders into a toolbar.
28736 * Creates a new Button
28737 * @param {Object} config A standard {@link Roo.Button} config object
28739 Roo.Toolbar.Button = function(config){
28740 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28742 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28743 render : function(td){
28745 Roo.Toolbar.Button.superclass.render.call(this, td);
28749 * Removes and destroys this button
28751 destroy : function(){
28752 Roo.Toolbar.Button.superclass.destroy.call(this);
28753 this.td.parentNode.removeChild(this.td);
28757 * Shows this button
28760 this.hidden = false;
28761 this.td.style.display = "";
28765 * Hides this button
28768 this.hidden = true;
28769 this.td.style.display = "none";
28773 * Disables this item
28775 disable : function(){
28776 Roo.fly(this.td).addClass("x-item-disabled");
28777 this.disabled = true;
28781 * Enables this item
28783 enable : function(){
28784 Roo.fly(this.td).removeClass("x-item-disabled");
28785 this.disabled = false;
28788 // backwards compat
28789 Roo.ToolbarButton = Roo.Toolbar.Button;
28792 * @class Roo.Toolbar.SplitButton
28793 * @extends Roo.SplitButton
28794 * A menu button that renders into a toolbar.
28796 * Creates a new SplitButton
28797 * @param {Object} config A standard {@link Roo.SplitButton} config object
28799 Roo.Toolbar.SplitButton = function(config){
28800 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28802 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28803 render : function(td){
28805 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28809 * Removes and destroys this button
28811 destroy : function(){
28812 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28813 this.td.parentNode.removeChild(this.td);
28817 * Shows this button
28820 this.hidden = false;
28821 this.td.style.display = "";
28825 * Hides this button
28828 this.hidden = true;
28829 this.td.style.display = "none";
28833 // backwards compat
28834 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28836 * Ext JS Library 1.1.1
28837 * Copyright(c) 2006-2007, Ext JS, LLC.
28839 * Originally Released Under LGPL - original licence link has changed is not relivant.
28842 * <script type="text/javascript">
28846 * @class Roo.PagingToolbar
28847 * @extends Roo.Toolbar
28848 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28850 * Create a new PagingToolbar
28851 * @param {Object} config The config object
28853 Roo.PagingToolbar = function(el, ds, config)
28855 // old args format still supported... - xtype is prefered..
28856 if (typeof(el) == 'object' && el.xtype) {
28857 // created from xtype...
28859 ds = el.dataSource;
28860 el = config.container;
28863 if (config.items) {
28864 items = config.items;
28868 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28871 this.renderButtons(this.el);
28874 // supprot items array.
28876 Roo.each(items, function(e) {
28877 this.add(Roo.factory(e));
28882 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28884 * @cfg {Roo.data.Store} dataSource
28885 * The underlying data store providing the paged data
28888 * @cfg {String/HTMLElement/Element} container
28889 * container The id or element that will contain the toolbar
28892 * @cfg {Boolean} displayInfo
28893 * True to display the displayMsg (defaults to false)
28896 * @cfg {Number} pageSize
28897 * The number of records to display per page (defaults to 20)
28901 * @cfg {String} displayMsg
28902 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28904 displayMsg : 'Displaying {0} - {1} of {2}',
28906 * @cfg {String} emptyMsg
28907 * The message to display when no records are found (defaults to "No data to display")
28909 emptyMsg : 'No data to display',
28911 * Customizable piece of the default paging text (defaults to "Page")
28914 beforePageText : "Page",
28916 * Customizable piece of the default paging text (defaults to "of %0")
28919 afterPageText : "of {0}",
28921 * Customizable piece of the default paging text (defaults to "First Page")
28924 firstText : "First Page",
28926 * Customizable piece of the default paging text (defaults to "Previous Page")
28929 prevText : "Previous Page",
28931 * Customizable piece of the default paging text (defaults to "Next Page")
28934 nextText : "Next Page",
28936 * Customizable piece of the default paging text (defaults to "Last Page")
28939 lastText : "Last Page",
28941 * Customizable piece of the default paging text (defaults to "Refresh")
28944 refreshText : "Refresh",
28947 renderButtons : function(el){
28948 Roo.PagingToolbar.superclass.render.call(this, el);
28949 this.first = this.addButton({
28950 tooltip: this.firstText,
28951 cls: "x-btn-icon x-grid-page-first",
28953 handler: this.onClick.createDelegate(this, ["first"])
28955 this.prev = this.addButton({
28956 tooltip: this.prevText,
28957 cls: "x-btn-icon x-grid-page-prev",
28959 handler: this.onClick.createDelegate(this, ["prev"])
28961 //this.addSeparator();
28962 this.add(this.beforePageText);
28963 this.field = Roo.get(this.addDom({
28968 cls: "x-grid-page-number"
28970 this.field.on("keydown", this.onPagingKeydown, this);
28971 this.field.on("focus", function(){this.dom.select();});
28972 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28973 this.field.setHeight(18);
28974 //this.addSeparator();
28975 this.next = this.addButton({
28976 tooltip: this.nextText,
28977 cls: "x-btn-icon x-grid-page-next",
28979 handler: this.onClick.createDelegate(this, ["next"])
28981 this.last = this.addButton({
28982 tooltip: this.lastText,
28983 cls: "x-btn-icon x-grid-page-last",
28985 handler: this.onClick.createDelegate(this, ["last"])
28987 //this.addSeparator();
28988 this.loading = this.addButton({
28989 tooltip: this.refreshText,
28990 cls: "x-btn-icon x-grid-loading",
28991 handler: this.onClick.createDelegate(this, ["refresh"])
28994 if(this.displayInfo){
28995 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29000 updateInfo : function(){
29001 if(this.displayEl){
29002 var count = this.ds.getCount();
29003 var msg = count == 0 ?
29007 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29009 this.displayEl.update(msg);
29014 onLoad : function(ds, r, o){
29015 this.cursor = o.params ? o.params.start : 0;
29016 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29018 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29019 this.field.dom.value = ap;
29020 this.first.setDisabled(ap == 1);
29021 this.prev.setDisabled(ap == 1);
29022 this.next.setDisabled(ap == ps);
29023 this.last.setDisabled(ap == ps);
29024 this.loading.enable();
29029 getPageData : function(){
29030 var total = this.ds.getTotalCount();
29033 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29034 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29039 onLoadError : function(){
29040 this.loading.enable();
29044 onPagingKeydown : function(e){
29045 var k = e.getKey();
29046 var d = this.getPageData();
29048 var v = this.field.dom.value, pageNum;
29049 if(!v || isNaN(pageNum = parseInt(v, 10))){
29050 this.field.dom.value = d.activePage;
29053 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29054 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29057 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))
29059 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29060 this.field.dom.value = pageNum;
29061 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29064 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29066 var v = this.field.dom.value, pageNum;
29067 var increment = (e.shiftKey) ? 10 : 1;
29068 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29070 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29071 this.field.dom.value = d.activePage;
29074 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29076 this.field.dom.value = parseInt(v, 10) + increment;
29077 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29078 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29085 beforeLoad : function(){
29087 this.loading.disable();
29092 onClick : function(which){
29096 ds.load({params:{start: 0, limit: this.pageSize}});
29099 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29102 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29105 var total = ds.getTotalCount();
29106 var extra = total % this.pageSize;
29107 var lastStart = extra ? (total - extra) : total-this.pageSize;
29108 ds.load({params:{start: lastStart, limit: this.pageSize}});
29111 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29117 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29118 * @param {Roo.data.Store} store The data store to unbind
29120 unbind : function(ds){
29121 ds.un("beforeload", this.beforeLoad, this);
29122 ds.un("load", this.onLoad, this);
29123 ds.un("loadexception", this.onLoadError, this);
29124 ds.un("remove", this.updateInfo, this);
29125 ds.un("add", this.updateInfo, this);
29126 this.ds = undefined;
29130 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29131 * @param {Roo.data.Store} store The data store to bind
29133 bind : function(ds){
29134 ds.on("beforeload", this.beforeLoad, this);
29135 ds.on("load", this.onLoad, this);
29136 ds.on("loadexception", this.onLoadError, this);
29137 ds.on("remove", this.updateInfo, this);
29138 ds.on("add", this.updateInfo, this);
29143 * Ext JS Library 1.1.1
29144 * Copyright(c) 2006-2007, Ext JS, LLC.
29146 * Originally Released Under LGPL - original licence link has changed is not relivant.
29149 * <script type="text/javascript">
29153 * @class Roo.Resizable
29154 * @extends Roo.util.Observable
29155 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29156 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29157 * 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
29158 * the element will be wrapped for you automatically.</p>
29159 * <p>Here is the list of valid resize handles:</p>
29162 ------ -------------------
29171 'hd' horizontal drag
29174 * <p>Here's an example showing the creation of a typical Resizable:</p>
29176 var resizer = new Roo.Resizable("element-id", {
29184 resizer.on("resize", myHandler);
29186 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29187 * resizer.east.setDisplayed(false);</p>
29188 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29189 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29190 * resize operation's new size (defaults to [0, 0])
29191 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29192 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29193 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29194 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29195 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29196 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29197 * @cfg {Number} width The width of the element in pixels (defaults to null)
29198 * @cfg {Number} height The height of the element in pixels (defaults to null)
29199 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29200 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29201 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29202 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29203 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29204 * in favor of the handles config option (defaults to false)
29205 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29206 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29207 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29208 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29209 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29210 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29211 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29212 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29213 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29214 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29215 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29217 * Create a new resizable component
29218 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29219 * @param {Object} config configuration options
29221 Roo.Resizable = function(el, config)
29223 this.el = Roo.get(el);
29225 if(config && config.wrap){
29226 config.resizeChild = this.el;
29227 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29228 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29229 this.el.setStyle("overflow", "hidden");
29230 this.el.setPositioning(config.resizeChild.getPositioning());
29231 config.resizeChild.clearPositioning();
29232 if(!config.width || !config.height){
29233 var csize = config.resizeChild.getSize();
29234 this.el.setSize(csize.width, csize.height);
29236 if(config.pinned && !config.adjustments){
29237 config.adjustments = "auto";
29241 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29242 this.proxy.unselectable();
29243 this.proxy.enableDisplayMode('block');
29245 Roo.apply(this, config);
29248 this.disableTrackOver = true;
29249 this.el.addClass("x-resizable-pinned");
29251 // if the element isn't positioned, make it relative
29252 var position = this.el.getStyle("position");
29253 if(position != "absolute" && position != "fixed"){
29254 this.el.setStyle("position", "relative");
29256 if(!this.handles){ // no handles passed, must be legacy style
29257 this.handles = 's,e,se';
29258 if(this.multiDirectional){
29259 this.handles += ',n,w';
29262 if(this.handles == "all"){
29263 this.handles = "n s e w ne nw se sw";
29265 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29266 var ps = Roo.Resizable.positions;
29267 for(var i = 0, len = hs.length; i < len; i++){
29268 if(hs[i] && ps[hs[i]]){
29269 var pos = ps[hs[i]];
29270 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29274 this.corner = this.southeast;
29276 // updateBox = the box can move..
29277 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29278 this.updateBox = true;
29281 this.activeHandle = null;
29283 if(this.resizeChild){
29284 if(typeof this.resizeChild == "boolean"){
29285 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29287 this.resizeChild = Roo.get(this.resizeChild, true);
29291 if(this.adjustments == "auto"){
29292 var rc = this.resizeChild;
29293 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29294 if(rc && (hw || hn)){
29295 rc.position("relative");
29296 rc.setLeft(hw ? hw.el.getWidth() : 0);
29297 rc.setTop(hn ? hn.el.getHeight() : 0);
29299 this.adjustments = [
29300 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29301 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29305 if(this.draggable){
29306 this.dd = this.dynamic ?
29307 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29308 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29314 * @event beforeresize
29315 * Fired before resize is allowed. Set enabled to false to cancel resize.
29316 * @param {Roo.Resizable} this
29317 * @param {Roo.EventObject} e The mousedown event
29319 "beforeresize" : true,
29322 * Fired a resizing.
29323 * @param {Roo.Resizable} this
29324 * @param {Number} x The new x position
29325 * @param {Number} y The new y position
29326 * @param {Number} w The new w width
29327 * @param {Number} h The new h hight
29328 * @param {Roo.EventObject} e The mouseup event
29333 * Fired after a resize.
29334 * @param {Roo.Resizable} this
29335 * @param {Number} width The new width
29336 * @param {Number} height The new height
29337 * @param {Roo.EventObject} e The mouseup event
29342 if(this.width !== null && this.height !== null){
29343 this.resizeTo(this.width, this.height);
29345 this.updateChildSize();
29348 this.el.dom.style.zoom = 1;
29350 Roo.Resizable.superclass.constructor.call(this);
29353 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29354 resizeChild : false,
29355 adjustments : [0, 0],
29365 multiDirectional : false,
29366 disableTrackOver : false,
29367 easing : 'easeOutStrong',
29368 widthIncrement : 0,
29369 heightIncrement : 0,
29373 preserveRatio : false,
29374 transparent: false,
29380 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29382 constrainTo: undefined,
29384 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29386 resizeRegion: undefined,
29390 * Perform a manual resize
29391 * @param {Number} width
29392 * @param {Number} height
29394 resizeTo : function(width, height){
29395 this.el.setSize(width, height);
29396 this.updateChildSize();
29397 this.fireEvent("resize", this, width, height, null);
29401 startSizing : function(e, handle){
29402 this.fireEvent("beforeresize", this, e);
29403 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29406 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29407 this.overlay.unselectable();
29408 this.overlay.enableDisplayMode("block");
29409 this.overlay.on("mousemove", this.onMouseMove, this);
29410 this.overlay.on("mouseup", this.onMouseUp, this);
29412 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29414 this.resizing = true;
29415 this.startBox = this.el.getBox();
29416 this.startPoint = e.getXY();
29417 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29418 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29420 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29421 this.overlay.show();
29423 if(this.constrainTo) {
29424 var ct = Roo.get(this.constrainTo);
29425 this.resizeRegion = ct.getRegion().adjust(
29426 ct.getFrameWidth('t'),
29427 ct.getFrameWidth('l'),
29428 -ct.getFrameWidth('b'),
29429 -ct.getFrameWidth('r')
29433 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29435 this.proxy.setBox(this.startBox);
29437 this.proxy.setStyle('visibility', 'visible');
29443 onMouseDown : function(handle, e){
29446 this.activeHandle = handle;
29447 this.startSizing(e, handle);
29452 onMouseUp : function(e){
29453 var size = this.resizeElement();
29454 this.resizing = false;
29456 this.overlay.hide();
29458 this.fireEvent("resize", this, size.width, size.height, e);
29462 updateChildSize : function(){
29464 if(this.resizeChild){
29466 var child = this.resizeChild;
29467 var adj = this.adjustments;
29468 if(el.dom.offsetWidth){
29469 var b = el.getSize(true);
29470 child.setSize(b.width+adj[0], b.height+adj[1]);
29472 // Second call here for IE
29473 // The first call enables instant resizing and
29474 // the second call corrects scroll bars if they
29477 setTimeout(function(){
29478 if(el.dom.offsetWidth){
29479 var b = el.getSize(true);
29480 child.setSize(b.width+adj[0], b.height+adj[1]);
29488 snap : function(value, inc, min){
29489 if(!inc || !value) return value;
29490 var newValue = value;
29491 var m = value % inc;
29494 newValue = value + (inc-m);
29496 newValue = value - m;
29499 return Math.max(min, newValue);
29503 resizeElement : function(){
29504 var box = this.proxy.getBox();
29505 if(this.updateBox){
29506 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29508 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29510 this.updateChildSize();
29518 constrain : function(v, diff, m, mx){
29521 }else if(v - diff > mx){
29528 onMouseMove : function(e){
29531 try{// try catch so if something goes wrong the user doesn't get hung
29533 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29537 //var curXY = this.startPoint;
29538 var curSize = this.curSize || this.startBox;
29539 var x = this.startBox.x, y = this.startBox.y;
29540 var ox = x, oy = y;
29541 var w = curSize.width, h = curSize.height;
29542 var ow = w, oh = h;
29543 var mw = this.minWidth, mh = this.minHeight;
29544 var mxw = this.maxWidth, mxh = this.maxHeight;
29545 var wi = this.widthIncrement;
29546 var hi = this.heightIncrement;
29548 var eventXY = e.getXY();
29549 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29550 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29552 var pos = this.activeHandle.position;
29557 w = Math.min(Math.max(mw, w), mxw);
29562 h = Math.min(Math.max(mh, h), mxh);
29567 w = Math.min(Math.max(mw, w), mxw);
29568 h = Math.min(Math.max(mh, h), mxh);
29571 diffY = this.constrain(h, diffY, mh, mxh);
29578 var adiffX = Math.abs(diffX);
29579 var sub = (adiffX % wi); // how much
29580 if (sub > (wi/2)) { // far enough to snap
29581 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29583 // remove difference..
29584 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29588 x = Math.max(this.minX, x);
29591 diffX = this.constrain(w, diffX, mw, mxw);
29597 w = Math.min(Math.max(mw, w), mxw);
29598 diffY = this.constrain(h, diffY, mh, mxh);
29603 diffX = this.constrain(w, diffX, mw, mxw);
29604 diffY = this.constrain(h, diffY, mh, mxh);
29611 diffX = this.constrain(w, diffX, mw, mxw);
29613 h = Math.min(Math.max(mh, h), mxh);
29619 var sw = this.snap(w, wi, mw);
29620 var sh = this.snap(h, hi, mh);
29621 if(sw != w || sh != h){
29644 if(this.preserveRatio){
29649 h = Math.min(Math.max(mh, h), mxh);
29654 w = Math.min(Math.max(mw, w), mxw);
29659 w = Math.min(Math.max(mw, w), mxw);
29665 w = Math.min(Math.max(mw, w), mxw);
29671 h = Math.min(Math.max(mh, h), mxh);
29679 h = Math.min(Math.max(mh, h), mxh);
29689 h = Math.min(Math.max(mh, h), mxh);
29697 if (pos == 'hdrag') {
29700 this.proxy.setBounds(x, y, w, h);
29702 this.resizeElement();
29706 this.fireEvent("resizing", this, x, y, w, h, e);
29710 handleOver : function(){
29712 this.el.addClass("x-resizable-over");
29717 handleOut : function(){
29718 if(!this.resizing){
29719 this.el.removeClass("x-resizable-over");
29724 * Returns the element this component is bound to.
29725 * @return {Roo.Element}
29727 getEl : function(){
29732 * Returns the resizeChild element (or null).
29733 * @return {Roo.Element}
29735 getResizeChild : function(){
29736 return this.resizeChild;
29738 groupHandler : function()
29743 * Destroys this resizable. If the element was wrapped and
29744 * removeEl is not true then the element remains.
29745 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29747 destroy : function(removeEl){
29748 this.proxy.remove();
29750 this.overlay.removeAllListeners();
29751 this.overlay.remove();
29753 var ps = Roo.Resizable.positions;
29755 if(typeof ps[k] != "function" && this[ps[k]]){
29756 var h = this[ps[k]];
29757 h.el.removeAllListeners();
29762 this.el.update("");
29769 // hash to map config positions to true positions
29770 Roo.Resizable.positions = {
29771 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29776 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29778 // only initialize the template if resizable is used
29779 var tpl = Roo.DomHelper.createTemplate(
29780 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29783 Roo.Resizable.Handle.prototype.tpl = tpl;
29785 this.position = pos;
29787 // show north drag fro topdra
29788 var handlepos = pos == 'hdrag' ? 'north' : pos;
29790 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29791 if (pos == 'hdrag') {
29792 this.el.setStyle('cursor', 'pointer');
29794 this.el.unselectable();
29796 this.el.setOpacity(0);
29798 this.el.on("mousedown", this.onMouseDown, this);
29799 if(!disableTrackOver){
29800 this.el.on("mouseover", this.onMouseOver, this);
29801 this.el.on("mouseout", this.onMouseOut, this);
29806 Roo.Resizable.Handle.prototype = {
29807 afterResize : function(rz){
29812 onMouseDown : function(e){
29813 this.rz.onMouseDown(this, e);
29816 onMouseOver : function(e){
29817 this.rz.handleOver(this, e);
29820 onMouseOut : function(e){
29821 this.rz.handleOut(this, e);
29825 * Ext JS Library 1.1.1
29826 * Copyright(c) 2006-2007, Ext JS, LLC.
29828 * Originally Released Under LGPL - original licence link has changed is not relivant.
29831 * <script type="text/javascript">
29835 * @class Roo.Editor
29836 * @extends Roo.Component
29837 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29839 * Create a new Editor
29840 * @param {Roo.form.Field} field The Field object (or descendant)
29841 * @param {Object} config The config object
29843 Roo.Editor = function(field, config){
29844 Roo.Editor.superclass.constructor.call(this, config);
29845 this.field = field;
29848 * @event beforestartedit
29849 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29850 * false from the handler of this event.
29851 * @param {Editor} this
29852 * @param {Roo.Element} boundEl The underlying element bound to this editor
29853 * @param {Mixed} value The field value being set
29855 "beforestartedit" : true,
29858 * Fires when this editor is displayed
29859 * @param {Roo.Element} boundEl The underlying element bound to this editor
29860 * @param {Mixed} value The starting field value
29862 "startedit" : true,
29864 * @event beforecomplete
29865 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29866 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29867 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29868 * event will not fire since no edit actually occurred.
29869 * @param {Editor} this
29870 * @param {Mixed} value The current field value
29871 * @param {Mixed} startValue The original field value
29873 "beforecomplete" : true,
29876 * Fires after editing is complete and any changed value has been written to the underlying field.
29877 * @param {Editor} this
29878 * @param {Mixed} value The current field value
29879 * @param {Mixed} startValue The original field value
29883 * @event specialkey
29884 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29885 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29886 * @param {Roo.form.Field} this
29887 * @param {Roo.EventObject} e The event object
29889 "specialkey" : true
29893 Roo.extend(Roo.Editor, Roo.Component, {
29895 * @cfg {Boolean/String} autosize
29896 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29897 * or "height" to adopt the height only (defaults to false)
29900 * @cfg {Boolean} revertInvalid
29901 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29902 * validation fails (defaults to true)
29905 * @cfg {Boolean} ignoreNoChange
29906 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29907 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29908 * will never be ignored.
29911 * @cfg {Boolean} hideEl
29912 * False to keep the bound element visible while the editor is displayed (defaults to true)
29915 * @cfg {Mixed} value
29916 * The data value of the underlying field (defaults to "")
29920 * @cfg {String} alignment
29921 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29925 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29926 * for bottom-right shadow (defaults to "frame")
29930 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29934 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29936 completeOnEnter : false,
29938 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29940 cancelOnEsc : false,
29942 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29947 onRender : function(ct, position){
29948 this.el = new Roo.Layer({
29949 shadow: this.shadow,
29955 constrain: this.constrain
29957 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29958 if(this.field.msgTarget != 'title'){
29959 this.field.msgTarget = 'qtip';
29961 this.field.render(this.el);
29963 this.field.el.dom.setAttribute('autocomplete', 'off');
29965 this.field.on("specialkey", this.onSpecialKey, this);
29966 if(this.swallowKeys){
29967 this.field.el.swallowEvent(['keydown','keypress']);
29970 this.field.on("blur", this.onBlur, this);
29971 if(this.field.grow){
29972 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29976 onSpecialKey : function(field, e)
29978 //Roo.log('editor onSpecialKey');
29979 if(this.completeOnEnter && e.getKey() == e.ENTER){
29981 this.completeEdit();
29984 // do not fire special key otherwise it might hide close the editor...
29985 if(e.getKey() == e.ENTER){
29988 if(this.cancelOnEsc && e.getKey() == e.ESC){
29992 this.fireEvent('specialkey', field, e);
29997 * Starts the editing process and shows the editor.
29998 * @param {String/HTMLElement/Element} el The element to edit
29999 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30000 * to the innerHTML of el.
30002 startEdit : function(el, value){
30004 this.completeEdit();
30006 this.boundEl = Roo.get(el);
30007 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30008 if(!this.rendered){
30009 this.render(this.parentEl || document.body);
30011 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30014 this.startValue = v;
30015 this.field.setValue(v);
30017 var sz = this.boundEl.getSize();
30018 switch(this.autoSize){
30020 this.setSize(sz.width, "");
30023 this.setSize("", sz.height);
30026 this.setSize(sz.width, sz.height);
30029 this.el.alignTo(this.boundEl, this.alignment);
30030 this.editing = true;
30032 Roo.QuickTips.disable();
30038 * Sets the height and width of this editor.
30039 * @param {Number} width The new width
30040 * @param {Number} height The new height
30042 setSize : function(w, h){
30043 this.field.setSize(w, h);
30050 * Realigns the editor to the bound field based on the current alignment config value.
30052 realign : function(){
30053 this.el.alignTo(this.boundEl, this.alignment);
30057 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30058 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30060 completeEdit : function(remainVisible){
30064 var v = this.getValue();
30065 if(this.revertInvalid !== false && !this.field.isValid()){
30066 v = this.startValue;
30067 this.cancelEdit(true);
30069 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30070 this.editing = false;
30074 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30075 this.editing = false;
30076 if(this.updateEl && this.boundEl){
30077 this.boundEl.update(v);
30079 if(remainVisible !== true){
30082 this.fireEvent("complete", this, v, this.startValue);
30087 onShow : function(){
30089 if(this.hideEl !== false){
30090 this.boundEl.hide();
30093 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30094 this.fixIEFocus = true;
30095 this.deferredFocus.defer(50, this);
30097 this.field.focus();
30099 this.fireEvent("startedit", this.boundEl, this.startValue);
30102 deferredFocus : function(){
30104 this.field.focus();
30109 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30110 * reverted to the original starting value.
30111 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30112 * cancel (defaults to false)
30114 cancelEdit : function(remainVisible){
30116 this.setValue(this.startValue);
30117 if(remainVisible !== true){
30124 onBlur : function(){
30125 if(this.allowBlur !== true && this.editing){
30126 this.completeEdit();
30131 onHide : function(){
30133 this.completeEdit();
30137 if(this.field.collapse){
30138 this.field.collapse();
30141 if(this.hideEl !== false){
30142 this.boundEl.show();
30145 Roo.QuickTips.enable();
30150 * Sets the data value of the editor
30151 * @param {Mixed} value Any valid value supported by the underlying field
30153 setValue : function(v){
30154 this.field.setValue(v);
30158 * Gets the data value of the editor
30159 * @return {Mixed} The data value
30161 getValue : function(){
30162 return this.field.getValue();
30166 * Ext JS Library 1.1.1
30167 * Copyright(c) 2006-2007, Ext JS, LLC.
30169 * Originally Released Under LGPL - original licence link has changed is not relivant.
30172 * <script type="text/javascript">
30176 * @class Roo.BasicDialog
30177 * @extends Roo.util.Observable
30178 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30180 var dlg = new Roo.BasicDialog("my-dlg", {
30189 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30190 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30191 dlg.addButton('Cancel', dlg.hide, dlg);
30194 <b>A Dialog should always be a direct child of the body element.</b>
30195 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30196 * @cfg {String} title Default text to display in the title bar (defaults to null)
30197 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30198 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30199 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30200 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30201 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30202 * (defaults to null with no animation)
30203 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30204 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30205 * property for valid values (defaults to 'all')
30206 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30207 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30208 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30209 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30210 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30211 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30212 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30213 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30214 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30215 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30216 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30217 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30218 * draggable = true (defaults to false)
30219 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30220 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30221 * shadow (defaults to false)
30222 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30223 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30224 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30225 * @cfg {Array} buttons Array of buttons
30226 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30228 * Create a new BasicDialog.
30229 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30230 * @param {Object} config Configuration options
30232 Roo.BasicDialog = function(el, config){
30233 this.el = Roo.get(el);
30234 var dh = Roo.DomHelper;
30235 if(!this.el && config && config.autoCreate){
30236 if(typeof config.autoCreate == "object"){
30237 if(!config.autoCreate.id){
30238 config.autoCreate.id = el;
30240 this.el = dh.append(document.body,
30241 config.autoCreate, true);
30243 this.el = dh.append(document.body,
30244 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30248 el.setDisplayed(true);
30249 el.hide = this.hideAction;
30251 el.addClass("x-dlg");
30253 Roo.apply(this, config);
30255 this.proxy = el.createProxy("x-dlg-proxy");
30256 this.proxy.hide = this.hideAction;
30257 this.proxy.setOpacity(.5);
30261 el.setWidth(config.width);
30264 el.setHeight(config.height);
30266 this.size = el.getSize();
30267 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30268 this.xy = [config.x,config.y];
30270 this.xy = el.getCenterXY(true);
30272 /** The header element @type Roo.Element */
30273 this.header = el.child("> .x-dlg-hd");
30274 /** The body element @type Roo.Element */
30275 this.body = el.child("> .x-dlg-bd");
30276 /** The footer element @type Roo.Element */
30277 this.footer = el.child("> .x-dlg-ft");
30280 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30283 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30286 this.header.unselectable();
30288 this.header.update(this.title);
30290 // this element allows the dialog to be focused for keyboard event
30291 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30292 this.focusEl.swallowEvent("click", true);
30294 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30296 // wrap the body and footer for special rendering
30297 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30299 this.bwrap.dom.appendChild(this.footer.dom);
30302 this.bg = this.el.createChild({
30303 tag: "div", cls:"x-dlg-bg",
30304 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30306 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30309 if(this.autoScroll !== false && !this.autoTabs){
30310 this.body.setStyle("overflow", "auto");
30313 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30315 if(this.closable !== false){
30316 this.el.addClass("x-dlg-closable");
30317 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30318 this.close.on("click", this.closeClick, this);
30319 this.close.addClassOnOver("x-dlg-close-over");
30321 if(this.collapsible !== false){
30322 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30323 this.collapseBtn.on("click", this.collapseClick, this);
30324 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30325 this.header.on("dblclick", this.collapseClick, this);
30327 if(this.resizable !== false){
30328 this.el.addClass("x-dlg-resizable");
30329 this.resizer = new Roo.Resizable(el, {
30330 minWidth: this.minWidth || 80,
30331 minHeight:this.minHeight || 80,
30332 handles: this.resizeHandles || "all",
30335 this.resizer.on("beforeresize", this.beforeResize, this);
30336 this.resizer.on("resize", this.onResize, this);
30338 if(this.draggable !== false){
30339 el.addClass("x-dlg-draggable");
30340 if (!this.proxyDrag) {
30341 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30344 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30346 dd.setHandleElId(this.header.id);
30347 dd.endDrag = this.endMove.createDelegate(this);
30348 dd.startDrag = this.startMove.createDelegate(this);
30349 dd.onDrag = this.onDrag.createDelegate(this);
30354 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30355 this.mask.enableDisplayMode("block");
30357 this.el.addClass("x-dlg-modal");
30360 this.shadow = new Roo.Shadow({
30361 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30362 offset : this.shadowOffset
30365 this.shadowOffset = 0;
30367 if(Roo.useShims && this.shim !== false){
30368 this.shim = this.el.createShim();
30369 this.shim.hide = this.hideAction;
30377 if (this.buttons) {
30378 var bts= this.buttons;
30380 Roo.each(bts, function(b) {
30389 * Fires when a key is pressed
30390 * @param {Roo.BasicDialog} this
30391 * @param {Roo.EventObject} e
30396 * Fires when this dialog is moved by the user.
30397 * @param {Roo.BasicDialog} this
30398 * @param {Number} x The new page X
30399 * @param {Number} y The new page Y
30404 * Fires when this dialog is resized by the user.
30405 * @param {Roo.BasicDialog} this
30406 * @param {Number} width The new width
30407 * @param {Number} height The new height
30411 * @event beforehide
30412 * Fires before this dialog is hidden.
30413 * @param {Roo.BasicDialog} this
30415 "beforehide" : true,
30418 * Fires when this dialog is hidden.
30419 * @param {Roo.BasicDialog} this
30423 * @event beforeshow
30424 * Fires before this dialog is shown.
30425 * @param {Roo.BasicDialog} this
30427 "beforeshow" : true,
30430 * Fires when this dialog is shown.
30431 * @param {Roo.BasicDialog} this
30435 el.on("keydown", this.onKeyDown, this);
30436 el.on("mousedown", this.toFront, this);
30437 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30439 Roo.DialogManager.register(this);
30440 Roo.BasicDialog.superclass.constructor.call(this);
30443 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30444 shadowOffset: Roo.isIE ? 6 : 5,
30447 minButtonWidth: 75,
30448 defaultButton: null,
30449 buttonAlign: "right",
30454 * Sets the dialog title text
30455 * @param {String} text The title text to display
30456 * @return {Roo.BasicDialog} this
30458 setTitle : function(text){
30459 this.header.update(text);
30464 closeClick : function(){
30469 collapseClick : function(){
30470 this[this.collapsed ? "expand" : "collapse"]();
30474 * Collapses the dialog to its minimized state (only the title bar is visible).
30475 * Equivalent to the user clicking the collapse dialog button.
30477 collapse : function(){
30478 if(!this.collapsed){
30479 this.collapsed = true;
30480 this.el.addClass("x-dlg-collapsed");
30481 this.restoreHeight = this.el.getHeight();
30482 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30487 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30488 * clicking the expand dialog button.
30490 expand : function(){
30491 if(this.collapsed){
30492 this.collapsed = false;
30493 this.el.removeClass("x-dlg-collapsed");
30494 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30499 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30500 * @return {Roo.TabPanel} The tabs component
30502 initTabs : function(){
30503 var tabs = this.getTabs();
30504 while(tabs.getTab(0)){
30507 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30509 tabs.addTab(Roo.id(dom), dom.title);
30517 beforeResize : function(){
30518 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30522 onResize : function(){
30523 this.refreshSize();
30524 this.syncBodyHeight();
30525 this.adjustAssets();
30527 this.fireEvent("resize", this, this.size.width, this.size.height);
30531 onKeyDown : function(e){
30532 if(this.isVisible()){
30533 this.fireEvent("keydown", this, e);
30538 * Resizes the dialog.
30539 * @param {Number} width
30540 * @param {Number} height
30541 * @return {Roo.BasicDialog} this
30543 resizeTo : function(width, height){
30544 this.el.setSize(width, height);
30545 this.size = {width: width, height: height};
30546 this.syncBodyHeight();
30547 if(this.fixedcenter){
30550 if(this.isVisible()){
30551 this.constrainXY();
30552 this.adjustAssets();
30554 this.fireEvent("resize", this, width, height);
30560 * Resizes the dialog to fit the specified content size.
30561 * @param {Number} width
30562 * @param {Number} height
30563 * @return {Roo.BasicDialog} this
30565 setContentSize : function(w, h){
30566 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30567 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30568 //if(!this.el.isBorderBox()){
30569 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30570 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30573 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30574 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30576 this.resizeTo(w, h);
30581 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30582 * executed in response to a particular key being pressed while the dialog is active.
30583 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30584 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30585 * @param {Function} fn The function to call
30586 * @param {Object} scope (optional) The scope of the function
30587 * @return {Roo.BasicDialog} this
30589 addKeyListener : function(key, fn, scope){
30590 var keyCode, shift, ctrl, alt;
30591 if(typeof key == "object" && !(key instanceof Array)){
30592 keyCode = key["key"];
30593 shift = key["shift"];
30594 ctrl = key["ctrl"];
30599 var handler = function(dlg, e){
30600 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30601 var k = e.getKey();
30602 if(keyCode instanceof Array){
30603 for(var i = 0, len = keyCode.length; i < len; i++){
30604 if(keyCode[i] == k){
30605 fn.call(scope || window, dlg, k, e);
30611 fn.call(scope || window, dlg, k, e);
30616 this.on("keydown", handler);
30621 * Returns the TabPanel component (creates it if it doesn't exist).
30622 * Note: If you wish to simply check for the existence of tabs without creating them,
30623 * check for a null 'tabs' property.
30624 * @return {Roo.TabPanel} The tabs component
30626 getTabs : function(){
30628 this.el.addClass("x-dlg-auto-tabs");
30629 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30630 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30636 * Adds a button to the footer section of the dialog.
30637 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30638 * object or a valid Roo.DomHelper element config
30639 * @param {Function} handler The function called when the button is clicked
30640 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30641 * @return {Roo.Button} The new button
30643 addButton : function(config, handler, scope){
30644 var dh = Roo.DomHelper;
30646 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30648 if(!this.btnContainer){
30649 var tb = this.footer.createChild({
30651 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30652 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30654 this.btnContainer = tb.firstChild.firstChild.firstChild;
30659 minWidth: this.minButtonWidth,
30662 if(typeof config == "string"){
30663 bconfig.text = config;
30666 bconfig.dhconfig = config;
30668 Roo.apply(bconfig, config);
30672 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30673 bconfig.position = Math.max(0, bconfig.position);
30674 fc = this.btnContainer.childNodes[bconfig.position];
30677 var btn = new Roo.Button(
30679 this.btnContainer.insertBefore(document.createElement("td"),fc)
30680 : this.btnContainer.appendChild(document.createElement("td")),
30681 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30684 this.syncBodyHeight();
30687 * Array of all the buttons that have been added to this dialog via addButton
30692 this.buttons.push(btn);
30697 * Sets the default button to be focused when the dialog is displayed.
30698 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30699 * @return {Roo.BasicDialog} this
30701 setDefaultButton : function(btn){
30702 this.defaultButton = btn;
30707 getHeaderFooterHeight : function(safe){
30710 height += this.header.getHeight();
30713 var fm = this.footer.getMargins();
30714 height += (this.footer.getHeight()+fm.top+fm.bottom);
30716 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30717 height += this.centerBg.getPadding("tb");
30722 syncBodyHeight : function()
30724 var bd = this.body, // the text
30725 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30727 var height = this.size.height - this.getHeaderFooterHeight(false);
30728 bd.setHeight(height-bd.getMargins("tb"));
30729 var hh = this.header.getHeight();
30730 var h = this.size.height-hh;
30733 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30734 bw.setHeight(h-cb.getPadding("tb"));
30736 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30737 bd.setWidth(bw.getWidth(true));
30739 this.tabs.syncHeight();
30741 this.tabs.el.repaint();
30747 * Restores the previous state of the dialog if Roo.state is configured.
30748 * @return {Roo.BasicDialog} this
30750 restoreState : function(){
30751 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30752 if(box && box.width){
30753 this.xy = [box.x, box.y];
30754 this.resizeTo(box.width, box.height);
30760 beforeShow : function(){
30762 if(this.fixedcenter){
30763 this.xy = this.el.getCenterXY(true);
30766 Roo.get(document.body).addClass("x-body-masked");
30767 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30770 this.constrainXY();
30774 animShow : function(){
30775 var b = Roo.get(this.animateTarget).getBox();
30776 this.proxy.setSize(b.width, b.height);
30777 this.proxy.setLocation(b.x, b.y);
30779 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30780 true, .35, this.showEl.createDelegate(this));
30784 * Shows the dialog.
30785 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30786 * @return {Roo.BasicDialog} this
30788 show : function(animateTarget){
30789 if (this.fireEvent("beforeshow", this) === false){
30792 if(this.syncHeightBeforeShow){
30793 this.syncBodyHeight();
30794 }else if(this.firstShow){
30795 this.firstShow = false;
30796 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30798 this.animateTarget = animateTarget || this.animateTarget;
30799 if(!this.el.isVisible()){
30801 if(this.animateTarget && Roo.get(this.animateTarget)){
30811 showEl : function(){
30813 this.el.setXY(this.xy);
30815 this.adjustAssets(true);
30818 // IE peekaboo bug - fix found by Dave Fenwick
30822 this.fireEvent("show", this);
30826 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30827 * dialog itself will receive focus.
30829 focus : function(){
30830 if(this.defaultButton){
30831 this.defaultButton.focus();
30833 this.focusEl.focus();
30838 constrainXY : function(){
30839 if(this.constraintoviewport !== false){
30840 if(!this.viewSize){
30841 if(this.container){
30842 var s = this.container.getSize();
30843 this.viewSize = [s.width, s.height];
30845 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30848 var s = Roo.get(this.container||document).getScroll();
30850 var x = this.xy[0], y = this.xy[1];
30851 var w = this.size.width, h = this.size.height;
30852 var vw = this.viewSize[0], vh = this.viewSize[1];
30853 // only move it if it needs it
30855 // first validate right/bottom
30856 if(x + w > vw+s.left){
30860 if(y + h > vh+s.top){
30864 // then make sure top/left isn't negative
30876 if(this.isVisible()){
30877 this.el.setLocation(x, y);
30878 this.adjustAssets();
30885 onDrag : function(){
30886 if(!this.proxyDrag){
30887 this.xy = this.el.getXY();
30888 this.adjustAssets();
30893 adjustAssets : function(doShow){
30894 var x = this.xy[0], y = this.xy[1];
30895 var w = this.size.width, h = this.size.height;
30896 if(doShow === true){
30898 this.shadow.show(this.el);
30904 if(this.shadow && this.shadow.isVisible()){
30905 this.shadow.show(this.el);
30907 if(this.shim && this.shim.isVisible()){
30908 this.shim.setBounds(x, y, w, h);
30913 adjustViewport : function(w, h){
30915 w = Roo.lib.Dom.getViewWidth();
30916 h = Roo.lib.Dom.getViewHeight();
30919 this.viewSize = [w, h];
30920 if(this.modal && this.mask.isVisible()){
30921 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30922 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30924 if(this.isVisible()){
30925 this.constrainXY();
30930 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30931 * shadow, proxy, mask, etc.) Also removes all event listeners.
30932 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30934 destroy : function(removeEl){
30935 if(this.isVisible()){
30936 this.animateTarget = null;
30939 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30941 this.tabs.destroy(removeEl);
30954 for(var i = 0, len = this.buttons.length; i < len; i++){
30955 this.buttons[i].destroy();
30958 this.el.removeAllListeners();
30959 if(removeEl === true){
30960 this.el.update("");
30963 Roo.DialogManager.unregister(this);
30967 startMove : function(){
30968 if(this.proxyDrag){
30971 if(this.constraintoviewport !== false){
30972 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30977 endMove : function(){
30978 if(!this.proxyDrag){
30979 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30981 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30984 this.refreshSize();
30985 this.adjustAssets();
30987 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30991 * Brings this dialog to the front of any other visible dialogs
30992 * @return {Roo.BasicDialog} this
30994 toFront : function(){
30995 Roo.DialogManager.bringToFront(this);
31000 * Sends this dialog to the back (under) of any other visible dialogs
31001 * @return {Roo.BasicDialog} this
31003 toBack : function(){
31004 Roo.DialogManager.sendToBack(this);
31009 * Centers this dialog in the viewport
31010 * @return {Roo.BasicDialog} this
31012 center : function(){
31013 var xy = this.el.getCenterXY(true);
31014 this.moveTo(xy[0], xy[1]);
31019 * Moves the dialog's top-left corner to the specified point
31020 * @param {Number} x
31021 * @param {Number} y
31022 * @return {Roo.BasicDialog} this
31024 moveTo : function(x, y){
31026 if(this.isVisible()){
31027 this.el.setXY(this.xy);
31028 this.adjustAssets();
31034 * Aligns the dialog to the specified element
31035 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31036 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31037 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31038 * @return {Roo.BasicDialog} this
31040 alignTo : function(element, position, offsets){
31041 this.xy = this.el.getAlignToXY(element, position, offsets);
31042 if(this.isVisible()){
31043 this.el.setXY(this.xy);
31044 this.adjustAssets();
31050 * Anchors an element to another element and realigns it when the window is resized.
31051 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31052 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31053 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31054 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31055 * is a number, it is used as the buffer delay (defaults to 50ms).
31056 * @return {Roo.BasicDialog} this
31058 anchorTo : function(el, alignment, offsets, monitorScroll){
31059 var action = function(){
31060 this.alignTo(el, alignment, offsets);
31062 Roo.EventManager.onWindowResize(action, this);
31063 var tm = typeof monitorScroll;
31064 if(tm != 'undefined'){
31065 Roo.EventManager.on(window, 'scroll', action, this,
31066 {buffer: tm == 'number' ? monitorScroll : 50});
31073 * Returns true if the dialog is visible
31074 * @return {Boolean}
31076 isVisible : function(){
31077 return this.el.isVisible();
31081 animHide : function(callback){
31082 var b = Roo.get(this.animateTarget).getBox();
31084 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31086 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31087 this.hideEl.createDelegate(this, [callback]));
31091 * Hides the dialog.
31092 * @param {Function} callback (optional) Function to call when the dialog is hidden
31093 * @return {Roo.BasicDialog} this
31095 hide : function(callback){
31096 if (this.fireEvent("beforehide", this) === false){
31100 this.shadow.hide();
31105 // sometimes animateTarget seems to get set.. causing problems...
31106 // this just double checks..
31107 if(this.animateTarget && Roo.get(this.animateTarget)) {
31108 this.animHide(callback);
31111 this.hideEl(callback);
31117 hideEl : function(callback){
31121 Roo.get(document.body).removeClass("x-body-masked");
31123 this.fireEvent("hide", this);
31124 if(typeof callback == "function"){
31130 hideAction : function(){
31131 this.setLeft("-10000px");
31132 this.setTop("-10000px");
31133 this.setStyle("visibility", "hidden");
31137 refreshSize : function(){
31138 this.size = this.el.getSize();
31139 this.xy = this.el.getXY();
31140 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31144 // z-index is managed by the DialogManager and may be overwritten at any time
31145 setZIndex : function(index){
31147 this.mask.setStyle("z-index", index);
31150 this.shim.setStyle("z-index", ++index);
31153 this.shadow.setZIndex(++index);
31155 this.el.setStyle("z-index", ++index);
31157 this.proxy.setStyle("z-index", ++index);
31160 this.resizer.proxy.setStyle("z-index", ++index);
31163 this.lastZIndex = index;
31167 * Returns the element for this dialog
31168 * @return {Roo.Element} The underlying dialog Element
31170 getEl : function(){
31176 * @class Roo.DialogManager
31177 * Provides global access to BasicDialogs that have been created and
31178 * support for z-indexing (layering) multiple open dialogs.
31180 Roo.DialogManager = function(){
31182 var accessList = [];
31186 var sortDialogs = function(d1, d2){
31187 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31191 var orderDialogs = function(){
31192 accessList.sort(sortDialogs);
31193 var seed = Roo.DialogManager.zseed;
31194 for(var i = 0, len = accessList.length; i < len; i++){
31195 var dlg = accessList[i];
31197 dlg.setZIndex(seed + (i*10));
31204 * The starting z-index for BasicDialogs (defaults to 9000)
31205 * @type Number The z-index value
31210 register : function(dlg){
31211 list[dlg.id] = dlg;
31212 accessList.push(dlg);
31216 unregister : function(dlg){
31217 delete list[dlg.id];
31220 if(!accessList.indexOf){
31221 for( i = 0, len = accessList.length; i < len; i++){
31222 if(accessList[i] == dlg){
31223 accessList.splice(i, 1);
31228 i = accessList.indexOf(dlg);
31230 accessList.splice(i, 1);
31236 * Gets a registered dialog by id
31237 * @param {String/Object} id The id of the dialog or a dialog
31238 * @return {Roo.BasicDialog} this
31240 get : function(id){
31241 return typeof id == "object" ? id : list[id];
31245 * Brings the specified dialog to the front
31246 * @param {String/Object} dlg The id of the dialog or a dialog
31247 * @return {Roo.BasicDialog} this
31249 bringToFront : function(dlg){
31250 dlg = this.get(dlg);
31253 dlg._lastAccess = new Date().getTime();
31260 * Sends the specified dialog to the back
31261 * @param {String/Object} dlg The id of the dialog or a dialog
31262 * @return {Roo.BasicDialog} this
31264 sendToBack : function(dlg){
31265 dlg = this.get(dlg);
31266 dlg._lastAccess = -(new Date().getTime());
31272 * Hides all dialogs
31274 hideAll : function(){
31275 for(var id in list){
31276 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31285 * @class Roo.LayoutDialog
31286 * @extends Roo.BasicDialog
31287 * Dialog which provides adjustments for working with a layout in a Dialog.
31288 * Add your necessary layout config options to the dialog's config.<br>
31289 * Example usage (including a nested layout):
31292 dialog = new Roo.LayoutDialog("download-dlg", {
31301 // layout config merges with the dialog config
31303 tabPosition: "top",
31304 alwaysShowTabs: true
31307 dialog.addKeyListener(27, dialog.hide, dialog);
31308 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31309 dialog.addButton("Build It!", this.getDownload, this);
31311 // we can even add nested layouts
31312 var innerLayout = new Roo.BorderLayout("dl-inner", {
31322 innerLayout.beginUpdate();
31323 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31324 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31325 innerLayout.endUpdate(true);
31327 var layout = dialog.getLayout();
31328 layout.beginUpdate();
31329 layout.add("center", new Roo.ContentPanel("standard-panel",
31330 {title: "Download the Source", fitToFrame:true}));
31331 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31332 {title: "Build your own roo.js"}));
31333 layout.getRegion("center").showPanel(sp);
31334 layout.endUpdate();
31338 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31339 * @param {Object} config configuration options
31341 Roo.LayoutDialog = function(el, cfg){
31344 if (typeof(cfg) == 'undefined') {
31345 config = Roo.apply({}, el);
31346 // not sure why we use documentElement here.. - it should always be body.
31347 // IE7 borks horribly if we use documentElement.
31348 // webkit also does not like documentElement - it creates a body element...
31349 el = Roo.get( document.body || document.documentElement ).createChild();
31350 //config.autoCreate = true;
31354 config.autoTabs = false;
31355 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31356 this.body.setStyle({overflow:"hidden", position:"relative"});
31357 this.layout = new Roo.BorderLayout(this.body.dom, config);
31358 this.layout.monitorWindowResize = false;
31359 this.el.addClass("x-dlg-auto-layout");
31360 // fix case when center region overwrites center function
31361 this.center = Roo.BasicDialog.prototype.center;
31362 this.on("show", this.layout.layout, this.layout, true);
31363 if (config.items) {
31364 var xitems = config.items;
31365 delete config.items;
31366 Roo.each(xitems, this.addxtype, this);
31371 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31373 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31376 endUpdate : function(){
31377 this.layout.endUpdate();
31381 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31384 beginUpdate : function(){
31385 this.layout.beginUpdate();
31389 * Get the BorderLayout for this dialog
31390 * @return {Roo.BorderLayout}
31392 getLayout : function(){
31393 return this.layout;
31396 showEl : function(){
31397 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31399 this.layout.layout();
31404 // Use the syncHeightBeforeShow config option to control this automatically
31405 syncBodyHeight : function(){
31406 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31407 if(this.layout){this.layout.layout();}
31411 * Add an xtype element (actually adds to the layout.)
31412 * @return {Object} xdata xtype object data.
31415 addxtype : function(c) {
31416 return this.layout.addxtype(c);
31420 * Ext JS Library 1.1.1
31421 * Copyright(c) 2006-2007, Ext JS, LLC.
31423 * Originally Released Under LGPL - original licence link has changed is not relivant.
31426 * <script type="text/javascript">
31430 * @class Roo.MessageBox
31431 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31435 Roo.Msg.alert('Status', 'Changes saved successfully.');
31437 // Prompt for user data:
31438 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31440 // process text value...
31444 // Show a dialog using config options:
31446 title:'Save Changes?',
31447 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31448 buttons: Roo.Msg.YESNOCANCEL,
31455 Roo.MessageBox = function(){
31456 var dlg, opt, mask, waitTimer;
31457 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31458 var buttons, activeTextEl, bwidth;
31461 var handleButton = function(button){
31463 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31467 var handleHide = function(){
31468 if(opt && opt.cls){
31469 dlg.el.removeClass(opt.cls);
31472 Roo.TaskMgr.stop(waitTimer);
31478 var updateButtons = function(b){
31481 buttons["ok"].hide();
31482 buttons["cancel"].hide();
31483 buttons["yes"].hide();
31484 buttons["no"].hide();
31485 dlg.footer.dom.style.display = 'none';
31488 dlg.footer.dom.style.display = '';
31489 for(var k in buttons){
31490 if(typeof buttons[k] != "function"){
31493 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31494 width += buttons[k].el.getWidth()+15;
31504 var handleEsc = function(d, k, e){
31505 if(opt && opt.closable !== false){
31515 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31516 * @return {Roo.BasicDialog} The BasicDialog element
31518 getDialog : function(){
31520 dlg = new Roo.BasicDialog("x-msg-box", {
31525 constraintoviewport:false,
31527 collapsible : false,
31530 width:400, height:100,
31531 buttonAlign:"center",
31532 closeClick : function(){
31533 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31534 handleButton("no");
31536 handleButton("cancel");
31540 dlg.on("hide", handleHide);
31542 dlg.addKeyListener(27, handleEsc);
31544 var bt = this.buttonText;
31545 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31546 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31547 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31548 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31549 bodyEl = dlg.body.createChild({
31551 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>'
31553 msgEl = bodyEl.dom.firstChild;
31554 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31555 textboxEl.enableDisplayMode();
31556 textboxEl.addKeyListener([10,13], function(){
31557 if(dlg.isVisible() && opt && opt.buttons){
31558 if(opt.buttons.ok){
31559 handleButton("ok");
31560 }else if(opt.buttons.yes){
31561 handleButton("yes");
31565 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31566 textareaEl.enableDisplayMode();
31567 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31568 progressEl.enableDisplayMode();
31569 var pf = progressEl.dom.firstChild;
31571 pp = Roo.get(pf.firstChild);
31572 pp.setHeight(pf.offsetHeight);
31580 * Updates the message box body text
31581 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31582 * the XHTML-compliant non-breaking space character '&#160;')
31583 * @return {Roo.MessageBox} This message box
31585 updateText : function(text){
31586 if(!dlg.isVisible() && !opt.width){
31587 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31589 msgEl.innerHTML = text || ' ';
31591 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31592 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31594 Math.min(opt.width || cw , this.maxWidth),
31595 Math.max(opt.minWidth || this.minWidth, bwidth)
31598 activeTextEl.setWidth(w);
31600 if(dlg.isVisible()){
31601 dlg.fixedcenter = false;
31603 // to big, make it scroll. = But as usual stupid IE does not support
31606 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31607 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31608 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31610 bodyEl.dom.style.height = '';
31611 bodyEl.dom.style.overflowY = '';
31614 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31616 bodyEl.dom.style.overflowX = '';
31619 dlg.setContentSize(w, bodyEl.getHeight());
31620 if(dlg.isVisible()){
31621 dlg.fixedcenter = true;
31627 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31628 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31629 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31630 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31631 * @return {Roo.MessageBox} This message box
31633 updateProgress : function(value, text){
31635 this.updateText(text);
31637 if (pp) { // weird bug on my firefox - for some reason this is not defined
31638 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31644 * Returns true if the message box is currently displayed
31645 * @return {Boolean} True if the message box is visible, else false
31647 isVisible : function(){
31648 return dlg && dlg.isVisible();
31652 * Hides the message box if it is displayed
31655 if(this.isVisible()){
31661 * Displays a new message box, or reinitializes an existing message box, based on the config options
31662 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31663 * The following config object properties are supported:
31665 Property Type Description
31666 ---------- --------------- ------------------------------------------------------------------------------------
31667 animEl String/Element An id or Element from which the message box should animate as it opens and
31668 closes (defaults to undefined)
31669 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31670 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31671 closable Boolean False to hide the top-right close button (defaults to true). Note that
31672 progress and wait dialogs will ignore this property and always hide the
31673 close button as they can only be closed programmatically.
31674 cls String A custom CSS class to apply to the message box element
31675 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31676 displayed (defaults to 75)
31677 fn Function A callback function to execute after closing the dialog. The arguments to the
31678 function will be btn (the name of the button that was clicked, if applicable,
31679 e.g. "ok"), and text (the value of the active text field, if applicable).
31680 Progress and wait dialogs will ignore this option since they do not respond to
31681 user actions and can only be closed programmatically, so any required function
31682 should be called by the same code after it closes the dialog.
31683 icon String A CSS class that provides a background image to be used as an icon for
31684 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31685 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31686 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31687 modal Boolean False to allow user interaction with the page while the message box is
31688 displayed (defaults to true)
31689 msg String A string that will replace the existing message box body text (defaults
31690 to the XHTML-compliant non-breaking space character ' ')
31691 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31692 progress Boolean True to display a progress bar (defaults to false)
31693 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31694 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31695 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31696 title String The title text
31697 value String The string value to set into the active textbox element if displayed
31698 wait Boolean True to display a progress bar (defaults to false)
31699 width Number The width of the dialog in pixels
31706 msg: 'Please enter your address:',
31708 buttons: Roo.MessageBox.OKCANCEL,
31711 animEl: 'addAddressBtn'
31714 * @param {Object} config Configuration options
31715 * @return {Roo.MessageBox} This message box
31717 show : function(options)
31720 // this causes nightmares if you show one dialog after another
31721 // especially on callbacks..
31723 if(this.isVisible()){
31726 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31727 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31728 Roo.log("New Dialog Message:" + options.msg )
31729 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31730 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31733 var d = this.getDialog();
31735 d.setTitle(opt.title || " ");
31736 d.close.setDisplayed(opt.closable !== false);
31737 activeTextEl = textboxEl;
31738 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31743 textareaEl.setHeight(typeof opt.multiline == "number" ?
31744 opt.multiline : this.defaultTextHeight);
31745 activeTextEl = textareaEl;
31754 progressEl.setDisplayed(opt.progress === true);
31755 this.updateProgress(0);
31756 activeTextEl.dom.value = opt.value || "";
31758 dlg.setDefaultButton(activeTextEl);
31760 var bs = opt.buttons;
31763 db = buttons["ok"];
31764 }else if(bs && bs.yes){
31765 db = buttons["yes"];
31767 dlg.setDefaultButton(db);
31769 bwidth = updateButtons(opt.buttons);
31770 this.updateText(opt.msg);
31772 d.el.addClass(opt.cls);
31774 d.proxyDrag = opt.proxyDrag === true;
31775 d.modal = opt.modal !== false;
31776 d.mask = opt.modal !== false ? mask : false;
31777 if(!d.isVisible()){
31778 // force it to the end of the z-index stack so it gets a cursor in FF
31779 document.body.appendChild(dlg.el.dom);
31780 d.animateTarget = null;
31781 d.show(options.animEl);
31787 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31788 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31789 * and closing the message box when the process is complete.
31790 * @param {String} title The title bar text
31791 * @param {String} msg The message box body text
31792 * @return {Roo.MessageBox} This message box
31794 progress : function(title, msg){
31801 minWidth: this.minProgressWidth,
31808 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31809 * If a callback function is passed it will be called after the user clicks the button, and the
31810 * id of the button that was clicked will be passed as the only parameter to the callback
31811 * (could also be the top-right close button).
31812 * @param {String} title The title bar text
31813 * @param {String} msg The message box body text
31814 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31815 * @param {Object} scope (optional) The scope of the callback function
31816 * @return {Roo.MessageBox} This message box
31818 alert : function(title, msg, fn, scope){
31831 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31832 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31833 * You are responsible for closing the message box when the process is complete.
31834 * @param {String} msg The message box body text
31835 * @param {String} title (optional) The title bar text
31836 * @return {Roo.MessageBox} This message box
31838 wait : function(msg, title){
31849 waitTimer = Roo.TaskMgr.start({
31851 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31859 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31860 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31861 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31862 * @param {String} title The title bar text
31863 * @param {String} msg The message box body text
31864 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31865 * @param {Object} scope (optional) The scope of the callback function
31866 * @return {Roo.MessageBox} This message box
31868 confirm : function(title, msg, fn, scope){
31872 buttons: this.YESNO,
31881 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31882 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31883 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31884 * (could also be the top-right close button) and the text that was entered will be passed as the two
31885 * parameters to the callback.
31886 * @param {String} title The title bar text
31887 * @param {String} msg The message box body text
31888 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31889 * @param {Object} scope (optional) The scope of the callback function
31890 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31891 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31892 * @return {Roo.MessageBox} This message box
31894 prompt : function(title, msg, fn, scope, multiline){
31898 buttons: this.OKCANCEL,
31903 multiline: multiline,
31910 * Button config that displays a single OK button
31915 * Button config that displays Yes and No buttons
31918 YESNO : {yes:true, no:true},
31920 * Button config that displays OK and Cancel buttons
31923 OKCANCEL : {ok:true, cancel:true},
31925 * Button config that displays Yes, No and Cancel buttons
31928 YESNOCANCEL : {yes:true, no:true, cancel:true},
31931 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31934 defaultTextHeight : 75,
31936 * The maximum width in pixels of the message box (defaults to 600)
31941 * The minimum width in pixels of the message box (defaults to 100)
31946 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31947 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31950 minProgressWidth : 250,
31952 * An object containing the default button text strings that can be overriden for localized language support.
31953 * Supported properties are: ok, cancel, yes and no.
31954 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31967 * Shorthand for {@link Roo.MessageBox}
31969 Roo.Msg = Roo.MessageBox;/*
31971 * Ext JS Library 1.1.1
31972 * Copyright(c) 2006-2007, Ext JS, LLC.
31974 * Originally Released Under LGPL - original licence link has changed is not relivant.
31977 * <script type="text/javascript">
31980 * @class Roo.QuickTips
31981 * Provides attractive and customizable tooltips for any element.
31984 Roo.QuickTips = function(){
31985 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31986 var ce, bd, xy, dd;
31987 var visible = false, disabled = true, inited = false;
31988 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31990 var onOver = function(e){
31994 var t = e.getTarget();
31995 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31998 if(ce && t == ce.el){
31999 clearTimeout(hideProc);
32002 if(t && tagEls[t.id]){
32003 tagEls[t.id].el = t;
32004 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32007 var ttp, et = Roo.fly(t);
32008 var ns = cfg.namespace;
32009 if(tm.interceptTitles && t.title){
32012 t.removeAttribute("title");
32013 e.preventDefault();
32015 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32018 showProc = show.defer(tm.showDelay, tm, [{
32021 width: et.getAttributeNS(ns, cfg.width),
32022 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32023 title: et.getAttributeNS(ns, cfg.title),
32024 cls: et.getAttributeNS(ns, cfg.cls)
32029 var onOut = function(e){
32030 clearTimeout(showProc);
32031 var t = e.getTarget();
32032 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32033 hideProc = setTimeout(hide, tm.hideDelay);
32037 var onMove = function(e){
32043 if(tm.trackMouse && ce){
32048 var onDown = function(e){
32049 clearTimeout(showProc);
32050 clearTimeout(hideProc);
32052 if(tm.hideOnClick){
32055 tm.enable.defer(100, tm);
32060 var getPad = function(){
32061 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32064 var show = function(o){
32068 clearTimeout(dismissProc);
32070 if(removeCls){ // in case manually hidden
32071 el.removeClass(removeCls);
32075 el.addClass(ce.cls);
32076 removeCls = ce.cls;
32079 tipTitle.update(ce.title);
32082 tipTitle.update('');
32085 el.dom.style.width = tm.maxWidth+'px';
32086 //tipBody.dom.style.width = '';
32087 tipBodyText.update(o.text);
32088 var p = getPad(), w = ce.width;
32090 var td = tipBodyText.dom;
32091 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32092 if(aw > tm.maxWidth){
32094 }else if(aw < tm.minWidth){
32100 //tipBody.setWidth(w);
32101 el.setWidth(parseInt(w, 10) + p);
32102 if(ce.autoHide === false){
32103 close.setDisplayed(true);
32108 close.setDisplayed(false);
32114 el.avoidY = xy[1]-18;
32119 el.setStyle("visibility", "visible");
32120 el.fadeIn({callback: afterShow});
32126 var afterShow = function(){
32130 if(tm.autoDismiss && ce.autoHide !== false){
32131 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32136 var hide = function(noanim){
32137 clearTimeout(dismissProc);
32138 clearTimeout(hideProc);
32140 if(el.isVisible()){
32142 if(noanim !== true && tm.animate){
32143 el.fadeOut({callback: afterHide});
32150 var afterHide = function(){
32153 el.removeClass(removeCls);
32160 * @cfg {Number} minWidth
32161 * The minimum width of the quick tip (defaults to 40)
32165 * @cfg {Number} maxWidth
32166 * The maximum width of the quick tip (defaults to 300)
32170 * @cfg {Boolean} interceptTitles
32171 * True to automatically use the element's DOM title value if available (defaults to false)
32173 interceptTitles : false,
32175 * @cfg {Boolean} trackMouse
32176 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32178 trackMouse : false,
32180 * @cfg {Boolean} hideOnClick
32181 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32183 hideOnClick : true,
32185 * @cfg {Number} showDelay
32186 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32190 * @cfg {Number} hideDelay
32191 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32195 * @cfg {Boolean} autoHide
32196 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32197 * Used in conjunction with hideDelay.
32202 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32203 * (defaults to true). Used in conjunction with autoDismissDelay.
32205 autoDismiss : true,
32208 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32210 autoDismissDelay : 5000,
32212 * @cfg {Boolean} animate
32213 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32218 * @cfg {String} title
32219 * Title text to display (defaults to ''). This can be any valid HTML markup.
32223 * @cfg {String} text
32224 * Body text to display (defaults to ''). This can be any valid HTML markup.
32228 * @cfg {String} cls
32229 * A CSS class to apply to the base quick tip element (defaults to '').
32233 * @cfg {Number} width
32234 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32235 * minWidth or maxWidth.
32240 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32241 * or display QuickTips in a page.
32244 tm = Roo.QuickTips;
32245 cfg = tm.tagConfig;
32247 if(!Roo.isReady){ // allow calling of init() before onReady
32248 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32251 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32252 el.fxDefaults = {stopFx: true};
32253 // maximum custom styling
32254 //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>');
32255 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>');
32256 tipTitle = el.child('h3');
32257 tipTitle.enableDisplayMode("block");
32258 tipBody = el.child('div.x-tip-bd');
32259 tipBodyText = el.child('div.x-tip-bd-inner');
32260 //bdLeft = el.child('div.x-tip-bd-left');
32261 //bdRight = el.child('div.x-tip-bd-right');
32262 close = el.child('div.x-tip-close');
32263 close.enableDisplayMode("block");
32264 close.on("click", hide);
32265 var d = Roo.get(document);
32266 d.on("mousedown", onDown);
32267 d.on("mouseover", onOver);
32268 d.on("mouseout", onOut);
32269 d.on("mousemove", onMove);
32270 esc = d.addKeyListener(27, hide);
32273 dd = el.initDD("default", null, {
32274 onDrag : function(){
32278 dd.setHandleElId(tipTitle.id);
32287 * Configures a new quick tip instance and assigns it to a target element. The following config options
32290 Property Type Description
32291 ---------- --------------------- ------------------------------------------------------------------------
32292 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32294 * @param {Object} config The config object
32296 register : function(config){
32297 var cs = config instanceof Array ? config : arguments;
32298 for(var i = 0, len = cs.length; i < len; i++) {
32300 var target = c.target;
32302 if(target instanceof Array){
32303 for(var j = 0, jlen = target.length; j < jlen; j++){
32304 tagEls[target[j]] = c;
32307 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32314 * Removes this quick tip from its element and destroys it.
32315 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32317 unregister : function(el){
32318 delete tagEls[Roo.id(el)];
32322 * Enable this quick tip.
32324 enable : function(){
32325 if(inited && disabled){
32327 if(locks.length < 1){
32334 * Disable this quick tip.
32336 disable : function(){
32338 clearTimeout(showProc);
32339 clearTimeout(hideProc);
32340 clearTimeout(dismissProc);
32348 * Returns true if the quick tip is enabled, else false.
32350 isEnabled : function(){
32357 attribute : "qtip",
32367 // backwards compat
32368 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32370 * Ext JS Library 1.1.1
32371 * Copyright(c) 2006-2007, Ext JS, LLC.
32373 * Originally Released Under LGPL - original licence link has changed is not relivant.
32376 * <script type="text/javascript">
32381 * @class Roo.tree.TreePanel
32382 * @extends Roo.data.Tree
32384 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32385 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32386 * @cfg {Boolean} enableDD true to enable drag and drop
32387 * @cfg {Boolean} enableDrag true to enable just drag
32388 * @cfg {Boolean} enableDrop true to enable just drop
32389 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32390 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32391 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32392 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32393 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32394 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32395 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32396 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32397 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32398 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32399 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32400 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32401 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32402 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32403 * @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>
32404 * @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>
32407 * @param {String/HTMLElement/Element} el The container element
32408 * @param {Object} config
32410 Roo.tree.TreePanel = function(el, config){
32412 var loader = false;
32414 root = config.root;
32415 delete config.root;
32417 if (config.loader) {
32418 loader = config.loader;
32419 delete config.loader;
32422 Roo.apply(this, config);
32423 Roo.tree.TreePanel.superclass.constructor.call(this);
32424 this.el = Roo.get(el);
32425 this.el.addClass('x-tree');
32426 //console.log(root);
32428 this.setRootNode( Roo.factory(root, Roo.tree));
32431 this.loader = Roo.factory(loader, Roo.tree);
32434 * Read-only. The id of the container element becomes this TreePanel's id.
32436 this.id = this.el.id;
32439 * @event beforeload
32440 * Fires before a node is loaded, return false to cancel
32441 * @param {Node} node The node being loaded
32443 "beforeload" : true,
32446 * Fires when a node is loaded
32447 * @param {Node} node The node that was loaded
32451 * @event textchange
32452 * Fires when the text for a node is changed
32453 * @param {Node} node The node
32454 * @param {String} text The new text
32455 * @param {String} oldText The old text
32457 "textchange" : true,
32459 * @event beforeexpand
32460 * Fires before a node is expanded, return false to cancel.
32461 * @param {Node} node The node
32462 * @param {Boolean} deep
32463 * @param {Boolean} anim
32465 "beforeexpand" : true,
32467 * @event beforecollapse
32468 * Fires before a node is collapsed, return false to cancel.
32469 * @param {Node} node The node
32470 * @param {Boolean} deep
32471 * @param {Boolean} anim
32473 "beforecollapse" : true,
32476 * Fires when a node is expanded
32477 * @param {Node} node The node
32481 * @event disabledchange
32482 * Fires when the disabled status of a node changes
32483 * @param {Node} node The node
32484 * @param {Boolean} disabled
32486 "disabledchange" : true,
32489 * Fires when a node is collapsed
32490 * @param {Node} node The node
32494 * @event beforeclick
32495 * Fires before click processing on a node. Return false to cancel the default action.
32496 * @param {Node} node The node
32497 * @param {Roo.EventObject} e The event object
32499 "beforeclick":true,
32501 * @event checkchange
32502 * Fires when a node with a checkbox's checked property changes
32503 * @param {Node} this This node
32504 * @param {Boolean} checked
32506 "checkchange":true,
32509 * Fires when a node is clicked
32510 * @param {Node} node The node
32511 * @param {Roo.EventObject} e The event object
32516 * Fires when a node is double clicked
32517 * @param {Node} node The node
32518 * @param {Roo.EventObject} e The event object
32522 * @event contextmenu
32523 * Fires when a node is right clicked
32524 * @param {Node} node The node
32525 * @param {Roo.EventObject} e The event object
32527 "contextmenu":true,
32529 * @event beforechildrenrendered
32530 * Fires right before the child nodes for a node are rendered
32531 * @param {Node} node The node
32533 "beforechildrenrendered":true,
32536 * Fires when a node starts being dragged
32537 * @param {Roo.tree.TreePanel} this
32538 * @param {Roo.tree.TreeNode} node
32539 * @param {event} e The raw browser event
32541 "startdrag" : true,
32544 * Fires when a drag operation is complete
32545 * @param {Roo.tree.TreePanel} this
32546 * @param {Roo.tree.TreeNode} node
32547 * @param {event} e The raw browser event
32552 * Fires when a dragged node is dropped on a valid DD target
32553 * @param {Roo.tree.TreePanel} this
32554 * @param {Roo.tree.TreeNode} node
32555 * @param {DD} dd The dd it was dropped on
32556 * @param {event} e The raw browser event
32560 * @event beforenodedrop
32561 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32562 * passed to handlers has the following properties:<br />
32563 * <ul style="padding:5px;padding-left:16px;">
32564 * <li>tree - The TreePanel</li>
32565 * <li>target - The node being targeted for the drop</li>
32566 * <li>data - The drag data from the drag source</li>
32567 * <li>point - The point of the drop - append, above or below</li>
32568 * <li>source - The drag source</li>
32569 * <li>rawEvent - Raw mouse event</li>
32570 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32571 * to be inserted by setting them on this object.</li>
32572 * <li>cancel - Set this to true to cancel the drop.</li>
32574 * @param {Object} dropEvent
32576 "beforenodedrop" : true,
32579 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32580 * passed to handlers has the following properties:<br />
32581 * <ul style="padding:5px;padding-left:16px;">
32582 * <li>tree - The TreePanel</li>
32583 * <li>target - The node being targeted for the drop</li>
32584 * <li>data - The drag data from the drag source</li>
32585 * <li>point - The point of the drop - append, above or below</li>
32586 * <li>source - The drag source</li>
32587 * <li>rawEvent - Raw mouse event</li>
32588 * <li>dropNode - Dropped node(s).</li>
32590 * @param {Object} dropEvent
32594 * @event nodedragover
32595 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32596 * passed to handlers has the following properties:<br />
32597 * <ul style="padding:5px;padding-left:16px;">
32598 * <li>tree - The TreePanel</li>
32599 * <li>target - The node being targeted for the drop</li>
32600 * <li>data - The drag data from the drag source</li>
32601 * <li>point - The point of the drop - append, above or below</li>
32602 * <li>source - The drag source</li>
32603 * <li>rawEvent - Raw mouse event</li>
32604 * <li>dropNode - Drop node(s) provided by the source.</li>
32605 * <li>cancel - Set this to true to signal drop not allowed.</li>
32607 * @param {Object} dragOverEvent
32609 "nodedragover" : true
32612 if(this.singleExpand){
32613 this.on("beforeexpand", this.restrictExpand, this);
32616 this.editor.tree = this;
32617 this.editor = Roo.factory(this.editor, Roo.tree);
32620 if (this.selModel) {
32621 this.selModel = Roo.factory(this.selModel, Roo.tree);
32625 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32626 rootVisible : true,
32627 animate: Roo.enableFx,
32630 hlDrop : Roo.enableFx,
32634 rendererTip: false,
32636 restrictExpand : function(node){
32637 var p = node.parentNode;
32639 if(p.expandedChild && p.expandedChild.parentNode == p){
32640 p.expandedChild.collapse();
32642 p.expandedChild = node;
32646 // private override
32647 setRootNode : function(node){
32648 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32649 if(!this.rootVisible){
32650 node.ui = new Roo.tree.RootTreeNodeUI(node);
32656 * Returns the container element for this TreePanel
32658 getEl : function(){
32663 * Returns the default TreeLoader for this TreePanel
32665 getLoader : function(){
32666 return this.loader;
32672 expandAll : function(){
32673 this.root.expand(true);
32677 * Collapse all nodes
32679 collapseAll : function(){
32680 this.root.collapse(true);
32684 * Returns the selection model used by this TreePanel
32686 getSelectionModel : function(){
32687 if(!this.selModel){
32688 this.selModel = new Roo.tree.DefaultSelectionModel();
32690 return this.selModel;
32694 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32695 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32696 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32699 getChecked : function(a, startNode){
32700 startNode = startNode || this.root;
32702 var f = function(){
32703 if(this.attributes.checked){
32704 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32707 startNode.cascade(f);
32712 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32713 * @param {String} path
32714 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32715 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32716 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32718 expandPath : function(path, attr, callback){
32719 attr = attr || "id";
32720 var keys = path.split(this.pathSeparator);
32721 var curNode = this.root;
32722 if(curNode.attributes[attr] != keys[1]){ // invalid root
32724 callback(false, null);
32729 var f = function(){
32730 if(++index == keys.length){
32732 callback(true, curNode);
32736 var c = curNode.findChild(attr, keys[index]);
32739 callback(false, curNode);
32744 c.expand(false, false, f);
32746 curNode.expand(false, false, f);
32750 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32751 * @param {String} path
32752 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32753 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32754 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32756 selectPath : function(path, attr, callback){
32757 attr = attr || "id";
32758 var keys = path.split(this.pathSeparator);
32759 var v = keys.pop();
32760 if(keys.length > 0){
32761 var f = function(success, node){
32762 if(success && node){
32763 var n = node.findChild(attr, v);
32769 }else if(callback){
32770 callback(false, n);
32774 callback(false, n);
32778 this.expandPath(keys.join(this.pathSeparator), attr, f);
32780 this.root.select();
32782 callback(true, this.root);
32787 getTreeEl : function(){
32792 * Trigger rendering of this TreePanel
32794 render : function(){
32795 if (this.innerCt) {
32796 return this; // stop it rendering more than once!!
32799 this.innerCt = this.el.createChild({tag:"ul",
32800 cls:"x-tree-root-ct " +
32801 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32803 if(this.containerScroll){
32804 Roo.dd.ScrollManager.register(this.el);
32806 if((this.enableDD || this.enableDrop) && !this.dropZone){
32808 * The dropZone used by this tree if drop is enabled
32809 * @type Roo.tree.TreeDropZone
32811 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32812 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32815 if((this.enableDD || this.enableDrag) && !this.dragZone){
32817 * The dragZone used by this tree if drag is enabled
32818 * @type Roo.tree.TreeDragZone
32820 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32821 ddGroup: this.ddGroup || "TreeDD",
32822 scroll: this.ddScroll
32825 this.getSelectionModel().init(this);
32827 Roo.log("ROOT not set in tree");
32830 this.root.render();
32831 if(!this.rootVisible){
32832 this.root.renderChildren();
32838 * Ext JS Library 1.1.1
32839 * Copyright(c) 2006-2007, Ext JS, LLC.
32841 * Originally Released Under LGPL - original licence link has changed is not relivant.
32844 * <script type="text/javascript">
32849 * @class Roo.tree.DefaultSelectionModel
32850 * @extends Roo.util.Observable
32851 * The default single selection for a TreePanel.
32852 * @param {Object} cfg Configuration
32854 Roo.tree.DefaultSelectionModel = function(cfg){
32855 this.selNode = null;
32861 * @event selectionchange
32862 * Fires when the selected node changes
32863 * @param {DefaultSelectionModel} this
32864 * @param {TreeNode} node the new selection
32866 "selectionchange" : true,
32869 * @event beforeselect
32870 * Fires before the selected node changes, return false to cancel the change
32871 * @param {DefaultSelectionModel} this
32872 * @param {TreeNode} node the new selection
32873 * @param {TreeNode} node the old selection
32875 "beforeselect" : true
32878 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32881 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32882 init : function(tree){
32884 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32885 tree.on("click", this.onNodeClick, this);
32888 onNodeClick : function(node, e){
32889 if (e.ctrlKey && this.selNode == node) {
32890 this.unselect(node);
32898 * @param {TreeNode} node The node to select
32899 * @return {TreeNode} The selected node
32901 select : function(node){
32902 var last = this.selNode;
32903 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32905 last.ui.onSelectedChange(false);
32907 this.selNode = node;
32908 node.ui.onSelectedChange(true);
32909 this.fireEvent("selectionchange", this, node, last);
32916 * @param {TreeNode} node The node to unselect
32918 unselect : function(node){
32919 if(this.selNode == node){
32920 this.clearSelections();
32925 * Clear all selections
32927 clearSelections : function(){
32928 var n = this.selNode;
32930 n.ui.onSelectedChange(false);
32931 this.selNode = null;
32932 this.fireEvent("selectionchange", this, null);
32938 * Get the selected node
32939 * @return {TreeNode} The selected node
32941 getSelectedNode : function(){
32942 return this.selNode;
32946 * Returns true if the node is selected
32947 * @param {TreeNode} node The node to check
32948 * @return {Boolean}
32950 isSelected : function(node){
32951 return this.selNode == node;
32955 * Selects the node above the selected node in the tree, intelligently walking the nodes
32956 * @return TreeNode The new selection
32958 selectPrevious : function(){
32959 var s = this.selNode || this.lastSelNode;
32963 var ps = s.previousSibling;
32965 if(!ps.isExpanded() || ps.childNodes.length < 1){
32966 return this.select(ps);
32968 var lc = ps.lastChild;
32969 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32972 return this.select(lc);
32974 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32975 return this.select(s.parentNode);
32981 * Selects the node above the selected node in the tree, intelligently walking the nodes
32982 * @return TreeNode The new selection
32984 selectNext : function(){
32985 var s = this.selNode || this.lastSelNode;
32989 if(s.firstChild && s.isExpanded()){
32990 return this.select(s.firstChild);
32991 }else if(s.nextSibling){
32992 return this.select(s.nextSibling);
32993 }else if(s.parentNode){
32995 s.parentNode.bubble(function(){
32996 if(this.nextSibling){
32997 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33006 onKeyDown : function(e){
33007 var s = this.selNode || this.lastSelNode;
33008 // undesirable, but required
33013 var k = e.getKey();
33021 this.selectPrevious();
33024 e.preventDefault();
33025 if(s.hasChildNodes()){
33026 if(!s.isExpanded()){
33028 }else if(s.firstChild){
33029 this.select(s.firstChild, e);
33034 e.preventDefault();
33035 if(s.hasChildNodes() && s.isExpanded()){
33037 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33038 this.select(s.parentNode, e);
33046 * @class Roo.tree.MultiSelectionModel
33047 * @extends Roo.util.Observable
33048 * Multi selection for a TreePanel.
33049 * @param {Object} cfg Configuration
33051 Roo.tree.MultiSelectionModel = function(){
33052 this.selNodes = [];
33056 * @event selectionchange
33057 * Fires when the selected nodes change
33058 * @param {MultiSelectionModel} this
33059 * @param {Array} nodes Array of the selected nodes
33061 "selectionchange" : true
33063 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33067 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33068 init : function(tree){
33070 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33071 tree.on("click", this.onNodeClick, this);
33074 onNodeClick : function(node, e){
33075 this.select(node, e, e.ctrlKey);
33080 * @param {TreeNode} node The node to select
33081 * @param {EventObject} e (optional) An event associated with the selection
33082 * @param {Boolean} keepExisting True to retain existing selections
33083 * @return {TreeNode} The selected node
33085 select : function(node, e, keepExisting){
33086 if(keepExisting !== true){
33087 this.clearSelections(true);
33089 if(this.isSelected(node)){
33090 this.lastSelNode = node;
33093 this.selNodes.push(node);
33094 this.selMap[node.id] = node;
33095 this.lastSelNode = node;
33096 node.ui.onSelectedChange(true);
33097 this.fireEvent("selectionchange", this, this.selNodes);
33103 * @param {TreeNode} node The node to unselect
33105 unselect : function(node){
33106 if(this.selMap[node.id]){
33107 node.ui.onSelectedChange(false);
33108 var sn = this.selNodes;
33111 index = sn.indexOf(node);
33113 for(var i = 0, len = sn.length; i < len; i++){
33121 this.selNodes.splice(index, 1);
33123 delete this.selMap[node.id];
33124 this.fireEvent("selectionchange", this, this.selNodes);
33129 * Clear all selections
33131 clearSelections : function(suppressEvent){
33132 var sn = this.selNodes;
33134 for(var i = 0, len = sn.length; i < len; i++){
33135 sn[i].ui.onSelectedChange(false);
33137 this.selNodes = [];
33139 if(suppressEvent !== true){
33140 this.fireEvent("selectionchange", this, this.selNodes);
33146 * Returns true if the node is selected
33147 * @param {TreeNode} node The node to check
33148 * @return {Boolean}
33150 isSelected : function(node){
33151 return this.selMap[node.id] ? true : false;
33155 * Returns an array of the selected nodes
33158 getSelectedNodes : function(){
33159 return this.selNodes;
33162 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33164 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33166 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33169 * Ext JS Library 1.1.1
33170 * Copyright(c) 2006-2007, Ext JS, LLC.
33172 * Originally Released Under LGPL - original licence link has changed is not relivant.
33175 * <script type="text/javascript">
33179 * @class Roo.tree.TreeNode
33180 * @extends Roo.data.Node
33181 * @cfg {String} text The text for this node
33182 * @cfg {Boolean} expanded true to start the node expanded
33183 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33184 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33185 * @cfg {Boolean} disabled true to start the node disabled
33186 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33187 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33188 * @cfg {String} cls A css class to be added to the node
33189 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33190 * @cfg {String} href URL of the link used for the node (defaults to #)
33191 * @cfg {String} hrefTarget target frame for the link
33192 * @cfg {String} qtip An Ext QuickTip for the node
33193 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33194 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33195 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33196 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33197 * (defaults to undefined with no checkbox rendered)
33199 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33201 Roo.tree.TreeNode = function(attributes){
33202 attributes = attributes || {};
33203 if(typeof attributes == "string"){
33204 attributes = {text: attributes};
33206 this.childrenRendered = false;
33207 this.rendered = false;
33208 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33209 this.expanded = attributes.expanded === true;
33210 this.isTarget = attributes.isTarget !== false;
33211 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33212 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33215 * Read-only. The text for this node. To change it use setText().
33218 this.text = attributes.text;
33220 * True if this node is disabled.
33223 this.disabled = attributes.disabled === true;
33227 * @event textchange
33228 * Fires when the text for this node is changed
33229 * @param {Node} this This node
33230 * @param {String} text The new text
33231 * @param {String} oldText The old text
33233 "textchange" : true,
33235 * @event beforeexpand
33236 * Fires before this node is expanded, return false to cancel.
33237 * @param {Node} this This node
33238 * @param {Boolean} deep
33239 * @param {Boolean} anim
33241 "beforeexpand" : true,
33243 * @event beforecollapse
33244 * Fires before this node is collapsed, return false to cancel.
33245 * @param {Node} this This node
33246 * @param {Boolean} deep
33247 * @param {Boolean} anim
33249 "beforecollapse" : true,
33252 * Fires when this node is expanded
33253 * @param {Node} this This node
33257 * @event disabledchange
33258 * Fires when the disabled status of this node changes
33259 * @param {Node} this This node
33260 * @param {Boolean} disabled
33262 "disabledchange" : true,
33265 * Fires when this node is collapsed
33266 * @param {Node} this This node
33270 * @event beforeclick
33271 * Fires before click processing. Return false to cancel the default action.
33272 * @param {Node} this This node
33273 * @param {Roo.EventObject} e The event object
33275 "beforeclick":true,
33277 * @event checkchange
33278 * Fires when a node with a checkbox's checked property changes
33279 * @param {Node} this This node
33280 * @param {Boolean} checked
33282 "checkchange":true,
33285 * Fires when this node is clicked
33286 * @param {Node} this This node
33287 * @param {Roo.EventObject} e The event object
33292 * Fires when this node is double clicked
33293 * @param {Node} this This node
33294 * @param {Roo.EventObject} e The event object
33298 * @event contextmenu
33299 * Fires when this node is right clicked
33300 * @param {Node} this This node
33301 * @param {Roo.EventObject} e The event object
33303 "contextmenu":true,
33305 * @event beforechildrenrendered
33306 * Fires right before the child nodes for this node are rendered
33307 * @param {Node} this This node
33309 "beforechildrenrendered":true
33312 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33315 * Read-only. The UI for this node
33318 this.ui = new uiClass(this);
33320 // finally support items[]
33321 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33326 Roo.each(this.attributes.items, function(c) {
33327 this.appendChild(Roo.factory(c,Roo.Tree));
33329 delete this.attributes.items;
33334 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33335 preventHScroll: true,
33337 * Returns true if this node is expanded
33338 * @return {Boolean}
33340 isExpanded : function(){
33341 return this.expanded;
33345 * Returns the UI object for this node
33346 * @return {TreeNodeUI}
33348 getUI : function(){
33352 // private override
33353 setFirstChild : function(node){
33354 var of = this.firstChild;
33355 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33356 if(this.childrenRendered && of && node != of){
33357 of.renderIndent(true, true);
33360 this.renderIndent(true, true);
33364 // private override
33365 setLastChild : function(node){
33366 var ol = this.lastChild;
33367 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33368 if(this.childrenRendered && ol && node != ol){
33369 ol.renderIndent(true, true);
33372 this.renderIndent(true, true);
33376 // these methods are overridden to provide lazy rendering support
33377 // private override
33378 appendChild : function()
33380 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33381 if(node && this.childrenRendered){
33384 this.ui.updateExpandIcon();
33388 // private override
33389 removeChild : function(node){
33390 this.ownerTree.getSelectionModel().unselect(node);
33391 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33392 // if it's been rendered remove dom node
33393 if(this.childrenRendered){
33396 if(this.childNodes.length < 1){
33397 this.collapse(false, false);
33399 this.ui.updateExpandIcon();
33401 if(!this.firstChild) {
33402 this.childrenRendered = false;
33407 // private override
33408 insertBefore : function(node, refNode){
33409 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33410 if(newNode && refNode && this.childrenRendered){
33413 this.ui.updateExpandIcon();
33418 * Sets the text for this node
33419 * @param {String} text
33421 setText : function(text){
33422 var oldText = this.text;
33424 this.attributes.text = text;
33425 if(this.rendered){ // event without subscribing
33426 this.ui.onTextChange(this, text, oldText);
33428 this.fireEvent("textchange", this, text, oldText);
33432 * Triggers selection of this node
33434 select : function(){
33435 this.getOwnerTree().getSelectionModel().select(this);
33439 * Triggers deselection of this node
33441 unselect : function(){
33442 this.getOwnerTree().getSelectionModel().unselect(this);
33446 * Returns true if this node is selected
33447 * @return {Boolean}
33449 isSelected : function(){
33450 return this.getOwnerTree().getSelectionModel().isSelected(this);
33454 * Expand this node.
33455 * @param {Boolean} deep (optional) True to expand all children as well
33456 * @param {Boolean} anim (optional) false to cancel the default animation
33457 * @param {Function} callback (optional) A callback to be called when
33458 * expanding this node completes (does not wait for deep expand to complete).
33459 * Called with 1 parameter, this node.
33461 expand : function(deep, anim, callback){
33462 if(!this.expanded){
33463 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33466 if(!this.childrenRendered){
33467 this.renderChildren();
33469 this.expanded = true;
33470 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33471 this.ui.animExpand(function(){
33472 this.fireEvent("expand", this);
33473 if(typeof callback == "function"){
33477 this.expandChildNodes(true);
33479 }.createDelegate(this));
33483 this.fireEvent("expand", this);
33484 if(typeof callback == "function"){
33489 if(typeof callback == "function"){
33494 this.expandChildNodes(true);
33498 isHiddenRoot : function(){
33499 return this.isRoot && !this.getOwnerTree().rootVisible;
33503 * Collapse this node.
33504 * @param {Boolean} deep (optional) True to collapse all children as well
33505 * @param {Boolean} anim (optional) false to cancel the default animation
33507 collapse : function(deep, anim){
33508 if(this.expanded && !this.isHiddenRoot()){
33509 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33512 this.expanded = false;
33513 if((this.getOwnerTree().animate && anim !== false) || anim){
33514 this.ui.animCollapse(function(){
33515 this.fireEvent("collapse", this);
33517 this.collapseChildNodes(true);
33519 }.createDelegate(this));
33522 this.ui.collapse();
33523 this.fireEvent("collapse", this);
33527 var cs = this.childNodes;
33528 for(var i = 0, len = cs.length; i < len; i++) {
33529 cs[i].collapse(true, false);
33535 delayedExpand : function(delay){
33536 if(!this.expandProcId){
33537 this.expandProcId = this.expand.defer(delay, this);
33542 cancelExpand : function(){
33543 if(this.expandProcId){
33544 clearTimeout(this.expandProcId);
33546 this.expandProcId = false;
33550 * Toggles expanded/collapsed state of the node
33552 toggle : function(){
33561 * Ensures all parent nodes are expanded
33563 ensureVisible : function(callback){
33564 var tree = this.getOwnerTree();
33565 tree.expandPath(this.parentNode.getPath(), false, function(){
33566 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33567 Roo.callback(callback);
33568 }.createDelegate(this));
33572 * Expand all child nodes
33573 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33575 expandChildNodes : function(deep){
33576 var cs = this.childNodes;
33577 for(var i = 0, len = cs.length; i < len; i++) {
33578 cs[i].expand(deep);
33583 * Collapse all child nodes
33584 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33586 collapseChildNodes : function(deep){
33587 var cs = this.childNodes;
33588 for(var i = 0, len = cs.length; i < len; i++) {
33589 cs[i].collapse(deep);
33594 * Disables this node
33596 disable : function(){
33597 this.disabled = true;
33599 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33600 this.ui.onDisableChange(this, true);
33602 this.fireEvent("disabledchange", this, true);
33606 * Enables this node
33608 enable : function(){
33609 this.disabled = false;
33610 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33611 this.ui.onDisableChange(this, false);
33613 this.fireEvent("disabledchange", this, false);
33617 renderChildren : function(suppressEvent){
33618 if(suppressEvent !== false){
33619 this.fireEvent("beforechildrenrendered", this);
33621 var cs = this.childNodes;
33622 for(var i = 0, len = cs.length; i < len; i++){
33623 cs[i].render(true);
33625 this.childrenRendered = true;
33629 sort : function(fn, scope){
33630 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33631 if(this.childrenRendered){
33632 var cs = this.childNodes;
33633 for(var i = 0, len = cs.length; i < len; i++){
33634 cs[i].render(true);
33640 render : function(bulkRender){
33641 this.ui.render(bulkRender);
33642 if(!this.rendered){
33643 this.rendered = true;
33645 this.expanded = false;
33646 this.expand(false, false);
33652 renderIndent : function(deep, refresh){
33654 this.ui.childIndent = null;
33656 this.ui.renderIndent();
33657 if(deep === true && this.childrenRendered){
33658 var cs = this.childNodes;
33659 for(var i = 0, len = cs.length; i < len; i++){
33660 cs[i].renderIndent(true, refresh);
33666 * Ext JS Library 1.1.1
33667 * Copyright(c) 2006-2007, Ext JS, LLC.
33669 * Originally Released Under LGPL - original licence link has changed is not relivant.
33672 * <script type="text/javascript">
33676 * @class Roo.tree.AsyncTreeNode
33677 * @extends Roo.tree.TreeNode
33678 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33680 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33682 Roo.tree.AsyncTreeNode = function(config){
33683 this.loaded = false;
33684 this.loading = false;
33685 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33687 * @event beforeload
33688 * Fires before this node is loaded, return false to cancel
33689 * @param {Node} this This node
33691 this.addEvents({'beforeload':true, 'load': true});
33694 * Fires when this node is loaded
33695 * @param {Node} this This node
33698 * The loader used by this node (defaults to using the tree's defined loader)
33703 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33704 expand : function(deep, anim, callback){
33705 if(this.loading){ // if an async load is already running, waiting til it's done
33707 var f = function(){
33708 if(!this.loading){ // done loading
33709 clearInterval(timer);
33710 this.expand(deep, anim, callback);
33712 }.createDelegate(this);
33713 timer = setInterval(f, 200);
33717 if(this.fireEvent("beforeload", this) === false){
33720 this.loading = true;
33721 this.ui.beforeLoad(this);
33722 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33724 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33728 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33732 * Returns true if this node is currently loading
33733 * @return {Boolean}
33735 isLoading : function(){
33736 return this.loading;
33739 loadComplete : function(deep, anim, callback){
33740 this.loading = false;
33741 this.loaded = true;
33742 this.ui.afterLoad(this);
33743 this.fireEvent("load", this);
33744 this.expand(deep, anim, callback);
33748 * Returns true if this node has been loaded
33749 * @return {Boolean}
33751 isLoaded : function(){
33752 return this.loaded;
33755 hasChildNodes : function(){
33756 if(!this.isLeaf() && !this.loaded){
33759 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33764 * Trigger a reload for this node
33765 * @param {Function} callback
33767 reload : function(callback){
33768 this.collapse(false, false);
33769 while(this.firstChild){
33770 this.removeChild(this.firstChild);
33772 this.childrenRendered = false;
33773 this.loaded = false;
33774 if(this.isHiddenRoot()){
33775 this.expanded = false;
33777 this.expand(false, false, callback);
33781 * Ext JS Library 1.1.1
33782 * Copyright(c) 2006-2007, Ext JS, LLC.
33784 * Originally Released Under LGPL - original licence link has changed is not relivant.
33787 * <script type="text/javascript">
33791 * @class Roo.tree.TreeNodeUI
33793 * @param {Object} node The node to render
33794 * The TreeNode UI implementation is separate from the
33795 * tree implementation. Unless you are customizing the tree UI,
33796 * you should never have to use this directly.
33798 Roo.tree.TreeNodeUI = function(node){
33800 this.rendered = false;
33801 this.animating = false;
33802 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33805 Roo.tree.TreeNodeUI.prototype = {
33806 removeChild : function(node){
33808 this.ctNode.removeChild(node.ui.getEl());
33812 beforeLoad : function(){
33813 this.addClass("x-tree-node-loading");
33816 afterLoad : function(){
33817 this.removeClass("x-tree-node-loading");
33820 onTextChange : function(node, text, oldText){
33822 this.textNode.innerHTML = text;
33826 onDisableChange : function(node, state){
33827 this.disabled = state;
33829 this.addClass("x-tree-node-disabled");
33831 this.removeClass("x-tree-node-disabled");
33835 onSelectedChange : function(state){
33838 this.addClass("x-tree-selected");
33841 this.removeClass("x-tree-selected");
33845 onMove : function(tree, node, oldParent, newParent, index, refNode){
33846 this.childIndent = null;
33848 var targetNode = newParent.ui.getContainer();
33849 if(!targetNode){//target not rendered
33850 this.holder = document.createElement("div");
33851 this.holder.appendChild(this.wrap);
33854 var insertBefore = refNode ? refNode.ui.getEl() : null;
33856 targetNode.insertBefore(this.wrap, insertBefore);
33858 targetNode.appendChild(this.wrap);
33860 this.node.renderIndent(true);
33864 addClass : function(cls){
33866 Roo.fly(this.elNode).addClass(cls);
33870 removeClass : function(cls){
33872 Roo.fly(this.elNode).removeClass(cls);
33876 remove : function(){
33878 this.holder = document.createElement("div");
33879 this.holder.appendChild(this.wrap);
33883 fireEvent : function(){
33884 return this.node.fireEvent.apply(this.node, arguments);
33887 initEvents : function(){
33888 this.node.on("move", this.onMove, this);
33889 var E = Roo.EventManager;
33890 var a = this.anchor;
33892 var el = Roo.fly(a, '_treeui');
33894 if(Roo.isOpera){ // opera render bug ignores the CSS
33895 el.setStyle("text-decoration", "none");
33898 el.on("click", this.onClick, this);
33899 el.on("dblclick", this.onDblClick, this);
33902 Roo.EventManager.on(this.checkbox,
33903 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33906 el.on("contextmenu", this.onContextMenu, this);
33908 var icon = Roo.fly(this.iconNode);
33909 icon.on("click", this.onClick, this);
33910 icon.on("dblclick", this.onDblClick, this);
33911 icon.on("contextmenu", this.onContextMenu, this);
33912 E.on(this.ecNode, "click", this.ecClick, this, true);
33914 if(this.node.disabled){
33915 this.addClass("x-tree-node-disabled");
33917 if(this.node.hidden){
33918 this.addClass("x-tree-node-disabled");
33920 var ot = this.node.getOwnerTree();
33921 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33922 if(dd && (!this.node.isRoot || ot.rootVisible)){
33923 Roo.dd.Registry.register(this.elNode, {
33925 handles: this.getDDHandles(),
33931 getDDHandles : function(){
33932 return [this.iconNode, this.textNode];
33937 this.wrap.style.display = "none";
33943 this.wrap.style.display = "";
33947 onContextMenu : function(e){
33948 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33949 e.preventDefault();
33951 this.fireEvent("contextmenu", this.node, e);
33955 onClick : function(e){
33960 if(this.fireEvent("beforeclick", this.node, e) !== false){
33961 if(!this.disabled && this.node.attributes.href){
33962 this.fireEvent("click", this.node, e);
33965 e.preventDefault();
33970 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33971 this.node.toggle();
33974 this.fireEvent("click", this.node, e);
33980 onDblClick : function(e){
33981 e.preventDefault();
33986 this.toggleCheck();
33988 if(!this.animating && this.node.hasChildNodes()){
33989 this.node.toggle();
33991 this.fireEvent("dblclick", this.node, e);
33994 onCheckChange : function(){
33995 var checked = this.checkbox.checked;
33996 this.node.attributes.checked = checked;
33997 this.fireEvent('checkchange', this.node, checked);
34000 ecClick : function(e){
34001 if(!this.animating && this.node.hasChildNodes()){
34002 this.node.toggle();
34006 startDrop : function(){
34007 this.dropping = true;
34010 // delayed drop so the click event doesn't get fired on a drop
34011 endDrop : function(){
34012 setTimeout(function(){
34013 this.dropping = false;
34014 }.createDelegate(this), 50);
34017 expand : function(){
34018 this.updateExpandIcon();
34019 this.ctNode.style.display = "";
34022 focus : function(){
34023 if(!this.node.preventHScroll){
34024 try{this.anchor.focus();
34026 }else if(!Roo.isIE){
34028 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34029 var l = noscroll.scrollLeft;
34030 this.anchor.focus();
34031 noscroll.scrollLeft = l;
34036 toggleCheck : function(value){
34037 var cb = this.checkbox;
34039 cb.checked = (value === undefined ? !cb.checked : value);
34045 this.anchor.blur();
34049 animExpand : function(callback){
34050 var ct = Roo.get(this.ctNode);
34052 if(!this.node.hasChildNodes()){
34053 this.updateExpandIcon();
34054 this.ctNode.style.display = "";
34055 Roo.callback(callback);
34058 this.animating = true;
34059 this.updateExpandIcon();
34062 callback : function(){
34063 this.animating = false;
34064 Roo.callback(callback);
34067 duration: this.node.ownerTree.duration || .25
34071 highlight : function(){
34072 var tree = this.node.getOwnerTree();
34073 Roo.fly(this.wrap).highlight(
34074 tree.hlColor || "C3DAF9",
34075 {endColor: tree.hlBaseColor}
34079 collapse : function(){
34080 this.updateExpandIcon();
34081 this.ctNode.style.display = "none";
34084 animCollapse : function(callback){
34085 var ct = Roo.get(this.ctNode);
34086 ct.enableDisplayMode('block');
34089 this.animating = true;
34090 this.updateExpandIcon();
34093 callback : function(){
34094 this.animating = false;
34095 Roo.callback(callback);
34098 duration: this.node.ownerTree.duration || .25
34102 getContainer : function(){
34103 return this.ctNode;
34106 getEl : function(){
34110 appendDDGhost : function(ghostNode){
34111 ghostNode.appendChild(this.elNode.cloneNode(true));
34114 getDDRepairXY : function(){
34115 return Roo.lib.Dom.getXY(this.iconNode);
34118 onRender : function(){
34122 render : function(bulkRender){
34123 var n = this.node, a = n.attributes;
34124 var targetNode = n.parentNode ?
34125 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34127 if(!this.rendered){
34128 this.rendered = true;
34130 this.renderElements(n, a, targetNode, bulkRender);
34133 if(this.textNode.setAttributeNS){
34134 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34136 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34139 this.textNode.setAttribute("ext:qtip", a.qtip);
34141 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34144 }else if(a.qtipCfg){
34145 a.qtipCfg.target = Roo.id(this.textNode);
34146 Roo.QuickTips.register(a.qtipCfg);
34149 if(!this.node.expanded){
34150 this.updateExpandIcon();
34153 if(bulkRender === true) {
34154 targetNode.appendChild(this.wrap);
34159 renderElements : function(n, a, targetNode, bulkRender)
34161 // add some indent caching, this helps performance when rendering a large tree
34162 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34163 var t = n.getOwnerTree();
34164 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34165 if (typeof(n.attributes.html) != 'undefined') {
34166 txt = n.attributes.html;
34168 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34169 var cb = typeof a.checked == 'boolean';
34170 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34171 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34172 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34173 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34174 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34175 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34176 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34177 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34178 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34179 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34182 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34183 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34184 n.nextSibling.ui.getEl(), buf.join(""));
34186 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34189 this.elNode = this.wrap.childNodes[0];
34190 this.ctNode = this.wrap.childNodes[1];
34191 var cs = this.elNode.childNodes;
34192 this.indentNode = cs[0];
34193 this.ecNode = cs[1];
34194 this.iconNode = cs[2];
34197 this.checkbox = cs[3];
34200 this.anchor = cs[index];
34201 this.textNode = cs[index].firstChild;
34204 getAnchor : function(){
34205 return this.anchor;
34208 getTextEl : function(){
34209 return this.textNode;
34212 getIconEl : function(){
34213 return this.iconNode;
34216 isChecked : function(){
34217 return this.checkbox ? this.checkbox.checked : false;
34220 updateExpandIcon : function(){
34222 var n = this.node, c1, c2;
34223 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34224 var hasChild = n.hasChildNodes();
34228 c1 = "x-tree-node-collapsed";
34229 c2 = "x-tree-node-expanded";
34232 c1 = "x-tree-node-expanded";
34233 c2 = "x-tree-node-collapsed";
34236 this.removeClass("x-tree-node-leaf");
34237 this.wasLeaf = false;
34239 if(this.c1 != c1 || this.c2 != c2){
34240 Roo.fly(this.elNode).replaceClass(c1, c2);
34241 this.c1 = c1; this.c2 = c2;
34244 // this changes non-leafs into leafs if they have no children.
34245 // it's not very rational behaviour..
34247 if(!this.wasLeaf && this.node.leaf){
34248 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34251 this.wasLeaf = true;
34254 var ecc = "x-tree-ec-icon "+cls;
34255 if(this.ecc != ecc){
34256 this.ecNode.className = ecc;
34262 getChildIndent : function(){
34263 if(!this.childIndent){
34267 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34269 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34271 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34276 this.childIndent = buf.join("");
34278 return this.childIndent;
34281 renderIndent : function(){
34284 var p = this.node.parentNode;
34286 indent = p.ui.getChildIndent();
34288 if(this.indentMarkup != indent){ // don't rerender if not required
34289 this.indentNode.innerHTML = indent;
34290 this.indentMarkup = indent;
34292 this.updateExpandIcon();
34297 Roo.tree.RootTreeNodeUI = function(){
34298 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34300 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34301 render : function(){
34302 if(!this.rendered){
34303 var targetNode = this.node.ownerTree.innerCt.dom;
34304 this.node.expanded = true;
34305 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34306 this.wrap = this.ctNode = targetNode.firstChild;
34309 collapse : function(){
34311 expand : function(){
34315 * Ext JS Library 1.1.1
34316 * Copyright(c) 2006-2007, Ext JS, LLC.
34318 * Originally Released Under LGPL - original licence link has changed is not relivant.
34321 * <script type="text/javascript">
34324 * @class Roo.tree.TreeLoader
34325 * @extends Roo.util.Observable
34326 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34327 * nodes from a specified URL. The response must be a javascript Array definition
34328 * who's elements are node definition objects. eg:
34333 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34334 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34341 * The old style respose with just an array is still supported, but not recommended.
34344 * A server request is sent, and child nodes are loaded only when a node is expanded.
34345 * The loading node's id is passed to the server under the parameter name "node" to
34346 * enable the server to produce the correct child nodes.
34348 * To pass extra parameters, an event handler may be attached to the "beforeload"
34349 * event, and the parameters specified in the TreeLoader's baseParams property:
34351 myTreeLoader.on("beforeload", function(treeLoader, node) {
34352 this.baseParams.category = node.attributes.category;
34355 * This would pass an HTTP parameter called "category" to the server containing
34356 * the value of the Node's "category" attribute.
34358 * Creates a new Treeloader.
34359 * @param {Object} config A config object containing config properties.
34361 Roo.tree.TreeLoader = function(config){
34362 this.baseParams = {};
34363 this.requestMethod = "POST";
34364 Roo.apply(this, config);
34369 * @event beforeload
34370 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34371 * @param {Object} This TreeLoader object.
34372 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34373 * @param {Object} callback The callback function specified in the {@link #load} call.
34378 * Fires when the node has been successfuly loaded.
34379 * @param {Object} This TreeLoader object.
34380 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34381 * @param {Object} response The response object containing the data from the server.
34385 * @event loadexception
34386 * Fires if the network request failed.
34387 * @param {Object} This TreeLoader object.
34388 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34389 * @param {Object} response The response object containing the data from the server.
34391 loadexception : true,
34394 * Fires before a node is created, enabling you to return custom Node types
34395 * @param {Object} This TreeLoader object.
34396 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34401 Roo.tree.TreeLoader.superclass.constructor.call(this);
34404 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34406 * @cfg {String} dataUrl The URL from which to request a Json string which
34407 * specifies an array of node definition object representing the child nodes
34411 * @cfg {String} requestMethod either GET or POST
34412 * defaults to POST (due to BC)
34416 * @cfg {Object} baseParams (optional) An object containing properties which
34417 * specify HTTP parameters to be passed to each request for child nodes.
34420 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34421 * created by this loader. If the attributes sent by the server have an attribute in this object,
34422 * they take priority.
34425 * @cfg {Object} uiProviders (optional) An object containing properties which
34427 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34428 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34429 * <i>uiProvider</i> attribute of a returned child node is a string rather
34430 * than a reference to a TreeNodeUI implementation, this that string value
34431 * is used as a property name in the uiProviders object. You can define the provider named
34432 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34437 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34438 * child nodes before loading.
34440 clearOnLoad : true,
34443 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34444 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34445 * Grid query { data : [ .....] }
34450 * @cfg {String} queryParam (optional)
34451 * Name of the query as it will be passed on the querystring (defaults to 'node')
34452 * eg. the request will be ?node=[id]
34459 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34460 * This is called automatically when a node is expanded, but may be used to reload
34461 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34462 * @param {Roo.tree.TreeNode} node
34463 * @param {Function} callback
34465 load : function(node, callback){
34466 if(this.clearOnLoad){
34467 while(node.firstChild){
34468 node.removeChild(node.firstChild);
34471 if(node.attributes.children){ // preloaded json children
34472 var cs = node.attributes.children;
34473 for(var i = 0, len = cs.length; i < len; i++){
34474 node.appendChild(this.createNode(cs[i]));
34476 if(typeof callback == "function"){
34479 }else if(this.dataUrl){
34480 this.requestData(node, callback);
34484 getParams: function(node){
34485 var buf = [], bp = this.baseParams;
34486 for(var key in bp){
34487 if(typeof bp[key] != "function"){
34488 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34491 var n = this.queryParam === false ? 'node' : this.queryParam;
34492 buf.push(n + "=", encodeURIComponent(node.id));
34493 return buf.join("");
34496 requestData : function(node, callback){
34497 if(this.fireEvent("beforeload", this, node, callback) !== false){
34498 this.transId = Roo.Ajax.request({
34499 method:this.requestMethod,
34500 url: this.dataUrl||this.url,
34501 success: this.handleResponse,
34502 failure: this.handleFailure,
34504 argument: {callback: callback, node: node},
34505 params: this.getParams(node)
34508 // if the load is cancelled, make sure we notify
34509 // the node that we are done
34510 if(typeof callback == "function"){
34516 isLoading : function(){
34517 return this.transId ? true : false;
34520 abort : function(){
34521 if(this.isLoading()){
34522 Roo.Ajax.abort(this.transId);
34527 createNode : function(attr)
34529 // apply baseAttrs, nice idea Corey!
34530 if(this.baseAttrs){
34531 Roo.applyIf(attr, this.baseAttrs);
34533 if(this.applyLoader !== false){
34534 attr.loader = this;
34536 // uiProvider = depreciated..
34538 if(typeof(attr.uiProvider) == 'string'){
34539 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34540 /** eval:var:attr */ eval(attr.uiProvider);
34542 if(typeof(this.uiProviders['default']) != 'undefined') {
34543 attr.uiProvider = this.uiProviders['default'];
34546 this.fireEvent('create', this, attr);
34548 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34550 new Roo.tree.TreeNode(attr) :
34551 new Roo.tree.AsyncTreeNode(attr));
34554 processResponse : function(response, node, callback)
34556 var json = response.responseText;
34559 var o = Roo.decode(json);
34561 if (this.root === false && typeof(o.success) != undefined) {
34562 this.root = 'data'; // the default behaviour for list like data..
34565 if (this.root !== false && !o.success) {
34566 // it's a failure condition.
34567 var a = response.argument;
34568 this.fireEvent("loadexception", this, a.node, response);
34569 Roo.log("Load failed - should have a handler really");
34575 if (this.root !== false) {
34579 for(var i = 0, len = o.length; i < len; i++){
34580 var n = this.createNode(o[i]);
34582 node.appendChild(n);
34585 if(typeof callback == "function"){
34586 callback(this, node);
34589 this.handleFailure(response);
34593 handleResponse : function(response){
34594 this.transId = false;
34595 var a = response.argument;
34596 this.processResponse(response, a.node, a.callback);
34597 this.fireEvent("load", this, a.node, response);
34600 handleFailure : function(response)
34602 // should handle failure better..
34603 this.transId = false;
34604 var a = response.argument;
34605 this.fireEvent("loadexception", this, a.node, response);
34606 if(typeof a.callback == "function"){
34607 a.callback(this, a.node);
34612 * Ext JS Library 1.1.1
34613 * Copyright(c) 2006-2007, Ext JS, LLC.
34615 * Originally Released Under LGPL - original licence link has changed is not relivant.
34618 * <script type="text/javascript">
34622 * @class Roo.tree.TreeFilter
34623 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34624 * @param {TreePanel} tree
34625 * @param {Object} config (optional)
34627 Roo.tree.TreeFilter = function(tree, config){
34629 this.filtered = {};
34630 Roo.apply(this, config);
34633 Roo.tree.TreeFilter.prototype = {
34640 * Filter the data by a specific attribute.
34641 * @param {String/RegExp} value Either string that the attribute value
34642 * should start with or a RegExp to test against the attribute
34643 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34644 * @param {TreeNode} startNode (optional) The node to start the filter at.
34646 filter : function(value, attr, startNode){
34647 attr = attr || "text";
34649 if(typeof value == "string"){
34650 var vlen = value.length;
34651 // auto clear empty filter
34652 if(vlen == 0 && this.clearBlank){
34656 value = value.toLowerCase();
34658 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34660 }else if(value.exec){ // regex?
34662 return value.test(n.attributes[attr]);
34665 throw 'Illegal filter type, must be string or regex';
34667 this.filterBy(f, null, startNode);
34671 * Filter by a function. The passed function will be called with each
34672 * node in the tree (or from the startNode). If the function returns true, the node is kept
34673 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34674 * @param {Function} fn The filter function
34675 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34677 filterBy : function(fn, scope, startNode){
34678 startNode = startNode || this.tree.root;
34679 if(this.autoClear){
34682 var af = this.filtered, rv = this.reverse;
34683 var f = function(n){
34684 if(n == startNode){
34690 var m = fn.call(scope || n, n);
34698 startNode.cascade(f);
34701 if(typeof id != "function"){
34703 if(n && n.parentNode){
34704 n.parentNode.removeChild(n);
34712 * Clears the current filter. Note: with the "remove" option
34713 * set a filter cannot be cleared.
34715 clear : function(){
34717 var af = this.filtered;
34719 if(typeof id != "function"){
34726 this.filtered = {};
34731 * Ext JS Library 1.1.1
34732 * Copyright(c) 2006-2007, Ext JS, LLC.
34734 * Originally Released Under LGPL - original licence link has changed is not relivant.
34737 * <script type="text/javascript">
34742 * @class Roo.tree.TreeSorter
34743 * Provides sorting of nodes in a TreePanel
34745 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34746 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34747 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34748 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34749 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34750 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34752 * @param {TreePanel} tree
34753 * @param {Object} config
34755 Roo.tree.TreeSorter = function(tree, config){
34756 Roo.apply(this, config);
34757 tree.on("beforechildrenrendered", this.doSort, this);
34758 tree.on("append", this.updateSort, this);
34759 tree.on("insert", this.updateSort, this);
34761 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34762 var p = this.property || "text";
34763 var sortType = this.sortType;
34764 var fs = this.folderSort;
34765 var cs = this.caseSensitive === true;
34766 var leafAttr = this.leafAttr || 'leaf';
34768 this.sortFn = function(n1, n2){
34770 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34773 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34777 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34778 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34780 return dsc ? +1 : -1;
34782 return dsc ? -1 : +1;
34789 Roo.tree.TreeSorter.prototype = {
34790 doSort : function(node){
34791 node.sort(this.sortFn);
34794 compareNodes : function(n1, n2){
34795 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34798 updateSort : function(tree, node){
34799 if(node.childrenRendered){
34800 this.doSort.defer(1, this, [node]);
34805 * Ext JS Library 1.1.1
34806 * Copyright(c) 2006-2007, Ext JS, LLC.
34808 * Originally Released Under LGPL - original licence link has changed is not relivant.
34811 * <script type="text/javascript">
34814 if(Roo.dd.DropZone){
34816 Roo.tree.TreeDropZone = function(tree, config){
34817 this.allowParentInsert = false;
34818 this.allowContainerDrop = false;
34819 this.appendOnly = false;
34820 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34822 this.lastInsertClass = "x-tree-no-status";
34823 this.dragOverData = {};
34826 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34827 ddGroup : "TreeDD",
34830 expandDelay : 1000,
34832 expandNode : function(node){
34833 if(node.hasChildNodes() && !node.isExpanded()){
34834 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34838 queueExpand : function(node){
34839 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34842 cancelExpand : function(){
34843 if(this.expandProcId){
34844 clearTimeout(this.expandProcId);
34845 this.expandProcId = false;
34849 isValidDropPoint : function(n, pt, dd, e, data){
34850 if(!n || !data){ return false; }
34851 var targetNode = n.node;
34852 var dropNode = data.node;
34853 // default drop rules
34854 if(!(targetNode && targetNode.isTarget && pt)){
34857 if(pt == "append" && targetNode.allowChildren === false){
34860 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34863 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34866 // reuse the object
34867 var overEvent = this.dragOverData;
34868 overEvent.tree = this.tree;
34869 overEvent.target = targetNode;
34870 overEvent.data = data;
34871 overEvent.point = pt;
34872 overEvent.source = dd;
34873 overEvent.rawEvent = e;
34874 overEvent.dropNode = dropNode;
34875 overEvent.cancel = false;
34876 var result = this.tree.fireEvent("nodedragover", overEvent);
34877 return overEvent.cancel === false && result !== false;
34880 getDropPoint : function(e, n, dd)
34884 return tn.allowChildren !== false ? "append" : false; // always append for root
34886 var dragEl = n.ddel;
34887 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34888 var y = Roo.lib.Event.getPageY(e);
34889 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34891 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34892 var noAppend = tn.allowChildren === false;
34893 if(this.appendOnly || tn.parentNode.allowChildren === false){
34894 return noAppend ? false : "append";
34896 var noBelow = false;
34897 if(!this.allowParentInsert){
34898 noBelow = tn.hasChildNodes() && tn.isExpanded();
34900 var q = (b - t) / (noAppend ? 2 : 3);
34901 if(y >= t && y < (t + q)){
34903 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34910 onNodeEnter : function(n, dd, e, data)
34912 this.cancelExpand();
34915 onNodeOver : function(n, dd, e, data)
34918 var pt = this.getDropPoint(e, n, dd);
34921 // auto node expand check
34922 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34923 this.queueExpand(node);
34924 }else if(pt != "append"){
34925 this.cancelExpand();
34928 // set the insert point style on the target node
34929 var returnCls = this.dropNotAllowed;
34930 if(this.isValidDropPoint(n, pt, dd, e, data)){
34935 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34936 cls = "x-tree-drag-insert-above";
34937 }else if(pt == "below"){
34938 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34939 cls = "x-tree-drag-insert-below";
34941 returnCls = "x-tree-drop-ok-append";
34942 cls = "x-tree-drag-append";
34944 if(this.lastInsertClass != cls){
34945 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34946 this.lastInsertClass = cls;
34953 onNodeOut : function(n, dd, e, data){
34955 this.cancelExpand();
34956 this.removeDropIndicators(n);
34959 onNodeDrop : function(n, dd, e, data){
34960 var point = this.getDropPoint(e, n, dd);
34961 var targetNode = n.node;
34962 targetNode.ui.startDrop();
34963 if(!this.isValidDropPoint(n, point, dd, e, data)){
34964 targetNode.ui.endDrop();
34967 // first try to find the drop node
34968 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34971 target: targetNode,
34976 dropNode: dropNode,
34979 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34980 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34981 targetNode.ui.endDrop();
34984 // allow target changing
34985 targetNode = dropEvent.target;
34986 if(point == "append" && !targetNode.isExpanded()){
34987 targetNode.expand(false, null, function(){
34988 this.completeDrop(dropEvent);
34989 }.createDelegate(this));
34991 this.completeDrop(dropEvent);
34996 completeDrop : function(de){
34997 var ns = de.dropNode, p = de.point, t = de.target;
34998 if(!(ns instanceof Array)){
35002 for(var i = 0, len = ns.length; i < len; i++){
35005 t.parentNode.insertBefore(n, t);
35006 }else if(p == "below"){
35007 t.parentNode.insertBefore(n, t.nextSibling);
35013 if(this.tree.hlDrop){
35017 this.tree.fireEvent("nodedrop", de);
35020 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35021 if(this.tree.hlDrop){
35022 dropNode.ui.focus();
35023 dropNode.ui.highlight();
35025 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35028 getTree : function(){
35032 removeDropIndicators : function(n){
35035 Roo.fly(el).removeClass([
35036 "x-tree-drag-insert-above",
35037 "x-tree-drag-insert-below",
35038 "x-tree-drag-append"]);
35039 this.lastInsertClass = "_noclass";
35043 beforeDragDrop : function(target, e, id){
35044 this.cancelExpand();
35048 afterRepair : function(data){
35049 if(data && Roo.enableFx){
35050 data.node.ui.highlight();
35060 * Ext JS Library 1.1.1
35061 * Copyright(c) 2006-2007, Ext JS, LLC.
35063 * Originally Released Under LGPL - original licence link has changed is not relivant.
35066 * <script type="text/javascript">
35070 if(Roo.dd.DragZone){
35071 Roo.tree.TreeDragZone = function(tree, config){
35072 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35076 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35077 ddGroup : "TreeDD",
35079 onBeforeDrag : function(data, e){
35081 return n && n.draggable && !n.disabled;
35085 onInitDrag : function(e){
35086 var data = this.dragData;
35087 this.tree.getSelectionModel().select(data.node);
35088 this.proxy.update("");
35089 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35090 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35093 getRepairXY : function(e, data){
35094 return data.node.ui.getDDRepairXY();
35097 onEndDrag : function(data, e){
35098 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35103 onValidDrop : function(dd, e, id){
35104 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35108 beforeInvalidDrop : function(e, id){
35109 // this scrolls the original position back into view
35110 var sm = this.tree.getSelectionModel();
35111 sm.clearSelections();
35112 sm.select(this.dragData.node);
35117 * Ext JS Library 1.1.1
35118 * Copyright(c) 2006-2007, Ext JS, LLC.
35120 * Originally Released Under LGPL - original licence link has changed is not relivant.
35123 * <script type="text/javascript">
35126 * @class Roo.tree.TreeEditor
35127 * @extends Roo.Editor
35128 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35129 * as the editor field.
35131 * @param {Object} config (used to be the tree panel.)
35132 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35134 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35135 * @cfg {Roo.form.TextField|Object} field The field configuration
35139 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35142 if (oldconfig) { // old style..
35143 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35146 tree = config.tree;
35147 config.field = config.field || {};
35148 config.field.xtype = 'TextField';
35149 field = Roo.factory(config.field, Roo.form);
35151 config = config || {};
35156 * @event beforenodeedit
35157 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35158 * false from the handler of this event.
35159 * @param {Editor} this
35160 * @param {Roo.tree.Node} node
35162 "beforenodeedit" : true
35166 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35170 tree.on('beforeclick', this.beforeNodeClick, this);
35171 tree.getTreeEl().on('mousedown', this.hide, this);
35172 this.on('complete', this.updateNode, this);
35173 this.on('beforestartedit', this.fitToTree, this);
35174 this.on('startedit', this.bindScroll, this, {delay:10});
35175 this.on('specialkey', this.onSpecialKey, this);
35178 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35180 * @cfg {String} alignment
35181 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35187 * @cfg {Boolean} hideEl
35188 * True to hide the bound element while the editor is displayed (defaults to false)
35192 * @cfg {String} cls
35193 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35195 cls: "x-small-editor x-tree-editor",
35197 * @cfg {Boolean} shim
35198 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35204 * @cfg {Number} maxWidth
35205 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35206 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35207 * scroll and client offsets into account prior to each edit.
35214 fitToTree : function(ed, el){
35215 var td = this.tree.getTreeEl().dom, nd = el.dom;
35216 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35217 td.scrollLeft = nd.offsetLeft;
35221 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35222 this.setSize(w, '');
35224 return this.fireEvent('beforenodeedit', this, this.editNode);
35229 triggerEdit : function(node){
35230 this.completeEdit();
35231 this.editNode = node;
35232 this.startEdit(node.ui.textNode, node.text);
35236 bindScroll : function(){
35237 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35241 beforeNodeClick : function(node, e){
35242 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35243 this.lastClick = new Date();
35244 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35246 this.triggerEdit(node);
35253 updateNode : function(ed, value){
35254 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35255 this.editNode.setText(value);
35259 onHide : function(){
35260 Roo.tree.TreeEditor.superclass.onHide.call(this);
35262 this.editNode.ui.focus();
35267 onSpecialKey : function(field, e){
35268 var k = e.getKey();
35272 }else if(k == e.ENTER && !e.hasModifier()){
35274 this.completeEdit();
35277 });//<Script type="text/javascript">
35280 * Ext JS Library 1.1.1
35281 * Copyright(c) 2006-2007, Ext JS, LLC.
35283 * Originally Released Under LGPL - original licence link has changed is not relivant.
35286 * <script type="text/javascript">
35290 * Not documented??? - probably should be...
35293 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35294 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35296 renderElements : function(n, a, targetNode, bulkRender){
35297 //consel.log("renderElements?");
35298 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35300 var t = n.getOwnerTree();
35301 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35303 var cols = t.columns;
35304 var bw = t.borderWidth;
35306 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35307 var cb = typeof a.checked == "boolean";
35308 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35309 var colcls = 'x-t-' + tid + '-c0';
35311 '<li class="x-tree-node">',
35314 '<div class="x-tree-node-el ', a.cls,'">',
35316 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35319 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35320 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35321 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35322 (a.icon ? ' x-tree-node-inline-icon' : ''),
35323 (a.iconCls ? ' '+a.iconCls : ''),
35324 '" unselectable="on" />',
35325 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35326 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35328 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35329 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35330 '<span unselectable="on" qtip="' + tx + '">',
35334 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35335 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35337 for(var i = 1, len = cols.length; i < len; i++){
35339 colcls = 'x-t-' + tid + '-c' +i;
35340 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35341 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35342 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35348 '<div class="x-clear"></div></div>',
35349 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35352 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35353 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35354 n.nextSibling.ui.getEl(), buf.join(""));
35356 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35358 var el = this.wrap.firstChild;
35360 this.elNode = el.firstChild;
35361 this.ranchor = el.childNodes[1];
35362 this.ctNode = this.wrap.childNodes[1];
35363 var cs = el.firstChild.childNodes;
35364 this.indentNode = cs[0];
35365 this.ecNode = cs[1];
35366 this.iconNode = cs[2];
35369 this.checkbox = cs[3];
35372 this.anchor = cs[index];
35374 this.textNode = cs[index].firstChild;
35376 //el.on("click", this.onClick, this);
35377 //el.on("dblclick", this.onDblClick, this);
35380 // console.log(this);
35382 initEvents : function(){
35383 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35386 var a = this.ranchor;
35388 var el = Roo.get(a);
35390 if(Roo.isOpera){ // opera render bug ignores the CSS
35391 el.setStyle("text-decoration", "none");
35394 el.on("click", this.onClick, this);
35395 el.on("dblclick", this.onDblClick, this);
35396 el.on("contextmenu", this.onContextMenu, this);
35400 /*onSelectedChange : function(state){
35403 this.addClass("x-tree-selected");
35406 this.removeClass("x-tree-selected");
35409 addClass : function(cls){
35411 Roo.fly(this.elRow).addClass(cls);
35417 removeClass : function(cls){
35419 Roo.fly(this.elRow).removeClass(cls);
35425 });//<Script type="text/javascript">
35429 * Ext JS Library 1.1.1
35430 * Copyright(c) 2006-2007, Ext JS, LLC.
35432 * Originally Released Under LGPL - original licence link has changed is not relivant.
35435 * <script type="text/javascript">
35440 * @class Roo.tree.ColumnTree
35441 * @extends Roo.data.TreePanel
35442 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35443 * @cfg {int} borderWidth compined right/left border allowance
35445 * @param {String/HTMLElement/Element} el The container element
35446 * @param {Object} config
35448 Roo.tree.ColumnTree = function(el, config)
35450 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35454 * Fire this event on a container when it resizes
35455 * @param {int} w Width
35456 * @param {int} h Height
35460 this.on('resize', this.onResize, this);
35463 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35467 borderWidth: Roo.isBorderBox ? 0 : 2,
35470 render : function(){
35471 // add the header.....
35473 Roo.tree.ColumnTree.superclass.render.apply(this);
35475 this.el.addClass('x-column-tree');
35477 this.headers = this.el.createChild(
35478 {cls:'x-tree-headers'},this.innerCt.dom);
35480 var cols = this.columns, c;
35481 var totalWidth = 0;
35483 var len = cols.length;
35484 for(var i = 0; i < len; i++){
35486 totalWidth += c.width;
35487 this.headEls.push(this.headers.createChild({
35488 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35490 cls:'x-tree-hd-text',
35493 style:'width:'+(c.width-this.borderWidth)+'px;'
35496 this.headers.createChild({cls:'x-clear'});
35497 // prevent floats from wrapping when clipped
35498 this.headers.setWidth(totalWidth);
35499 //this.innerCt.setWidth(totalWidth);
35500 this.innerCt.setStyle({ overflow: 'auto' });
35501 this.onResize(this.width, this.height);
35505 onResize : function(w,h)
35510 this.innerCt.setWidth(this.width);
35511 this.innerCt.setHeight(this.height-20);
35514 var cols = this.columns, c;
35515 var totalWidth = 0;
35517 var len = cols.length;
35518 for(var i = 0; i < len; i++){
35520 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35521 // it's the expander..
35522 expEl = this.headEls[i];
35525 totalWidth += c.width;
35529 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35531 this.headers.setWidth(w-20);
35540 * Ext JS Library 1.1.1
35541 * Copyright(c) 2006-2007, Ext JS, LLC.
35543 * Originally Released Under LGPL - original licence link has changed is not relivant.
35546 * <script type="text/javascript">
35550 * @class Roo.menu.Menu
35551 * @extends Roo.util.Observable
35552 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35553 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35555 * Creates a new Menu
35556 * @param {Object} config Configuration options
35558 Roo.menu.Menu = function(config){
35559 Roo.apply(this, config);
35560 this.id = this.id || Roo.id();
35563 * @event beforeshow
35564 * Fires before this menu is displayed
35565 * @param {Roo.menu.Menu} this
35569 * @event beforehide
35570 * Fires before this menu is hidden
35571 * @param {Roo.menu.Menu} this
35576 * Fires after this menu is displayed
35577 * @param {Roo.menu.Menu} this
35582 * Fires after this menu is hidden
35583 * @param {Roo.menu.Menu} this
35588 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35589 * @param {Roo.menu.Menu} this
35590 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35591 * @param {Roo.EventObject} e
35596 * Fires when the mouse is hovering over this menu
35597 * @param {Roo.menu.Menu} this
35598 * @param {Roo.EventObject} e
35599 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35604 * Fires when the mouse exits this menu
35605 * @param {Roo.menu.Menu} this
35606 * @param {Roo.EventObject} e
35607 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35612 * Fires when a menu item contained in this menu is clicked
35613 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35614 * @param {Roo.EventObject} e
35618 if (this.registerMenu) {
35619 Roo.menu.MenuMgr.register(this);
35622 var mis = this.items;
35623 this.items = new Roo.util.MixedCollection();
35625 this.add.apply(this, mis);
35629 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35631 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35635 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35636 * for bottom-right shadow (defaults to "sides")
35640 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35641 * this menu (defaults to "tl-tr?")
35643 subMenuAlign : "tl-tr?",
35645 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35646 * relative to its element of origin (defaults to "tl-bl?")
35648 defaultAlign : "tl-bl?",
35650 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35652 allowOtherMenus : false,
35654 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35656 registerMenu : true,
35661 render : function(){
35665 var el = this.el = new Roo.Layer({
35667 shadow:this.shadow,
35669 parentEl: this.parentEl || document.body,
35673 this.keyNav = new Roo.menu.MenuNav(this);
35676 el.addClass("x-menu-plain");
35679 el.addClass(this.cls);
35681 // generic focus element
35682 this.focusEl = el.createChild({
35683 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35685 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35686 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35688 ul.on("mouseover", this.onMouseOver, this);
35689 ul.on("mouseout", this.onMouseOut, this);
35690 this.items.each(function(item){
35695 var li = document.createElement("li");
35696 li.className = "x-menu-list-item";
35697 ul.dom.appendChild(li);
35698 item.render(li, this);
35705 autoWidth : function(){
35706 var el = this.el, ul = this.ul;
35710 var w = this.width;
35713 }else if(Roo.isIE){
35714 el.setWidth(this.minWidth);
35715 var t = el.dom.offsetWidth; // force recalc
35716 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35721 delayAutoWidth : function(){
35724 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35726 this.awTask.delay(20);
35731 findTargetItem : function(e){
35732 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35733 if(t && t.menuItemId){
35734 return this.items.get(t.menuItemId);
35739 onClick : function(e){
35740 Roo.log("menu.onClick");
35741 var t = this.findTargetItem(e);
35746 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35747 if(t == this.activeItem && t.shouldDeactivate(e)){
35748 this.activeItem.deactivate();
35749 delete this.activeItem;
35753 this.setActiveItem(t, true);
35761 this.fireEvent("click", this, t, e);
35765 setActiveItem : function(item, autoExpand){
35766 if(item != this.activeItem){
35767 if(this.activeItem){
35768 this.activeItem.deactivate();
35770 this.activeItem = item;
35771 item.activate(autoExpand);
35772 }else if(autoExpand){
35778 tryActivate : function(start, step){
35779 var items = this.items;
35780 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35781 var item = items.get(i);
35782 if(!item.disabled && item.canActivate){
35783 this.setActiveItem(item, false);
35791 onMouseOver : function(e){
35793 if(t = this.findTargetItem(e)){
35794 if(t.canActivate && !t.disabled){
35795 this.setActiveItem(t, true);
35798 this.fireEvent("mouseover", this, e, t);
35802 onMouseOut : function(e){
35804 if(t = this.findTargetItem(e)){
35805 if(t == this.activeItem && t.shouldDeactivate(e)){
35806 this.activeItem.deactivate();
35807 delete this.activeItem;
35810 this.fireEvent("mouseout", this, e, t);
35814 * Read-only. Returns true if the menu is currently displayed, else false.
35817 isVisible : function(){
35818 return this.el && !this.hidden;
35822 * Displays this menu relative to another element
35823 * @param {String/HTMLElement/Roo.Element} element The element to align to
35824 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35825 * the element (defaults to this.defaultAlign)
35826 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35828 show : function(el, pos, parentMenu){
35829 this.parentMenu = parentMenu;
35833 this.fireEvent("beforeshow", this);
35834 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35838 * Displays this menu at a specific xy position
35839 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35840 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35842 showAt : function(xy, parentMenu, /* private: */_e){
35843 this.parentMenu = parentMenu;
35848 this.fireEvent("beforeshow", this);
35849 xy = this.el.adjustForConstraints(xy);
35853 this.hidden = false;
35855 this.fireEvent("show", this);
35858 focus : function(){
35860 this.doFocus.defer(50, this);
35864 doFocus : function(){
35866 this.focusEl.focus();
35871 * Hides this menu and optionally all parent menus
35872 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35874 hide : function(deep){
35875 if(this.el && this.isVisible()){
35876 this.fireEvent("beforehide", this);
35877 if(this.activeItem){
35878 this.activeItem.deactivate();
35879 this.activeItem = null;
35882 this.hidden = true;
35883 this.fireEvent("hide", this);
35885 if(deep === true && this.parentMenu){
35886 this.parentMenu.hide(true);
35891 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35892 * Any of the following are valid:
35894 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35895 * <li>An HTMLElement object which will be converted to a menu item</li>
35896 * <li>A menu item config object that will be created as a new menu item</li>
35897 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35898 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35903 var menu = new Roo.menu.Menu();
35905 // Create a menu item to add by reference
35906 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35908 // Add a bunch of items at once using different methods.
35909 // Only the last item added will be returned.
35910 var item = menu.add(
35911 menuItem, // add existing item by ref
35912 'Dynamic Item', // new TextItem
35913 '-', // new separator
35914 { text: 'Config Item' } // new item by config
35917 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35918 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35921 var a = arguments, l = a.length, item;
35922 for(var i = 0; i < l; i++){
35924 if ((typeof(el) == "object") && el.xtype && el.xns) {
35925 el = Roo.factory(el, Roo.menu);
35928 if(el.render){ // some kind of Item
35929 item = this.addItem(el);
35930 }else if(typeof el == "string"){ // string
35931 if(el == "separator" || el == "-"){
35932 item = this.addSeparator();
35934 item = this.addText(el);
35936 }else if(el.tagName || el.el){ // element
35937 item = this.addElement(el);
35938 }else if(typeof el == "object"){ // must be menu item config?
35939 item = this.addMenuItem(el);
35946 * Returns this menu's underlying {@link Roo.Element} object
35947 * @return {Roo.Element} The element
35949 getEl : function(){
35957 * Adds a separator bar to the menu
35958 * @return {Roo.menu.Item} The menu item that was added
35960 addSeparator : function(){
35961 return this.addItem(new Roo.menu.Separator());
35965 * Adds an {@link Roo.Element} object to the menu
35966 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35967 * @return {Roo.menu.Item} The menu item that was added
35969 addElement : function(el){
35970 return this.addItem(new Roo.menu.BaseItem(el));
35974 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35975 * @param {Roo.menu.Item} item The menu item to add
35976 * @return {Roo.menu.Item} The menu item that was added
35978 addItem : function(item){
35979 this.items.add(item);
35981 var li = document.createElement("li");
35982 li.className = "x-menu-list-item";
35983 this.ul.dom.appendChild(li);
35984 item.render(li, this);
35985 this.delayAutoWidth();
35991 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35992 * @param {Object} config A MenuItem config object
35993 * @return {Roo.menu.Item} The menu item that was added
35995 addMenuItem : function(config){
35996 if(!(config instanceof Roo.menu.Item)){
35997 if(typeof config.checked == "boolean"){ // must be check menu item config?
35998 config = new Roo.menu.CheckItem(config);
36000 config = new Roo.menu.Item(config);
36003 return this.addItem(config);
36007 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36008 * @param {String} text The text to display in the menu item
36009 * @return {Roo.menu.Item} The menu item that was added
36011 addText : function(text){
36012 return this.addItem(new Roo.menu.TextItem({ text : text }));
36016 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36017 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36018 * @param {Roo.menu.Item} item The menu item to add
36019 * @return {Roo.menu.Item} The menu item that was added
36021 insert : function(index, item){
36022 this.items.insert(index, item);
36024 var li = document.createElement("li");
36025 li.className = "x-menu-list-item";
36026 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36027 item.render(li, this);
36028 this.delayAutoWidth();
36034 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36035 * @param {Roo.menu.Item} item The menu item to remove
36037 remove : function(item){
36038 this.items.removeKey(item.id);
36043 * Removes and destroys all items in the menu
36045 removeAll : function(){
36047 while(f = this.items.first()){
36053 // MenuNav is a private utility class used internally by the Menu
36054 Roo.menu.MenuNav = function(menu){
36055 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36056 this.scope = this.menu = menu;
36059 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36060 doRelay : function(e, h){
36061 var k = e.getKey();
36062 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36063 this.menu.tryActivate(0, 1);
36066 return h.call(this.scope || this, e, this.menu);
36069 up : function(e, m){
36070 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36071 m.tryActivate(m.items.length-1, -1);
36075 down : function(e, m){
36076 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36077 m.tryActivate(0, 1);
36081 right : function(e, m){
36083 m.activeItem.expandMenu(true);
36087 left : function(e, m){
36089 if(m.parentMenu && m.parentMenu.activeItem){
36090 m.parentMenu.activeItem.activate();
36094 enter : function(e, m){
36096 e.stopPropagation();
36097 m.activeItem.onClick(e);
36098 m.fireEvent("click", this, m.activeItem);
36104 * Ext JS Library 1.1.1
36105 * Copyright(c) 2006-2007, Ext JS, LLC.
36107 * Originally Released Under LGPL - original licence link has changed is not relivant.
36110 * <script type="text/javascript">
36114 * @class Roo.menu.MenuMgr
36115 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36118 Roo.menu.MenuMgr = function(){
36119 var menus, active, groups = {}, attached = false, lastShow = new Date();
36121 // private - called when first menu is created
36124 active = new Roo.util.MixedCollection();
36125 Roo.get(document).addKeyListener(27, function(){
36126 if(active.length > 0){
36133 function hideAll(){
36134 if(active && active.length > 0){
36135 var c = active.clone();
36136 c.each(function(m){
36143 function onHide(m){
36145 if(active.length < 1){
36146 Roo.get(document).un("mousedown", onMouseDown);
36152 function onShow(m){
36153 var last = active.last();
36154 lastShow = new Date();
36157 Roo.get(document).on("mousedown", onMouseDown);
36161 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36162 m.parentMenu.activeChild = m;
36163 }else if(last && last.isVisible()){
36164 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36169 function onBeforeHide(m){
36171 m.activeChild.hide();
36173 if(m.autoHideTimer){
36174 clearTimeout(m.autoHideTimer);
36175 delete m.autoHideTimer;
36180 function onBeforeShow(m){
36181 var pm = m.parentMenu;
36182 if(!pm && !m.allowOtherMenus){
36184 }else if(pm && pm.activeChild && active != m){
36185 pm.activeChild.hide();
36190 function onMouseDown(e){
36191 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36197 function onBeforeCheck(mi, state){
36199 var g = groups[mi.group];
36200 for(var i = 0, l = g.length; i < l; i++){
36202 g[i].setChecked(false);
36211 * Hides all menus that are currently visible
36213 hideAll : function(){
36218 register : function(menu){
36222 menus[menu.id] = menu;
36223 menu.on("beforehide", onBeforeHide);
36224 menu.on("hide", onHide);
36225 menu.on("beforeshow", onBeforeShow);
36226 menu.on("show", onShow);
36227 var g = menu.group;
36228 if(g && menu.events["checkchange"]){
36232 groups[g].push(menu);
36233 menu.on("checkchange", onCheck);
36238 * Returns a {@link Roo.menu.Menu} object
36239 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36240 * be used to generate and return a new Menu instance.
36242 get : function(menu){
36243 if(typeof menu == "string"){ // menu id
36244 return menus[menu];
36245 }else if(menu.events){ // menu instance
36247 }else if(typeof menu.length == 'number'){ // array of menu items?
36248 return new Roo.menu.Menu({items:menu});
36249 }else{ // otherwise, must be a config
36250 return new Roo.menu.Menu(menu);
36255 unregister : function(menu){
36256 delete menus[menu.id];
36257 menu.un("beforehide", onBeforeHide);
36258 menu.un("hide", onHide);
36259 menu.un("beforeshow", onBeforeShow);
36260 menu.un("show", onShow);
36261 var g = menu.group;
36262 if(g && menu.events["checkchange"]){
36263 groups[g].remove(menu);
36264 menu.un("checkchange", onCheck);
36269 registerCheckable : function(menuItem){
36270 var g = menuItem.group;
36275 groups[g].push(menuItem);
36276 menuItem.on("beforecheckchange", onBeforeCheck);
36281 unregisterCheckable : function(menuItem){
36282 var g = menuItem.group;
36284 groups[g].remove(menuItem);
36285 menuItem.un("beforecheckchange", onBeforeCheck);
36291 * Ext JS Library 1.1.1
36292 * Copyright(c) 2006-2007, Ext JS, LLC.
36294 * Originally Released Under LGPL - original licence link has changed is not relivant.
36297 * <script type="text/javascript">
36302 * @class Roo.menu.BaseItem
36303 * @extends Roo.Component
36304 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36305 * management and base configuration options shared by all menu components.
36307 * Creates a new BaseItem
36308 * @param {Object} config Configuration options
36310 Roo.menu.BaseItem = function(config){
36311 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36316 * Fires when this item is clicked
36317 * @param {Roo.menu.BaseItem} this
36318 * @param {Roo.EventObject} e
36323 * Fires when this item is activated
36324 * @param {Roo.menu.BaseItem} this
36328 * @event deactivate
36329 * Fires when this item is deactivated
36330 * @param {Roo.menu.BaseItem} this
36336 this.on("click", this.handler, this.scope, true);
36340 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36342 * @cfg {Function} handler
36343 * A function that will handle the click event of this menu item (defaults to undefined)
36346 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36348 canActivate : false,
36351 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36356 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36358 activeClass : "x-menu-item-active",
36360 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36362 hideOnClick : true,
36364 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36369 ctype: "Roo.menu.BaseItem",
36372 actionMode : "container",
36375 render : function(container, parentMenu){
36376 this.parentMenu = parentMenu;
36377 Roo.menu.BaseItem.superclass.render.call(this, container);
36378 this.container.menuItemId = this.id;
36382 onRender : function(container, position){
36383 this.el = Roo.get(this.el);
36384 container.dom.appendChild(this.el.dom);
36388 onClick : function(e){
36389 if(!this.disabled && this.fireEvent("click", this, e) !== false
36390 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36391 this.handleClick(e);
36398 activate : function(){
36402 var li = this.container;
36403 li.addClass(this.activeClass);
36404 this.region = li.getRegion().adjust(2, 2, -2, -2);
36405 this.fireEvent("activate", this);
36410 deactivate : function(){
36411 this.container.removeClass(this.activeClass);
36412 this.fireEvent("deactivate", this);
36416 shouldDeactivate : function(e){
36417 return !this.region || !this.region.contains(e.getPoint());
36421 handleClick : function(e){
36422 if(this.hideOnClick){
36423 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36428 expandMenu : function(autoActivate){
36433 hideMenu : function(){
36438 * Ext JS Library 1.1.1
36439 * Copyright(c) 2006-2007, Ext JS, LLC.
36441 * Originally Released Under LGPL - original licence link has changed is not relivant.
36444 * <script type="text/javascript">
36448 * @class Roo.menu.Adapter
36449 * @extends Roo.menu.BaseItem
36450 * 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.
36451 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36453 * Creates a new Adapter
36454 * @param {Object} config Configuration options
36456 Roo.menu.Adapter = function(component, config){
36457 Roo.menu.Adapter.superclass.constructor.call(this, config);
36458 this.component = component;
36460 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36462 canActivate : true,
36465 onRender : function(container, position){
36466 this.component.render(container);
36467 this.el = this.component.getEl();
36471 activate : function(){
36475 this.component.focus();
36476 this.fireEvent("activate", this);
36481 deactivate : function(){
36482 this.fireEvent("deactivate", this);
36486 disable : function(){
36487 this.component.disable();
36488 Roo.menu.Adapter.superclass.disable.call(this);
36492 enable : function(){
36493 this.component.enable();
36494 Roo.menu.Adapter.superclass.enable.call(this);
36498 * Ext JS Library 1.1.1
36499 * Copyright(c) 2006-2007, Ext JS, LLC.
36501 * Originally Released Under LGPL - original licence link has changed is not relivant.
36504 * <script type="text/javascript">
36508 * @class Roo.menu.TextItem
36509 * @extends Roo.menu.BaseItem
36510 * Adds a static text string to a menu, usually used as either a heading or group separator.
36511 * Note: old style constructor with text is still supported.
36514 * Creates a new TextItem
36515 * @param {Object} cfg Configuration
36517 Roo.menu.TextItem = function(cfg){
36518 if (typeof(cfg) == 'string') {
36521 Roo.apply(this,cfg);
36524 Roo.menu.TextItem.superclass.constructor.call(this);
36527 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36529 * @cfg {Boolean} text Text to show on item.
36534 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36536 hideOnClick : false,
36538 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36540 itemCls : "x-menu-text",
36543 onRender : function(){
36544 var s = document.createElement("span");
36545 s.className = this.itemCls;
36546 s.innerHTML = this.text;
36548 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36552 * Ext JS Library 1.1.1
36553 * Copyright(c) 2006-2007, Ext JS, LLC.
36555 * Originally Released Under LGPL - original licence link has changed is not relivant.
36558 * <script type="text/javascript">
36562 * @class Roo.menu.Separator
36563 * @extends Roo.menu.BaseItem
36564 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36565 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36567 * @param {Object} config Configuration options
36569 Roo.menu.Separator = function(config){
36570 Roo.menu.Separator.superclass.constructor.call(this, config);
36573 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36575 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36577 itemCls : "x-menu-sep",
36579 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36581 hideOnClick : false,
36584 onRender : function(li){
36585 var s = document.createElement("span");
36586 s.className = this.itemCls;
36587 s.innerHTML = " ";
36589 li.addClass("x-menu-sep-li");
36590 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36594 * Ext JS Library 1.1.1
36595 * Copyright(c) 2006-2007, Ext JS, LLC.
36597 * Originally Released Under LGPL - original licence link has changed is not relivant.
36600 * <script type="text/javascript">
36603 * @class Roo.menu.Item
36604 * @extends Roo.menu.BaseItem
36605 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36606 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36607 * activation and click handling.
36609 * Creates a new Item
36610 * @param {Object} config Configuration options
36612 Roo.menu.Item = function(config){
36613 Roo.menu.Item.superclass.constructor.call(this, config);
36615 this.menu = Roo.menu.MenuMgr.get(this.menu);
36618 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36621 * @cfg {String} text
36622 * The text to show on the menu item.
36626 * @cfg {String} HTML to render in menu
36627 * The text to show on the menu item (HTML version).
36631 * @cfg {String} icon
36632 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36636 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36638 itemCls : "x-menu-item",
36640 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36642 canActivate : true,
36644 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36647 // doc'd in BaseItem
36651 ctype: "Roo.menu.Item",
36654 onRender : function(container, position){
36655 var el = document.createElement("a");
36656 el.hideFocus = true;
36657 el.unselectable = "on";
36658 el.href = this.href || "#";
36659 if(this.hrefTarget){
36660 el.target = this.hrefTarget;
36662 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36664 var html = this.html.length ? this.html : String.format('{0}',this.text);
36666 el.innerHTML = String.format(
36667 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36668 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36670 Roo.menu.Item.superclass.onRender.call(this, container, position);
36674 * Sets the text to display in this menu item
36675 * @param {String} text The text to display
36676 * @param {Boolean} isHTML true to indicate text is pure html.
36678 setText : function(text, isHTML){
36686 var html = this.html.length ? this.html : String.format('{0}',this.text);
36688 this.el.update(String.format(
36689 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36690 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36691 this.parentMenu.autoWidth();
36696 handleClick : function(e){
36697 if(!this.href){ // if no link defined, stop the event automatically
36700 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36704 activate : function(autoExpand){
36705 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36715 shouldDeactivate : function(e){
36716 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36717 if(this.menu && this.menu.isVisible()){
36718 return !this.menu.getEl().getRegion().contains(e.getPoint());
36726 deactivate : function(){
36727 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36732 expandMenu : function(autoActivate){
36733 if(!this.disabled && this.menu){
36734 clearTimeout(this.hideTimer);
36735 delete this.hideTimer;
36736 if(!this.menu.isVisible() && !this.showTimer){
36737 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36738 }else if (this.menu.isVisible() && autoActivate){
36739 this.menu.tryActivate(0, 1);
36745 deferExpand : function(autoActivate){
36746 delete this.showTimer;
36747 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36749 this.menu.tryActivate(0, 1);
36754 hideMenu : function(){
36755 clearTimeout(this.showTimer);
36756 delete this.showTimer;
36757 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36758 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36763 deferHide : function(){
36764 delete this.hideTimer;
36769 * Ext JS Library 1.1.1
36770 * Copyright(c) 2006-2007, Ext JS, LLC.
36772 * Originally Released Under LGPL - original licence link has changed is not relivant.
36775 * <script type="text/javascript">
36779 * @class Roo.menu.CheckItem
36780 * @extends Roo.menu.Item
36781 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36783 * Creates a new CheckItem
36784 * @param {Object} config Configuration options
36786 Roo.menu.CheckItem = function(config){
36787 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36790 * @event beforecheckchange
36791 * Fires before the checked value is set, providing an opportunity to cancel if needed
36792 * @param {Roo.menu.CheckItem} this
36793 * @param {Boolean} checked The new checked value that will be set
36795 "beforecheckchange" : true,
36797 * @event checkchange
36798 * Fires after the checked value has been set
36799 * @param {Roo.menu.CheckItem} this
36800 * @param {Boolean} checked The checked value that was set
36802 "checkchange" : true
36804 if(this.checkHandler){
36805 this.on('checkchange', this.checkHandler, this.scope);
36808 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36810 * @cfg {String} group
36811 * All check items with the same group name will automatically be grouped into a single-select
36812 * radio button group (defaults to '')
36815 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36817 itemCls : "x-menu-item x-menu-check-item",
36819 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36821 groupClass : "x-menu-group-item",
36824 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36825 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36826 * initialized with checked = true will be rendered as checked.
36831 ctype: "Roo.menu.CheckItem",
36834 onRender : function(c){
36835 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36837 this.el.addClass(this.groupClass);
36839 Roo.menu.MenuMgr.registerCheckable(this);
36841 this.checked = false;
36842 this.setChecked(true, true);
36847 destroy : function(){
36849 Roo.menu.MenuMgr.unregisterCheckable(this);
36851 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36855 * Set the checked state of this item
36856 * @param {Boolean} checked The new checked value
36857 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36859 setChecked : function(state, suppressEvent){
36860 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36861 if(this.container){
36862 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36864 this.checked = state;
36865 if(suppressEvent !== true){
36866 this.fireEvent("checkchange", this, state);
36872 handleClick : function(e){
36873 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36874 this.setChecked(!this.checked);
36876 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36880 * Ext JS Library 1.1.1
36881 * Copyright(c) 2006-2007, Ext JS, LLC.
36883 * Originally Released Under LGPL - original licence link has changed is not relivant.
36886 * <script type="text/javascript">
36890 * @class Roo.menu.DateItem
36891 * @extends Roo.menu.Adapter
36892 * A menu item that wraps the {@link Roo.DatPicker} component.
36894 * Creates a new DateItem
36895 * @param {Object} config Configuration options
36897 Roo.menu.DateItem = function(config){
36898 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36899 /** The Roo.DatePicker object @type Roo.DatePicker */
36900 this.picker = this.component;
36901 this.addEvents({select: true});
36903 this.picker.on("render", function(picker){
36904 picker.getEl().swallowEvent("click");
36905 picker.container.addClass("x-menu-date-item");
36908 this.picker.on("select", this.onSelect, this);
36911 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36913 onSelect : function(picker, date){
36914 this.fireEvent("select", this, date, picker);
36915 Roo.menu.DateItem.superclass.handleClick.call(this);
36919 * Ext JS Library 1.1.1
36920 * Copyright(c) 2006-2007, Ext JS, LLC.
36922 * Originally Released Under LGPL - original licence link has changed is not relivant.
36925 * <script type="text/javascript">
36929 * @class Roo.menu.ColorItem
36930 * @extends Roo.menu.Adapter
36931 * A menu item that wraps the {@link Roo.ColorPalette} component.
36933 * Creates a new ColorItem
36934 * @param {Object} config Configuration options
36936 Roo.menu.ColorItem = function(config){
36937 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36938 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36939 this.palette = this.component;
36940 this.relayEvents(this.palette, ["select"]);
36941 if(this.selectHandler){
36942 this.on('select', this.selectHandler, this.scope);
36945 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36947 * Ext JS Library 1.1.1
36948 * Copyright(c) 2006-2007, Ext JS, LLC.
36950 * Originally Released Under LGPL - original licence link has changed is not relivant.
36953 * <script type="text/javascript">
36958 * @class Roo.menu.DateMenu
36959 * @extends Roo.menu.Menu
36960 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36962 * Creates a new DateMenu
36963 * @param {Object} config Configuration options
36965 Roo.menu.DateMenu = function(config){
36966 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36968 var di = new Roo.menu.DateItem(config);
36971 * The {@link Roo.DatePicker} instance for this DateMenu
36974 this.picker = di.picker;
36977 * @param {DatePicker} picker
36978 * @param {Date} date
36980 this.relayEvents(di, ["select"]);
36981 this.on('beforeshow', function(){
36983 this.picker.hideMonthPicker(false);
36987 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36991 * Ext JS Library 1.1.1
36992 * Copyright(c) 2006-2007, Ext JS, LLC.
36994 * Originally Released Under LGPL - original licence link has changed is not relivant.
36997 * <script type="text/javascript">
37002 * @class Roo.menu.ColorMenu
37003 * @extends Roo.menu.Menu
37004 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37006 * Creates a new ColorMenu
37007 * @param {Object} config Configuration options
37009 Roo.menu.ColorMenu = function(config){
37010 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37012 var ci = new Roo.menu.ColorItem(config);
37015 * The {@link Roo.ColorPalette} instance for this ColorMenu
37016 * @type ColorPalette
37018 this.palette = ci.palette;
37021 * @param {ColorPalette} palette
37022 * @param {String} color
37024 this.relayEvents(ci, ["select"]);
37026 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37028 * Ext JS Library 1.1.1
37029 * Copyright(c) 2006-2007, Ext JS, LLC.
37031 * Originally Released Under LGPL - original licence link has changed is not relivant.
37034 * <script type="text/javascript">
37038 * @class Roo.form.Field
37039 * @extends Roo.BoxComponent
37040 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37042 * Creates a new Field
37043 * @param {Object} config Configuration options
37045 Roo.form.Field = function(config){
37046 Roo.form.Field.superclass.constructor.call(this, config);
37049 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37051 * @cfg {String} fieldLabel Label to use when rendering a form.
37054 * @cfg {String} qtip Mouse over tip
37058 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37060 invalidClass : "x-form-invalid",
37062 * @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")
37064 invalidText : "The value in this field is invalid",
37066 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37068 focusClass : "x-form-focus",
37070 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37071 automatic validation (defaults to "keyup").
37073 validationEvent : "keyup",
37075 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37077 validateOnBlur : true,
37079 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37081 validationDelay : 250,
37083 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37084 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37086 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37088 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37090 fieldClass : "x-form-field",
37092 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37095 ----------- ----------------------------------------------------------------------
37096 qtip Display a quick tip when the user hovers over the field
37097 title Display a default browser title attribute popup
37098 under Add a block div beneath the field containing the error text
37099 side Add an error icon to the right of the field with a popup on hover
37100 [element id] Add the error text directly to the innerHTML of the specified element
37103 msgTarget : 'qtip',
37105 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37110 * @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.
37115 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37120 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37122 inputType : undefined,
37125 * @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).
37127 tabIndex : undefined,
37130 isFormField : true,
37135 * @property {Roo.Element} fieldEl
37136 * Element Containing the rendered Field (with label etc.)
37139 * @cfg {Mixed} value A value to initialize this field with.
37144 * @cfg {String} name The field's HTML name attribute.
37147 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37151 initComponent : function(){
37152 Roo.form.Field.superclass.initComponent.call(this);
37156 * Fires when this field receives input focus.
37157 * @param {Roo.form.Field} this
37162 * Fires when this field loses input focus.
37163 * @param {Roo.form.Field} this
37167 * @event specialkey
37168 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37169 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37170 * @param {Roo.form.Field} this
37171 * @param {Roo.EventObject} e The event object
37176 * Fires just before the field blurs if the field value has changed.
37177 * @param {Roo.form.Field} this
37178 * @param {Mixed} newValue The new value
37179 * @param {Mixed} oldValue The original value
37184 * Fires after the field has been marked as invalid.
37185 * @param {Roo.form.Field} this
37186 * @param {String} msg The validation message
37191 * Fires after the field has been validated with no errors.
37192 * @param {Roo.form.Field} this
37197 * Fires after the key up
37198 * @param {Roo.form.Field} this
37199 * @param {Roo.EventObject} e The event Object
37206 * Returns the name attribute of the field if available
37207 * @return {String} name The field name
37209 getName: function(){
37210 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37214 onRender : function(ct, position){
37215 Roo.form.Field.superclass.onRender.call(this, ct, position);
37217 var cfg = this.getAutoCreate();
37219 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37221 if (!cfg.name.length) {
37224 if(this.inputType){
37225 cfg.type = this.inputType;
37227 this.el = ct.createChild(cfg, position);
37229 var type = this.el.dom.type;
37231 if(type == 'password'){
37234 this.el.addClass('x-form-'+type);
37237 this.el.dom.readOnly = true;
37239 if(this.tabIndex !== undefined){
37240 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37243 this.el.addClass([this.fieldClass, this.cls]);
37248 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37249 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37250 * @return {Roo.form.Field} this
37252 applyTo : function(target){
37253 this.allowDomMove = false;
37254 this.el = Roo.get(target);
37255 this.render(this.el.dom.parentNode);
37260 initValue : function(){
37261 if(this.value !== undefined){
37262 this.setValue(this.value);
37263 }else if(this.el.dom.value.length > 0){
37264 this.setValue(this.el.dom.value);
37269 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37271 isDirty : function() {
37272 if(this.disabled) {
37275 return String(this.getValue()) !== String(this.originalValue);
37279 afterRender : function(){
37280 Roo.form.Field.superclass.afterRender.call(this);
37285 fireKey : function(e){
37286 //Roo.log('field ' + e.getKey());
37287 if(e.isNavKeyPress()){
37288 this.fireEvent("specialkey", this, e);
37293 * Resets the current field value to the originally loaded value and clears any validation messages
37295 reset : function(){
37296 this.setValue(this.resetValue);
37297 this.clearInvalid();
37301 initEvents : function(){
37302 // safari killled keypress - so keydown is now used..
37303 this.el.on("keydown" , this.fireKey, this);
37304 this.el.on("focus", this.onFocus, this);
37305 this.el.on("blur", this.onBlur, this);
37306 this.el.relayEvent('keyup', this);
37308 // reference to original value for reset
37309 this.originalValue = this.getValue();
37310 this.resetValue = this.getValue();
37314 onFocus : function(){
37315 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37316 this.el.addClass(this.focusClass);
37318 if(!this.hasFocus){
37319 this.hasFocus = true;
37320 this.startValue = this.getValue();
37321 this.fireEvent("focus", this);
37325 beforeBlur : Roo.emptyFn,
37328 onBlur : function(){
37330 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37331 this.el.removeClass(this.focusClass);
37333 this.hasFocus = false;
37334 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37337 var v = this.getValue();
37338 if(String(v) !== String(this.startValue)){
37339 this.fireEvent('change', this, v, this.startValue);
37341 this.fireEvent("blur", this);
37345 * Returns whether or not the field value is currently valid
37346 * @param {Boolean} preventMark True to disable marking the field invalid
37347 * @return {Boolean} True if the value is valid, else false
37349 isValid : function(preventMark){
37353 var restore = this.preventMark;
37354 this.preventMark = preventMark === true;
37355 var v = this.validateValue(this.processValue(this.getRawValue()));
37356 this.preventMark = restore;
37361 * Validates the field value
37362 * @return {Boolean} True if the value is valid, else false
37364 validate : function(){
37365 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37366 this.clearInvalid();
37372 processValue : function(value){
37377 // Subclasses should provide the validation implementation by overriding this
37378 validateValue : function(value){
37383 * Mark this field as invalid
37384 * @param {String} msg The validation message
37386 markInvalid : function(msg){
37387 if(!this.rendered || this.preventMark){ // not rendered
37391 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37393 obj.el.addClass(this.invalidClass);
37394 msg = msg || this.invalidText;
37395 switch(this.msgTarget){
37397 obj.el.dom.qtip = msg;
37398 obj.el.dom.qclass = 'x-form-invalid-tip';
37399 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37400 Roo.QuickTips.enable();
37404 this.el.dom.title = msg;
37408 var elp = this.el.findParent('.x-form-element', 5, true);
37409 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37410 this.errorEl.setWidth(elp.getWidth(true)-20);
37412 this.errorEl.update(msg);
37413 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37416 if(!this.errorIcon){
37417 var elp = this.el.findParent('.x-form-element', 5, true);
37418 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37420 this.alignErrorIcon();
37421 this.errorIcon.dom.qtip = msg;
37422 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37423 this.errorIcon.show();
37424 this.on('resize', this.alignErrorIcon, this);
37427 var t = Roo.getDom(this.msgTarget);
37429 t.style.display = this.msgDisplay;
37432 this.fireEvent('invalid', this, msg);
37436 alignErrorIcon : function(){
37437 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37441 * Clear any invalid styles/messages for this field
37443 clearInvalid : function(){
37444 if(!this.rendered || this.preventMark){ // not rendered
37447 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37449 obj.el.removeClass(this.invalidClass);
37450 switch(this.msgTarget){
37452 obj.el.dom.qtip = '';
37455 this.el.dom.title = '';
37459 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37463 if(this.errorIcon){
37464 this.errorIcon.dom.qtip = '';
37465 this.errorIcon.hide();
37466 this.un('resize', this.alignErrorIcon, this);
37470 var t = Roo.getDom(this.msgTarget);
37472 t.style.display = 'none';
37475 this.fireEvent('valid', this);
37479 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37480 * @return {Mixed} value The field value
37482 getRawValue : function(){
37483 var v = this.el.getValue();
37489 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37490 * @return {Mixed} value The field value
37492 getValue : function(){
37493 var v = this.el.getValue();
37499 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37500 * @param {Mixed} value The value to set
37502 setRawValue : function(v){
37503 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37507 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37508 * @param {Mixed} value The value to set
37510 setValue : function(v){
37513 this.el.dom.value = (v === null || v === undefined ? '' : v);
37518 adjustSize : function(w, h){
37519 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37520 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37524 adjustWidth : function(tag, w){
37525 tag = tag.toLowerCase();
37526 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37527 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37528 if(tag == 'input'){
37531 if(tag == 'textarea'){
37534 }else if(Roo.isOpera){
37535 if(tag == 'input'){
37538 if(tag == 'textarea'){
37548 // anything other than normal should be considered experimental
37549 Roo.form.Field.msgFx = {
37551 show: function(msgEl, f){
37552 msgEl.setDisplayed('block');
37555 hide : function(msgEl, f){
37556 msgEl.setDisplayed(false).update('');
37561 show: function(msgEl, f){
37562 msgEl.slideIn('t', {stopFx:true});
37565 hide : function(msgEl, f){
37566 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37571 show: function(msgEl, f){
37572 msgEl.fixDisplay();
37573 msgEl.alignTo(f.el, 'tl-tr');
37574 msgEl.slideIn('l', {stopFx:true});
37577 hide : function(msgEl, f){
37578 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37583 * Ext JS Library 1.1.1
37584 * Copyright(c) 2006-2007, Ext JS, LLC.
37586 * Originally Released Under LGPL - original licence link has changed is not relivant.
37589 * <script type="text/javascript">
37594 * @class Roo.form.TextField
37595 * @extends Roo.form.Field
37596 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37597 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37599 * Creates a new TextField
37600 * @param {Object} config Configuration options
37602 Roo.form.TextField = function(config){
37603 Roo.form.TextField.superclass.constructor.call(this, config);
37607 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37608 * according to the default logic, but this event provides a hook for the developer to apply additional
37609 * logic at runtime to resize the field if needed.
37610 * @param {Roo.form.Field} this This text field
37611 * @param {Number} width The new field width
37617 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37619 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37623 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37627 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37631 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37635 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37639 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37641 disableKeyFilter : false,
37643 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37647 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37651 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37653 maxLength : Number.MAX_VALUE,
37655 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37657 minLengthText : "The minimum length for this field is {0}",
37659 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37661 maxLengthText : "The maximum length for this field is {0}",
37663 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37665 selectOnFocus : false,
37667 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37669 blankText : "This field is required",
37671 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37672 * If available, this function will be called only after the basic validators all return true, and will be passed the
37673 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37677 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37678 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37679 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37683 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37687 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37693 initEvents : function()
37695 if (this.emptyText) {
37696 this.el.attr('placeholder', this.emptyText);
37699 Roo.form.TextField.superclass.initEvents.call(this);
37700 if(this.validationEvent == 'keyup'){
37701 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37702 this.el.on('keyup', this.filterValidation, this);
37704 else if(this.validationEvent !== false){
37705 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37708 if(this.selectOnFocus){
37709 this.on("focus", this.preFocus, this);
37712 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37713 this.el.on("keypress", this.filterKeys, this);
37716 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37717 this.el.on("click", this.autoSize, this);
37719 if(this.el.is('input[type=password]') && Roo.isSafari){
37720 this.el.on('keydown', this.SafariOnKeyDown, this);
37724 processValue : function(value){
37725 if(this.stripCharsRe){
37726 var newValue = value.replace(this.stripCharsRe, '');
37727 if(newValue !== value){
37728 this.setRawValue(newValue);
37735 filterValidation : function(e){
37736 if(!e.isNavKeyPress()){
37737 this.validationTask.delay(this.validationDelay);
37742 onKeyUp : function(e){
37743 if(!e.isNavKeyPress()){
37749 * Resets the current field value to the originally-loaded value and clears any validation messages.
37752 reset : function(){
37753 Roo.form.TextField.superclass.reset.call(this);
37759 preFocus : function(){
37761 if(this.selectOnFocus){
37762 this.el.dom.select();
37768 filterKeys : function(e){
37769 var k = e.getKey();
37770 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37773 var c = e.getCharCode(), cc = String.fromCharCode(c);
37774 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37777 if(!this.maskRe.test(cc)){
37782 setValue : function(v){
37784 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37790 * Validates a value according to the field's validation rules and marks the field as invalid
37791 * if the validation fails
37792 * @param {Mixed} value The value to validate
37793 * @return {Boolean} True if the value is valid, else false
37795 validateValue : function(value){
37796 if(value.length < 1) { // if it's blank
37797 if(this.allowBlank){
37798 this.clearInvalid();
37801 this.markInvalid(this.blankText);
37805 if(value.length < this.minLength){
37806 this.markInvalid(String.format(this.minLengthText, this.minLength));
37809 if(value.length > this.maxLength){
37810 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37814 var vt = Roo.form.VTypes;
37815 if(!vt[this.vtype](value, this)){
37816 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37820 if(typeof this.validator == "function"){
37821 var msg = this.validator(value);
37823 this.markInvalid(msg);
37827 if(this.regex && !this.regex.test(value)){
37828 this.markInvalid(this.regexText);
37835 * Selects text in this field
37836 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37837 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37839 selectText : function(start, end){
37840 var v = this.getRawValue();
37842 start = start === undefined ? 0 : start;
37843 end = end === undefined ? v.length : end;
37844 var d = this.el.dom;
37845 if(d.setSelectionRange){
37846 d.setSelectionRange(start, end);
37847 }else if(d.createTextRange){
37848 var range = d.createTextRange();
37849 range.moveStart("character", start);
37850 range.moveEnd("character", v.length-end);
37857 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37858 * This only takes effect if grow = true, and fires the autosize event.
37860 autoSize : function(){
37861 if(!this.grow || !this.rendered){
37865 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37868 var v = el.dom.value;
37869 var d = document.createElement('div');
37870 d.appendChild(document.createTextNode(v));
37874 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37875 this.el.setWidth(w);
37876 this.fireEvent("autosize", this, w);
37880 SafariOnKeyDown : function(event)
37882 // this is a workaround for a password hang bug on chrome/ webkit.
37884 var isSelectAll = false;
37886 if(this.el.dom.selectionEnd > 0){
37887 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37889 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37890 event.preventDefault();
37895 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37897 event.preventDefault();
37898 // this is very hacky as keydown always get's upper case.
37900 var cc = String.fromCharCode(event.getCharCode());
37903 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37911 * Ext JS Library 1.1.1
37912 * Copyright(c) 2006-2007, Ext JS, LLC.
37914 * Originally Released Under LGPL - original licence link has changed is not relivant.
37917 * <script type="text/javascript">
37921 * @class Roo.form.Hidden
37922 * @extends Roo.form.TextField
37923 * Simple Hidden element used on forms
37925 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37928 * Creates a new Hidden form element.
37929 * @param {Object} config Configuration options
37934 // easy hidden field...
37935 Roo.form.Hidden = function(config){
37936 Roo.form.Hidden.superclass.constructor.call(this, config);
37939 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37941 inputType: 'hidden',
37944 labelSeparator: '',
37946 itemCls : 'x-form-item-display-none'
37954 * Ext JS Library 1.1.1
37955 * Copyright(c) 2006-2007, Ext JS, LLC.
37957 * Originally Released Under LGPL - original licence link has changed is not relivant.
37960 * <script type="text/javascript">
37964 * @class Roo.form.TriggerField
37965 * @extends Roo.form.TextField
37966 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37967 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37968 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37969 * for which you can provide a custom implementation. For example:
37971 var trigger = new Roo.form.TriggerField();
37972 trigger.onTriggerClick = myTriggerFn;
37973 trigger.applyTo('my-field');
37976 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37977 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37978 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37979 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37981 * Create a new TriggerField.
37982 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37983 * to the base TextField)
37985 Roo.form.TriggerField = function(config){
37986 this.mimicing = false;
37987 Roo.form.TriggerField.superclass.constructor.call(this, config);
37990 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37992 * @cfg {String} triggerClass A CSS class to apply to the trigger
37995 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37996 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37998 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38000 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38004 /** @cfg {Boolean} grow @hide */
38005 /** @cfg {Number} growMin @hide */
38006 /** @cfg {Number} growMax @hide */
38012 autoSize: Roo.emptyFn,
38016 deferHeight : true,
38019 actionMode : 'wrap',
38021 onResize : function(w, h){
38022 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38023 if(typeof w == 'number'){
38024 var x = w - this.trigger.getWidth();
38025 this.el.setWidth(this.adjustWidth('input', x));
38026 this.trigger.setStyle('left', x+'px');
38031 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38034 getResizeEl : function(){
38039 getPositionEl : function(){
38044 alignErrorIcon : function(){
38045 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38049 onRender : function(ct, position){
38050 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38051 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38052 this.trigger = this.wrap.createChild(this.triggerConfig ||
38053 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38054 if(this.hideTrigger){
38055 this.trigger.setDisplayed(false);
38057 this.initTrigger();
38059 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38064 initTrigger : function(){
38065 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38066 this.trigger.addClassOnOver('x-form-trigger-over');
38067 this.trigger.addClassOnClick('x-form-trigger-click');
38071 onDestroy : function(){
38073 this.trigger.removeAllListeners();
38074 this.trigger.remove();
38077 this.wrap.remove();
38079 Roo.form.TriggerField.superclass.onDestroy.call(this);
38083 onFocus : function(){
38084 Roo.form.TriggerField.superclass.onFocus.call(this);
38085 if(!this.mimicing){
38086 this.wrap.addClass('x-trigger-wrap-focus');
38087 this.mimicing = true;
38088 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38089 if(this.monitorTab){
38090 this.el.on("keydown", this.checkTab, this);
38096 checkTab : function(e){
38097 if(e.getKey() == e.TAB){
38098 this.triggerBlur();
38103 onBlur : function(){
38108 mimicBlur : function(e, t){
38109 if(!this.wrap.contains(t) && this.validateBlur()){
38110 this.triggerBlur();
38115 triggerBlur : function(){
38116 this.mimicing = false;
38117 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38118 if(this.monitorTab){
38119 this.el.un("keydown", this.checkTab, this);
38121 this.wrap.removeClass('x-trigger-wrap-focus');
38122 Roo.form.TriggerField.superclass.onBlur.call(this);
38126 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38127 validateBlur : function(e, t){
38132 onDisable : function(){
38133 Roo.form.TriggerField.superclass.onDisable.call(this);
38135 this.wrap.addClass('x-item-disabled');
38140 onEnable : function(){
38141 Roo.form.TriggerField.superclass.onEnable.call(this);
38143 this.wrap.removeClass('x-item-disabled');
38148 onShow : function(){
38149 var ae = this.getActionEl();
38152 ae.dom.style.display = '';
38153 ae.dom.style.visibility = 'visible';
38159 onHide : function(){
38160 var ae = this.getActionEl();
38161 ae.dom.style.display = 'none';
38165 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38166 * by an implementing function.
38168 * @param {EventObject} e
38170 onTriggerClick : Roo.emptyFn
38173 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38174 // to be extended by an implementing class. For an example of implementing this class, see the custom
38175 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38176 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38177 initComponent : function(){
38178 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38180 this.triggerConfig = {
38181 tag:'span', cls:'x-form-twin-triggers', cn:[
38182 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38183 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38187 getTrigger : function(index){
38188 return this.triggers[index];
38191 initTrigger : function(){
38192 var ts = this.trigger.select('.x-form-trigger', true);
38193 this.wrap.setStyle('overflow', 'hidden');
38194 var triggerField = this;
38195 ts.each(function(t, all, index){
38196 t.hide = function(){
38197 var w = triggerField.wrap.getWidth();
38198 this.dom.style.display = 'none';
38199 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38201 t.show = function(){
38202 var w = triggerField.wrap.getWidth();
38203 this.dom.style.display = '';
38204 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38206 var triggerIndex = 'Trigger'+(index+1);
38208 if(this['hide'+triggerIndex]){
38209 t.dom.style.display = 'none';
38211 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38212 t.addClassOnOver('x-form-trigger-over');
38213 t.addClassOnClick('x-form-trigger-click');
38215 this.triggers = ts.elements;
38218 onTrigger1Click : Roo.emptyFn,
38219 onTrigger2Click : Roo.emptyFn
38222 * Ext JS Library 1.1.1
38223 * Copyright(c) 2006-2007, Ext JS, LLC.
38225 * Originally Released Under LGPL - original licence link has changed is not relivant.
38228 * <script type="text/javascript">
38232 * @class Roo.form.TextArea
38233 * @extends Roo.form.TextField
38234 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38235 * support for auto-sizing.
38237 * Creates a new TextArea
38238 * @param {Object} config Configuration options
38240 Roo.form.TextArea = function(config){
38241 Roo.form.TextArea.superclass.constructor.call(this, config);
38242 // these are provided exchanges for backwards compat
38243 // minHeight/maxHeight were replaced by growMin/growMax to be
38244 // compatible with TextField growing config values
38245 if(this.minHeight !== undefined){
38246 this.growMin = this.minHeight;
38248 if(this.maxHeight !== undefined){
38249 this.growMax = this.maxHeight;
38253 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38255 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38259 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38263 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38264 * in the field (equivalent to setting overflow: hidden, defaults to false)
38266 preventScrollbars: false,
38268 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38269 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38273 onRender : function(ct, position){
38275 this.defaultAutoCreate = {
38277 style:"width:300px;height:60px;",
38278 autocomplete: "new-password"
38281 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38283 this.textSizeEl = Roo.DomHelper.append(document.body, {
38284 tag: "pre", cls: "x-form-grow-sizer"
38286 if(this.preventScrollbars){
38287 this.el.setStyle("overflow", "hidden");
38289 this.el.setHeight(this.growMin);
38293 onDestroy : function(){
38294 if(this.textSizeEl){
38295 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38297 Roo.form.TextArea.superclass.onDestroy.call(this);
38301 onKeyUp : function(e){
38302 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38308 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38309 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38311 autoSize : function(){
38312 if(!this.grow || !this.textSizeEl){
38316 var v = el.dom.value;
38317 var ts = this.textSizeEl;
38320 ts.appendChild(document.createTextNode(v));
38323 Roo.fly(ts).setWidth(this.el.getWidth());
38325 v = "  ";
38328 v = v.replace(/\n/g, '<p> </p>');
38330 v += " \n ";
38333 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38334 if(h != this.lastHeight){
38335 this.lastHeight = h;
38336 this.el.setHeight(h);
38337 this.fireEvent("autosize", this, h);
38342 * Ext JS Library 1.1.1
38343 * Copyright(c) 2006-2007, Ext JS, LLC.
38345 * Originally Released Under LGPL - original licence link has changed is not relivant.
38348 * <script type="text/javascript">
38353 * @class Roo.form.NumberField
38354 * @extends Roo.form.TextField
38355 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38357 * Creates a new NumberField
38358 * @param {Object} config Configuration options
38360 Roo.form.NumberField = function(config){
38361 Roo.form.NumberField.superclass.constructor.call(this, config);
38364 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38366 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38368 fieldClass: "x-form-field x-form-num-field",
38370 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38372 allowDecimals : true,
38374 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38376 decimalSeparator : ".",
38378 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38380 decimalPrecision : 2,
38382 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38384 allowNegative : true,
38386 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38388 minValue : Number.NEGATIVE_INFINITY,
38390 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38392 maxValue : Number.MAX_VALUE,
38394 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38396 minText : "The minimum value for this field is {0}",
38398 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38400 maxText : "The maximum value for this field is {0}",
38402 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38403 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38405 nanText : "{0} is not a valid number",
38408 initEvents : function(){
38409 Roo.form.NumberField.superclass.initEvents.call(this);
38410 var allowed = "0123456789";
38411 if(this.allowDecimals){
38412 allowed += this.decimalSeparator;
38414 if(this.allowNegative){
38417 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38418 var keyPress = function(e){
38419 var k = e.getKey();
38420 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38423 var c = e.getCharCode();
38424 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38428 this.el.on("keypress", keyPress, this);
38432 validateValue : function(value){
38433 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38436 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38439 var num = this.parseValue(value);
38441 this.markInvalid(String.format(this.nanText, value));
38444 if(num < this.minValue){
38445 this.markInvalid(String.format(this.minText, this.minValue));
38448 if(num > this.maxValue){
38449 this.markInvalid(String.format(this.maxText, this.maxValue));
38455 getValue : function(){
38456 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38460 parseValue : function(value){
38461 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38462 return isNaN(value) ? '' : value;
38466 fixPrecision : function(value){
38467 var nan = isNaN(value);
38468 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38469 return nan ? '' : value;
38471 return parseFloat(value).toFixed(this.decimalPrecision);
38474 setValue : function(v){
38475 v = this.fixPrecision(v);
38476 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38480 decimalPrecisionFcn : function(v){
38481 return Math.floor(v);
38484 beforeBlur : function(){
38485 var v = this.parseValue(this.getRawValue());
38492 * Ext JS Library 1.1.1
38493 * Copyright(c) 2006-2007, Ext JS, LLC.
38495 * Originally Released Under LGPL - original licence link has changed is not relivant.
38498 * <script type="text/javascript">
38502 * @class Roo.form.DateField
38503 * @extends Roo.form.TriggerField
38504 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38506 * Create a new DateField
38507 * @param {Object} config
38509 Roo.form.DateField = function(config){
38510 Roo.form.DateField.superclass.constructor.call(this, config);
38516 * Fires when a date is selected
38517 * @param {Roo.form.DateField} combo This combo box
38518 * @param {Date} date The date selected
38525 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38526 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38527 this.ddMatch = null;
38528 if(this.disabledDates){
38529 var dd = this.disabledDates;
38531 for(var i = 0; i < dd.length; i++){
38533 if(i != dd.length-1) re += "|";
38535 this.ddMatch = new RegExp(re + ")");
38539 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38541 * @cfg {String} format
38542 * The default date format string which can be overriden for localization support. The format must be
38543 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38547 * @cfg {String} altFormats
38548 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38549 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38551 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38553 * @cfg {Array} disabledDays
38554 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38556 disabledDays : null,
38558 * @cfg {String} disabledDaysText
38559 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38561 disabledDaysText : "Disabled",
38563 * @cfg {Array} disabledDates
38564 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38565 * expression so they are very powerful. Some examples:
38567 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38568 * <li>["03/08", "09/16"] would disable those days for every year</li>
38569 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38570 * <li>["03/../2006"] would disable every day in March 2006</li>
38571 * <li>["^03"] would disable every day in every March</li>
38573 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38574 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38576 disabledDates : null,
38578 * @cfg {String} disabledDatesText
38579 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38581 disabledDatesText : "Disabled",
38583 * @cfg {Date/String} minValue
38584 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38585 * valid format (defaults to null).
38589 * @cfg {Date/String} maxValue
38590 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38591 * valid format (defaults to null).
38595 * @cfg {String} minText
38596 * The error text to display when the date in the cell is before minValue (defaults to
38597 * 'The date in this field must be after {minValue}').
38599 minText : "The date in this field must be equal to or after {0}",
38601 * @cfg {String} maxText
38602 * The error text to display when the date in the cell is after maxValue (defaults to
38603 * 'The date in this field must be before {maxValue}').
38605 maxText : "The date in this field must be equal to or before {0}",
38607 * @cfg {String} invalidText
38608 * The error text to display when the date in the field is invalid (defaults to
38609 * '{value} is not a valid date - it must be in the format {format}').
38611 invalidText : "{0} is not a valid date - it must be in the format {1}",
38613 * @cfg {String} triggerClass
38614 * An additional CSS class used to style the trigger button. The trigger will always get the
38615 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38616 * which displays a calendar icon).
38618 triggerClass : 'x-form-date-trigger',
38622 * @cfg {Boolean} useIso
38623 * if enabled, then the date field will use a hidden field to store the
38624 * real value as iso formated date. default (false)
38628 * @cfg {String/Object} autoCreate
38629 * A DomHelper element spec, or true for a default element spec (defaults to
38630 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38633 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38636 hiddenField: false,
38638 onRender : function(ct, position)
38640 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38642 //this.el.dom.removeAttribute('name');
38643 Roo.log("Changing name?");
38644 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38645 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38647 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38648 // prevent input submission
38649 this.hiddenName = this.name;
38656 validateValue : function(value)
38658 value = this.formatDate(value);
38659 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38660 Roo.log('super failed');
38663 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38666 var svalue = value;
38667 value = this.parseDate(value);
38669 Roo.log('parse date failed' + svalue);
38670 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38673 var time = value.getTime();
38674 if(this.minValue && time < this.minValue.getTime()){
38675 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38678 if(this.maxValue && time > this.maxValue.getTime()){
38679 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38682 if(this.disabledDays){
38683 var day = value.getDay();
38684 for(var i = 0; i < this.disabledDays.length; i++) {
38685 if(day === this.disabledDays[i]){
38686 this.markInvalid(this.disabledDaysText);
38691 var fvalue = this.formatDate(value);
38692 if(this.ddMatch && this.ddMatch.test(fvalue)){
38693 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38700 // Provides logic to override the default TriggerField.validateBlur which just returns true
38701 validateBlur : function(){
38702 return !this.menu || !this.menu.isVisible();
38705 getName: function()
38707 // returns hidden if it's set..
38708 if (!this.rendered) {return ''};
38709 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38714 * Returns the current date value of the date field.
38715 * @return {Date} The date value
38717 getValue : function(){
38719 return this.hiddenField ?
38720 this.hiddenField.value :
38721 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38725 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38726 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38727 * (the default format used is "m/d/y").
38730 //All of these calls set the same date value (May 4, 2006)
38732 //Pass a date object:
38733 var dt = new Date('5/4/06');
38734 dateField.setValue(dt);
38736 //Pass a date string (default format):
38737 dateField.setValue('5/4/06');
38739 //Pass a date string (custom format):
38740 dateField.format = 'Y-m-d';
38741 dateField.setValue('2006-5-4');
38743 * @param {String/Date} date The date or valid date string
38745 setValue : function(date){
38746 if (this.hiddenField) {
38747 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38749 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38750 // make sure the value field is always stored as a date..
38751 this.value = this.parseDate(date);
38757 parseDate : function(value){
38758 if(!value || value instanceof Date){
38761 var v = Date.parseDate(value, this.format);
38762 if (!v && this.useIso) {
38763 v = Date.parseDate(value, 'Y-m-d');
38765 if(!v && this.altFormats){
38766 if(!this.altFormatsArray){
38767 this.altFormatsArray = this.altFormats.split("|");
38769 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38770 v = Date.parseDate(value, this.altFormatsArray[i]);
38777 formatDate : function(date, fmt){
38778 return (!date || !(date instanceof Date)) ?
38779 date : date.dateFormat(fmt || this.format);
38784 select: function(m, d){
38787 this.fireEvent('select', this, d);
38789 show : function(){ // retain focus styling
38793 this.focus.defer(10, this);
38794 var ml = this.menuListeners;
38795 this.menu.un("select", ml.select, this);
38796 this.menu.un("show", ml.show, this);
38797 this.menu.un("hide", ml.hide, this);
38802 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38803 onTriggerClick : function(){
38807 if(this.menu == null){
38808 this.menu = new Roo.menu.DateMenu();
38810 Roo.apply(this.menu.picker, {
38811 showClear: this.allowBlank,
38812 minDate : this.minValue,
38813 maxDate : this.maxValue,
38814 disabledDatesRE : this.ddMatch,
38815 disabledDatesText : this.disabledDatesText,
38816 disabledDays : this.disabledDays,
38817 disabledDaysText : this.disabledDaysText,
38818 format : this.useIso ? 'Y-m-d' : this.format,
38819 minText : String.format(this.minText, this.formatDate(this.minValue)),
38820 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38822 this.menu.on(Roo.apply({}, this.menuListeners, {
38825 this.menu.picker.setValue(this.getValue() || new Date());
38826 this.menu.show(this.el, "tl-bl?");
38829 beforeBlur : function(){
38830 var v = this.parseDate(this.getRawValue());
38840 isDirty : function() {
38841 if(this.disabled) {
38845 if(typeof(this.startValue) === 'undefined'){
38849 return String(this.getValue()) !== String(this.startValue);
38854 * Ext JS Library 1.1.1
38855 * Copyright(c) 2006-2007, Ext JS, LLC.
38857 * Originally Released Under LGPL - original licence link has changed is not relivant.
38860 * <script type="text/javascript">
38864 * @class Roo.form.MonthField
38865 * @extends Roo.form.TriggerField
38866 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38868 * Create a new MonthField
38869 * @param {Object} config
38871 Roo.form.MonthField = function(config){
38873 Roo.form.MonthField.superclass.constructor.call(this, config);
38879 * Fires when a date is selected
38880 * @param {Roo.form.MonthFieeld} combo This combo box
38881 * @param {Date} date The date selected
38888 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38889 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38890 this.ddMatch = null;
38891 if(this.disabledDates){
38892 var dd = this.disabledDates;
38894 for(var i = 0; i < dd.length; i++){
38896 if(i != dd.length-1) re += "|";
38898 this.ddMatch = new RegExp(re + ")");
38902 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38904 * @cfg {String} format
38905 * The default date format string which can be overriden for localization support. The format must be
38906 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38910 * @cfg {String} altFormats
38911 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38912 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38914 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38916 * @cfg {Array} disabledDays
38917 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38919 disabledDays : [0,1,2,3,4,5,6],
38921 * @cfg {String} disabledDaysText
38922 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38924 disabledDaysText : "Disabled",
38926 * @cfg {Array} disabledDates
38927 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38928 * expression so they are very powerful. Some examples:
38930 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38931 * <li>["03/08", "09/16"] would disable those days for every year</li>
38932 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38933 * <li>["03/../2006"] would disable every day in March 2006</li>
38934 * <li>["^03"] would disable every day in every March</li>
38936 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38937 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38939 disabledDates : null,
38941 * @cfg {String} disabledDatesText
38942 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38944 disabledDatesText : "Disabled",
38946 * @cfg {Date/String} minValue
38947 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38948 * valid format (defaults to null).
38952 * @cfg {Date/String} maxValue
38953 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38954 * valid format (defaults to null).
38958 * @cfg {String} minText
38959 * The error text to display when the date in the cell is before minValue (defaults to
38960 * 'The date in this field must be after {minValue}').
38962 minText : "The date in this field must be equal to or after {0}",
38964 * @cfg {String} maxTextf
38965 * The error text to display when the date in the cell is after maxValue (defaults to
38966 * 'The date in this field must be before {maxValue}').
38968 maxText : "The date in this field must be equal to or before {0}",
38970 * @cfg {String} invalidText
38971 * The error text to display when the date in the field is invalid (defaults to
38972 * '{value} is not a valid date - it must be in the format {format}').
38974 invalidText : "{0} is not a valid date - it must be in the format {1}",
38976 * @cfg {String} triggerClass
38977 * An additional CSS class used to style the trigger button. The trigger will always get the
38978 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38979 * which displays a calendar icon).
38981 triggerClass : 'x-form-date-trigger',
38985 * @cfg {Boolean} useIso
38986 * if enabled, then the date field will use a hidden field to store the
38987 * real value as iso formated date. default (true)
38991 * @cfg {String/Object} autoCreate
38992 * A DomHelper element spec, or true for a default element spec (defaults to
38993 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38996 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
38999 hiddenField: false,
39001 hideMonthPicker : false,
39003 onRender : function(ct, position)
39005 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39007 this.el.dom.removeAttribute('name');
39008 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39010 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39011 // prevent input submission
39012 this.hiddenName = this.name;
39019 validateValue : function(value)
39021 value = this.formatDate(value);
39022 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39025 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39028 var svalue = value;
39029 value = this.parseDate(value);
39031 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39034 var time = value.getTime();
39035 if(this.minValue && time < this.minValue.getTime()){
39036 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39039 if(this.maxValue && time > this.maxValue.getTime()){
39040 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39043 /*if(this.disabledDays){
39044 var day = value.getDay();
39045 for(var i = 0; i < this.disabledDays.length; i++) {
39046 if(day === this.disabledDays[i]){
39047 this.markInvalid(this.disabledDaysText);
39053 var fvalue = this.formatDate(value);
39054 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39055 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39063 // Provides logic to override the default TriggerField.validateBlur which just returns true
39064 validateBlur : function(){
39065 return !this.menu || !this.menu.isVisible();
39069 * Returns the current date value of the date field.
39070 * @return {Date} The date value
39072 getValue : function(){
39076 return this.hiddenField ?
39077 this.hiddenField.value :
39078 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39082 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39083 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39084 * (the default format used is "m/d/y").
39087 //All of these calls set the same date value (May 4, 2006)
39089 //Pass a date object:
39090 var dt = new Date('5/4/06');
39091 monthField.setValue(dt);
39093 //Pass a date string (default format):
39094 monthField.setValue('5/4/06');
39096 //Pass a date string (custom format):
39097 monthField.format = 'Y-m-d';
39098 monthField.setValue('2006-5-4');
39100 * @param {String/Date} date The date or valid date string
39102 setValue : function(date){
39103 Roo.log('month setValue' + date);
39104 // can only be first of month..
39106 var val = this.parseDate(date);
39108 if (this.hiddenField) {
39109 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39111 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39112 this.value = this.parseDate(date);
39116 parseDate : function(value){
39117 if(!value || value instanceof Date){
39118 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39121 var v = Date.parseDate(value, this.format);
39122 if (!v && this.useIso) {
39123 v = Date.parseDate(value, 'Y-m-d');
39127 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39131 if(!v && this.altFormats){
39132 if(!this.altFormatsArray){
39133 this.altFormatsArray = this.altFormats.split("|");
39135 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39136 v = Date.parseDate(value, this.altFormatsArray[i]);
39143 formatDate : function(date, fmt){
39144 return (!date || !(date instanceof Date)) ?
39145 date : date.dateFormat(fmt || this.format);
39150 select: function(m, d){
39152 this.fireEvent('select', this, d);
39154 show : function(){ // retain focus styling
39158 this.focus.defer(10, this);
39159 var ml = this.menuListeners;
39160 this.menu.un("select", ml.select, this);
39161 this.menu.un("show", ml.show, this);
39162 this.menu.un("hide", ml.hide, this);
39166 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39167 onTriggerClick : function(){
39171 if(this.menu == null){
39172 this.menu = new Roo.menu.DateMenu();
39176 Roo.apply(this.menu.picker, {
39178 showClear: this.allowBlank,
39179 minDate : this.minValue,
39180 maxDate : this.maxValue,
39181 disabledDatesRE : this.ddMatch,
39182 disabledDatesText : this.disabledDatesText,
39184 format : this.useIso ? 'Y-m-d' : this.format,
39185 minText : String.format(this.minText, this.formatDate(this.minValue)),
39186 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39189 this.menu.on(Roo.apply({}, this.menuListeners, {
39197 // hide month picker get's called when we called by 'before hide';
39199 var ignorehide = true;
39200 p.hideMonthPicker = function(disableAnim){
39204 if(this.monthPicker){
39205 Roo.log("hideMonthPicker called");
39206 if(disableAnim === true){
39207 this.monthPicker.hide();
39209 this.monthPicker.slideOut('t', {duration:.2});
39210 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39211 p.fireEvent("select", this, this.value);
39217 Roo.log('picker set value');
39218 Roo.log(this.getValue());
39219 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39220 m.show(this.el, 'tl-bl?');
39221 ignorehide = false;
39222 // this will trigger hideMonthPicker..
39225 // hidden the day picker
39226 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39232 p.showMonthPicker.defer(100, p);
39238 beforeBlur : function(){
39239 var v = this.parseDate(this.getRawValue());
39245 /** @cfg {Boolean} grow @hide */
39246 /** @cfg {Number} growMin @hide */
39247 /** @cfg {Number} growMax @hide */
39254 * Ext JS Library 1.1.1
39255 * Copyright(c) 2006-2007, Ext JS, LLC.
39257 * Originally Released Under LGPL - original licence link has changed is not relivant.
39260 * <script type="text/javascript">
39265 * @class Roo.form.ComboBox
39266 * @extends Roo.form.TriggerField
39267 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39269 * Create a new ComboBox.
39270 * @param {Object} config Configuration options
39272 Roo.form.ComboBox = function(config){
39273 Roo.form.ComboBox.superclass.constructor.call(this, config);
39277 * Fires when the dropdown list is expanded
39278 * @param {Roo.form.ComboBox} combo This combo box
39283 * Fires when the dropdown list is collapsed
39284 * @param {Roo.form.ComboBox} combo This combo box
39288 * @event beforeselect
39289 * Fires before a list item is selected. Return false to cancel the selection.
39290 * @param {Roo.form.ComboBox} combo This combo box
39291 * @param {Roo.data.Record} record The data record returned from the underlying store
39292 * @param {Number} index The index of the selected item in the dropdown list
39294 'beforeselect' : true,
39297 * Fires when a list item is selected
39298 * @param {Roo.form.ComboBox} combo This combo box
39299 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39300 * @param {Number} index The index of the selected item in the dropdown list
39304 * @event beforequery
39305 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39306 * The event object passed has these properties:
39307 * @param {Roo.form.ComboBox} combo This combo box
39308 * @param {String} query The query
39309 * @param {Boolean} forceAll true to force "all" query
39310 * @param {Boolean} cancel true to cancel the query
39311 * @param {Object} e The query event object
39313 'beforequery': true,
39316 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39317 * @param {Roo.form.ComboBox} combo This combo box
39322 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39323 * @param {Roo.form.ComboBox} combo This combo box
39324 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39330 if(this.transform){
39331 this.allowDomMove = false;
39332 var s = Roo.getDom(this.transform);
39333 if(!this.hiddenName){
39334 this.hiddenName = s.name;
39337 this.mode = 'local';
39338 var d = [], opts = s.options;
39339 for(var i = 0, len = opts.length;i < len; i++){
39341 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39343 this.value = value;
39345 d.push([value, o.text]);
39347 this.store = new Roo.data.SimpleStore({
39349 fields: ['value', 'text'],
39352 this.valueField = 'value';
39353 this.displayField = 'text';
39355 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39356 if(!this.lazyRender){
39357 this.target = true;
39358 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39359 s.parentNode.removeChild(s); // remove it
39360 this.render(this.el.parentNode);
39362 s.parentNode.removeChild(s); // remove it
39367 this.store = Roo.factory(this.store, Roo.data);
39370 this.selectedIndex = -1;
39371 if(this.mode == 'local'){
39372 if(config.queryDelay === undefined){
39373 this.queryDelay = 10;
39375 if(config.minChars === undefined){
39381 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39383 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39386 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39387 * rendering into an Roo.Editor, defaults to false)
39390 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39391 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39394 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39397 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39398 * the dropdown list (defaults to undefined, with no header element)
39402 * @cfg {String/Roo.Template} tpl The template to use to render the output
39406 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39408 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39410 listWidth: undefined,
39412 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39413 * mode = 'remote' or 'text' if mode = 'local')
39415 displayField: undefined,
39417 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39418 * mode = 'remote' or 'value' if mode = 'local').
39419 * Note: use of a valueField requires the user make a selection
39420 * in order for a value to be mapped.
39422 valueField: undefined,
39426 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39427 * field's data value (defaults to the underlying DOM element's name)
39429 hiddenName: undefined,
39431 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39435 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39437 selectedClass: 'x-combo-selected',
39439 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39440 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39441 * which displays a downward arrow icon).
39443 triggerClass : 'x-form-arrow-trigger',
39445 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39449 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39450 * anchor positions (defaults to 'tl-bl')
39452 listAlign: 'tl-bl?',
39454 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39458 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39459 * query specified by the allQuery config option (defaults to 'query')
39461 triggerAction: 'query',
39463 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39464 * (defaults to 4, does not apply if editable = false)
39468 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39469 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39473 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39474 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39478 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39479 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39483 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39484 * when editable = true (defaults to false)
39486 selectOnFocus:false,
39488 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39490 queryParam: 'query',
39492 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39493 * when mode = 'remote' (defaults to 'Loading...')
39495 loadingText: 'Loading...',
39497 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39501 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39505 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39506 * traditional select (defaults to true)
39510 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39514 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39518 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39519 * listWidth has a higher value)
39523 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39524 * allow the user to set arbitrary text into the field (defaults to false)
39526 forceSelection:false,
39528 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39529 * if typeAhead = true (defaults to 250)
39531 typeAheadDelay : 250,
39533 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39534 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39536 valueNotFoundText : undefined,
39538 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39540 blockFocus : false,
39543 * @cfg {Boolean} disableClear Disable showing of clear button.
39545 disableClear : false,
39547 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39549 alwaysQuery : false,
39555 // element that contains real text value.. (when hidden is used..)
39558 onRender : function(ct, position){
39559 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39560 if(this.hiddenName){
39561 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39563 this.hiddenField.value =
39564 this.hiddenValue !== undefined ? this.hiddenValue :
39565 this.value !== undefined ? this.value : '';
39567 // prevent input submission
39568 this.el.dom.removeAttribute('name');
39573 this.el.dom.setAttribute('autocomplete', 'off');
39576 var cls = 'x-combo-list';
39578 this.list = new Roo.Layer({
39579 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39582 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39583 this.list.setWidth(lw);
39584 this.list.swallowEvent('mousewheel');
39585 this.assetHeight = 0;
39588 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39589 this.assetHeight += this.header.getHeight();
39592 this.innerList = this.list.createChild({cls:cls+'-inner'});
39593 this.innerList.on('mouseover', this.onViewOver, this);
39594 this.innerList.on('mousemove', this.onViewMove, this);
39595 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39597 if(this.allowBlank && !this.pageSize && !this.disableClear){
39598 this.footer = this.list.createChild({cls:cls+'-ft'});
39599 this.pageTb = new Roo.Toolbar(this.footer);
39603 this.footer = this.list.createChild({cls:cls+'-ft'});
39604 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39605 {pageSize: this.pageSize});
39609 if (this.pageTb && this.allowBlank && !this.disableClear) {
39611 this.pageTb.add(new Roo.Toolbar.Fill(), {
39612 cls: 'x-btn-icon x-btn-clear',
39614 handler: function()
39617 _this.clearValue();
39618 _this.onSelect(false, -1);
39623 this.assetHeight += this.footer.getHeight();
39628 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39631 this.view = new Roo.View(this.innerList, this.tpl, {
39632 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39635 this.view.on('click', this.onViewClick, this);
39637 this.store.on('beforeload', this.onBeforeLoad, this);
39638 this.store.on('load', this.onLoad, this);
39639 this.store.on('loadexception', this.onLoadException, this);
39641 if(this.resizable){
39642 this.resizer = new Roo.Resizable(this.list, {
39643 pinned:true, handles:'se'
39645 this.resizer.on('resize', function(r, w, h){
39646 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39647 this.listWidth = w;
39648 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39649 this.restrictHeight();
39651 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39653 if(!this.editable){
39654 this.editable = true;
39655 this.setEditable(false);
39659 if (typeof(this.events.add.listeners) != 'undefined') {
39661 this.addicon = this.wrap.createChild(
39662 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39664 this.addicon.on('click', function(e) {
39665 this.fireEvent('add', this);
39668 if (typeof(this.events.edit.listeners) != 'undefined') {
39670 this.editicon = this.wrap.createChild(
39671 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39672 if (this.addicon) {
39673 this.editicon.setStyle('margin-left', '40px');
39675 this.editicon.on('click', function(e) {
39677 // we fire even if inothing is selected..
39678 this.fireEvent('edit', this, this.lastData );
39688 initEvents : function(){
39689 Roo.form.ComboBox.superclass.initEvents.call(this);
39691 this.keyNav = new Roo.KeyNav(this.el, {
39692 "up" : function(e){
39693 this.inKeyMode = true;
39697 "down" : function(e){
39698 if(!this.isExpanded()){
39699 this.onTriggerClick();
39701 this.inKeyMode = true;
39706 "enter" : function(e){
39707 this.onViewClick();
39711 "esc" : function(e){
39715 "tab" : function(e){
39716 this.onViewClick(false);
39717 this.fireEvent("specialkey", this, e);
39723 doRelay : function(foo, bar, hname){
39724 if(hname == 'down' || this.scope.isExpanded()){
39725 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39732 this.queryDelay = Math.max(this.queryDelay || 10,
39733 this.mode == 'local' ? 10 : 250);
39734 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39735 if(this.typeAhead){
39736 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39738 if(this.editable !== false){
39739 this.el.on("keyup", this.onKeyUp, this);
39741 if(this.forceSelection){
39742 this.on('blur', this.doForce, this);
39746 onDestroy : function(){
39748 this.view.setStore(null);
39749 this.view.el.removeAllListeners();
39750 this.view.el.remove();
39751 this.view.purgeListeners();
39754 this.list.destroy();
39757 this.store.un('beforeload', this.onBeforeLoad, this);
39758 this.store.un('load', this.onLoad, this);
39759 this.store.un('loadexception', this.onLoadException, this);
39761 Roo.form.ComboBox.superclass.onDestroy.call(this);
39765 fireKey : function(e){
39766 if(e.isNavKeyPress() && !this.list.isVisible()){
39767 this.fireEvent("specialkey", this, e);
39772 onResize: function(w, h){
39773 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39775 if(typeof w != 'number'){
39776 // we do not handle it!?!?
39779 var tw = this.trigger.getWidth();
39780 tw += this.addicon ? this.addicon.getWidth() : 0;
39781 tw += this.editicon ? this.editicon.getWidth() : 0;
39783 this.el.setWidth( this.adjustWidth('input', x));
39785 this.trigger.setStyle('left', x+'px');
39787 if(this.list && this.listWidth === undefined){
39788 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39789 this.list.setWidth(lw);
39790 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39798 * Allow or prevent the user from directly editing the field text. If false is passed,
39799 * the user will only be able to select from the items defined in the dropdown list. This method
39800 * is the runtime equivalent of setting the 'editable' config option at config time.
39801 * @param {Boolean} value True to allow the user to directly edit the field text
39803 setEditable : function(value){
39804 if(value == this.editable){
39807 this.editable = value;
39809 this.el.dom.setAttribute('readOnly', true);
39810 this.el.on('mousedown', this.onTriggerClick, this);
39811 this.el.addClass('x-combo-noedit');
39813 this.el.dom.setAttribute('readOnly', false);
39814 this.el.un('mousedown', this.onTriggerClick, this);
39815 this.el.removeClass('x-combo-noedit');
39820 onBeforeLoad : function(){
39821 if(!this.hasFocus){
39824 this.innerList.update(this.loadingText ?
39825 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39826 this.restrictHeight();
39827 this.selectedIndex = -1;
39831 onLoad : function(){
39832 if(!this.hasFocus){
39835 if(this.store.getCount() > 0){
39837 this.restrictHeight();
39838 if(this.lastQuery == this.allQuery){
39840 this.el.dom.select();
39842 if(!this.selectByValue(this.value, true)){
39843 this.select(0, true);
39847 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39848 this.taTask.delay(this.typeAheadDelay);
39852 this.onEmptyResults();
39857 onLoadException : function()
39860 Roo.log(this.store.reader.jsonData);
39861 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39862 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39868 onTypeAhead : function(){
39869 if(this.store.getCount() > 0){
39870 var r = this.store.getAt(0);
39871 var newValue = r.data[this.displayField];
39872 var len = newValue.length;
39873 var selStart = this.getRawValue().length;
39874 if(selStart != len){
39875 this.setRawValue(newValue);
39876 this.selectText(selStart, newValue.length);
39882 onSelect : function(record, index){
39883 if(this.fireEvent('beforeselect', this, record, index) !== false){
39884 this.setFromData(index > -1 ? record.data : false);
39886 this.fireEvent('select', this, record, index);
39891 * Returns the currently selected field value or empty string if no value is set.
39892 * @return {String} value The selected value
39894 getValue : function(){
39895 if(this.valueField){
39896 return typeof this.value != 'undefined' ? this.value : '';
39898 return Roo.form.ComboBox.superclass.getValue.call(this);
39902 * Clears any text/value currently set in the field
39904 clearValue : function(){
39905 if(this.hiddenField){
39906 this.hiddenField.value = '';
39909 this.setRawValue('');
39910 this.lastSelectionText = '';
39915 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39916 * will be displayed in the field. If the value does not match the data value of an existing item,
39917 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39918 * Otherwise the field will be blank (although the value will still be set).
39919 * @param {String} value The value to match
39921 setValue : function(v){
39923 if(this.valueField){
39924 var r = this.findRecord(this.valueField, v);
39926 text = r.data[this.displayField];
39927 }else if(this.valueNotFoundText !== undefined){
39928 text = this.valueNotFoundText;
39931 this.lastSelectionText = text;
39932 if(this.hiddenField){
39933 this.hiddenField.value = v;
39935 Roo.form.ComboBox.superclass.setValue.call(this, text);
39939 * @property {Object} the last set data for the element
39944 * Sets the value of the field based on a object which is related to the record format for the store.
39945 * @param {Object} value the value to set as. or false on reset?
39947 setFromData : function(o){
39948 var dv = ''; // display value
39949 var vv = ''; // value value..
39951 if (this.displayField) {
39952 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39954 // this is an error condition!!!
39955 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39958 if(this.valueField){
39959 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39961 if(this.hiddenField){
39962 this.hiddenField.value = vv;
39964 this.lastSelectionText = dv;
39965 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39969 // no hidden field.. - we store the value in 'value', but still display
39970 // display field!!!!
39971 this.lastSelectionText = dv;
39972 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39978 reset : function(){
39979 // overridden so that last data is reset..
39980 this.setValue(this.resetValue);
39981 this.clearInvalid();
39982 this.lastData = false;
39984 this.view.clearSelections();
39988 findRecord : function(prop, value){
39990 if(this.store.getCount() > 0){
39991 this.store.each(function(r){
39992 if(r.data[prop] == value){
40002 getName: function()
40004 // returns hidden if it's set..
40005 if (!this.rendered) {return ''};
40006 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40010 onViewMove : function(e, t){
40011 this.inKeyMode = false;
40015 onViewOver : function(e, t){
40016 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40019 var item = this.view.findItemFromChild(t);
40021 var index = this.view.indexOf(item);
40022 this.select(index, false);
40027 onViewClick : function(doFocus)
40029 var index = this.view.getSelectedIndexes()[0];
40030 var r = this.store.getAt(index);
40032 this.onSelect(r, index);
40034 if(doFocus !== false && !this.blockFocus){
40040 restrictHeight : function(){
40041 this.innerList.dom.style.height = '';
40042 var inner = this.innerList.dom;
40043 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40044 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40045 this.list.beginUpdate();
40046 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40047 this.list.alignTo(this.el, this.listAlign);
40048 this.list.endUpdate();
40052 onEmptyResults : function(){
40057 * Returns true if the dropdown list is expanded, else false.
40059 isExpanded : function(){
40060 return this.list.isVisible();
40064 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40065 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40066 * @param {String} value The data value of the item to select
40067 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40068 * selected item if it is not currently in view (defaults to true)
40069 * @return {Boolean} True if the value matched an item in the list, else false
40071 selectByValue : function(v, scrollIntoView){
40072 if(v !== undefined && v !== null){
40073 var r = this.findRecord(this.valueField || this.displayField, v);
40075 this.select(this.store.indexOf(r), scrollIntoView);
40083 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40084 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40085 * @param {Number} index The zero-based index of the list item to select
40086 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40087 * selected item if it is not currently in view (defaults to true)
40089 select : function(index, scrollIntoView){
40090 this.selectedIndex = index;
40091 this.view.select(index);
40092 if(scrollIntoView !== false){
40093 var el = this.view.getNode(index);
40095 this.innerList.scrollChildIntoView(el, false);
40101 selectNext : function(){
40102 var ct = this.store.getCount();
40104 if(this.selectedIndex == -1){
40106 }else if(this.selectedIndex < ct-1){
40107 this.select(this.selectedIndex+1);
40113 selectPrev : function(){
40114 var ct = this.store.getCount();
40116 if(this.selectedIndex == -1){
40118 }else if(this.selectedIndex != 0){
40119 this.select(this.selectedIndex-1);
40125 onKeyUp : function(e){
40126 if(this.editable !== false && !e.isSpecialKey()){
40127 this.lastKey = e.getKey();
40128 this.dqTask.delay(this.queryDelay);
40133 validateBlur : function(){
40134 return !this.list || !this.list.isVisible();
40138 initQuery : function(){
40139 this.doQuery(this.getRawValue());
40143 doForce : function(){
40144 if(this.el.dom.value.length > 0){
40145 this.el.dom.value =
40146 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40152 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40153 * query allowing the query action to be canceled if needed.
40154 * @param {String} query The SQL query to execute
40155 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40156 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40157 * saved in the current store (defaults to false)
40159 doQuery : function(q, forceAll){
40160 if(q === undefined || q === null){
40165 forceAll: forceAll,
40169 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40173 forceAll = qe.forceAll;
40174 if(forceAll === true || (q.length >= this.minChars)){
40175 if(this.lastQuery != q || this.alwaysQuery){
40176 this.lastQuery = q;
40177 if(this.mode == 'local'){
40178 this.selectedIndex = -1;
40180 this.store.clearFilter();
40182 this.store.filter(this.displayField, q);
40186 this.store.baseParams[this.queryParam] = q;
40188 params: this.getParams(q)
40193 this.selectedIndex = -1;
40200 getParams : function(q){
40202 //p[this.queryParam] = q;
40205 p.limit = this.pageSize;
40211 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40213 collapse : function(){
40214 if(!this.isExpanded()){
40218 Roo.get(document).un('mousedown', this.collapseIf, this);
40219 Roo.get(document).un('mousewheel', this.collapseIf, this);
40220 if (!this.editable) {
40221 Roo.get(document).un('keydown', this.listKeyPress, this);
40223 this.fireEvent('collapse', this);
40227 collapseIf : function(e){
40228 if(!e.within(this.wrap) && !e.within(this.list)){
40234 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40236 expand : function(){
40237 if(this.isExpanded() || !this.hasFocus){
40240 this.list.alignTo(this.el, this.listAlign);
40242 Roo.get(document).on('mousedown', this.collapseIf, this);
40243 Roo.get(document).on('mousewheel', this.collapseIf, this);
40244 if (!this.editable) {
40245 Roo.get(document).on('keydown', this.listKeyPress, this);
40248 this.fireEvent('expand', this);
40252 // Implements the default empty TriggerField.onTriggerClick function
40253 onTriggerClick : function(){
40257 if(this.isExpanded()){
40259 if (!this.blockFocus) {
40264 this.hasFocus = true;
40265 if(this.triggerAction == 'all') {
40266 this.doQuery(this.allQuery, true);
40268 this.doQuery(this.getRawValue());
40270 if (!this.blockFocus) {
40275 listKeyPress : function(e)
40277 //Roo.log('listkeypress');
40278 // scroll to first matching element based on key pres..
40279 if (e.isSpecialKey()) {
40282 var k = String.fromCharCode(e.getKey()).toUpperCase();
40285 var csel = this.view.getSelectedNodes();
40286 var cselitem = false;
40288 var ix = this.view.indexOf(csel[0]);
40289 cselitem = this.store.getAt(ix);
40290 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40296 this.store.each(function(v) {
40298 // start at existing selection.
40299 if (cselitem.id == v.id) {
40305 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40306 match = this.store.indexOf(v);
40311 if (match === false) {
40312 return true; // no more action?
40315 this.view.select(match);
40316 var sn = Roo.get(this.view.getSelectedNodes()[0])
40317 sn.scrollIntoView(sn.dom.parentNode, false);
40321 * @cfg {Boolean} grow
40325 * @cfg {Number} growMin
40329 * @cfg {Number} growMax
40337 * Copyright(c) 2010-2012, Roo J Solutions Limited
40344 * @class Roo.form.ComboBoxArray
40345 * @extends Roo.form.TextField
40346 * A facebook style adder... for lists of email / people / countries etc...
40347 * pick multiple items from a combo box, and shows each one.
40349 * Fred [x] Brian [x] [Pick another |v]
40352 * For this to work: it needs various extra information
40353 * - normal combo problay has
40355 * + displayField, valueField
40357 * For our purpose...
40360 * If we change from 'extends' to wrapping...
40367 * Create a new ComboBoxArray.
40368 * @param {Object} config Configuration options
40372 Roo.form.ComboBoxArray = function(config)
40376 * @event beforeremove
40377 * Fires before remove the value from the list
40378 * @param {Roo.form.ComboBoxArray} _self This combo box array
40379 * @param {Roo.form.ComboBoxArray.Item} item removed item
40381 'beforeremove' : true,
40384 * Fires when remove the value from the list
40385 * @param {Roo.form.ComboBoxArray} _self This combo box array
40386 * @param {Roo.form.ComboBoxArray.Item} item removed item
40393 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40395 this.items = new Roo.util.MixedCollection(false);
40397 // construct the child combo...
40407 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40410 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40415 // behavies liek a hiddne field
40416 inputType: 'hidden',
40418 * @cfg {Number} width The width of the box that displays the selected element
40425 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40429 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40431 hiddenName : false,
40434 // private the array of items that are displayed..
40436 // private - the hidden field el.
40438 // private - the filed el..
40441 //validateValue : function() { return true; }, // all values are ok!
40442 //onAddClick: function() { },
40444 onRender : function(ct, position)
40447 // create the standard hidden element
40448 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40451 // give fake names to child combo;
40452 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40453 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40455 this.combo = Roo.factory(this.combo, Roo.form);
40456 this.combo.onRender(ct, position);
40457 if (typeof(this.combo.width) != 'undefined') {
40458 this.combo.onResize(this.combo.width,0);
40461 this.combo.initEvents();
40463 // assigned so form know we need to do this..
40464 this.store = this.combo.store;
40465 this.valueField = this.combo.valueField;
40466 this.displayField = this.combo.displayField ;
40469 this.combo.wrap.addClass('x-cbarray-grp');
40471 var cbwrap = this.combo.wrap.createChild(
40472 {tag: 'div', cls: 'x-cbarray-cb'},
40477 this.hiddenEl = this.combo.wrap.createChild({
40478 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40480 this.el = this.combo.wrap.createChild({
40481 tag: 'input', type:'hidden' , name: this.name, value : ''
40483 // this.el.dom.removeAttribute("name");
40486 this.outerWrap = this.combo.wrap;
40487 this.wrap = cbwrap;
40489 this.outerWrap.setWidth(this.width);
40490 this.outerWrap.dom.removeChild(this.el.dom);
40492 this.wrap.dom.appendChild(this.el.dom);
40493 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40494 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40496 this.combo.trigger.setStyle('position','relative');
40497 this.combo.trigger.setStyle('left', '0px');
40498 this.combo.trigger.setStyle('top', '2px');
40500 this.combo.el.setStyle('vertical-align', 'text-bottom');
40502 //this.trigger.setStyle('vertical-align', 'top');
40504 // this should use the code from combo really... on('add' ....)
40508 this.adder = this.outerWrap.createChild(
40509 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40511 this.adder.on('click', function(e) {
40512 _t.fireEvent('adderclick', this, e);
40516 //this.adder.on('click', this.onAddClick, _t);
40519 this.combo.on('select', function(cb, rec, ix) {
40520 this.addItem(rec.data);
40523 cb.el.dom.value = '';
40524 //cb.lastData = rec.data;
40533 getName: function()
40535 // returns hidden if it's set..
40536 if (!this.rendered) {return ''};
40537 return this.hiddenName ? this.hiddenName : this.name;
40542 onResize: function(w, h){
40545 // not sure if this is needed..
40546 //this.combo.onResize(w,h);
40548 if(typeof w != 'number'){
40549 // we do not handle it!?!?
40552 var tw = this.combo.trigger.getWidth();
40553 tw += this.addicon ? this.addicon.getWidth() : 0;
40554 tw += this.editicon ? this.editicon.getWidth() : 0;
40556 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40558 this.combo.trigger.setStyle('left', '0px');
40560 if(this.list && this.listWidth === undefined){
40561 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40562 this.list.setWidth(lw);
40563 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40570 addItem: function(rec)
40572 var valueField = this.combo.valueField;
40573 var displayField = this.combo.displayField;
40574 if (this.items.indexOfKey(rec[valueField]) > -1) {
40575 //console.log("GOT " + rec.data.id);
40579 var x = new Roo.form.ComboBoxArray.Item({
40580 //id : rec[this.idField],
40582 displayField : displayField ,
40583 tipField : displayField ,
40587 this.items.add(rec[valueField],x);
40588 // add it before the element..
40589 this.updateHiddenEl();
40590 x.render(this.outerWrap, this.wrap.dom);
40591 // add the image handler..
40594 updateHiddenEl : function()
40597 if (!this.hiddenEl) {
40601 var idField = this.combo.valueField;
40603 this.items.each(function(f) {
40604 ar.push(f.data[idField]);
40607 this.hiddenEl.dom.value = ar.join(',');
40613 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40614 this.items.each(function(f) {
40617 this.el.dom.value = '';
40618 if (this.hiddenEl) {
40619 this.hiddenEl.dom.value = '';
40623 getValue: function()
40625 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40627 setValue: function(v) // not a valid action - must use addItems..
40634 if (this.store.isLocal && (typeof(v) == 'string')) {
40635 // then we can use the store to find the values..
40636 // comma seperated at present.. this needs to allow JSON based encoding..
40637 this.hiddenEl.value = v;
40639 Roo.each(v.split(','), function(k) {
40640 Roo.log("CHECK " + this.valueField + ',' + k);
40641 var li = this.store.query(this.valueField, k);
40646 add[this.valueField] = k;
40647 add[this.displayField] = li.item(0).data[this.displayField];
40653 if (typeof(v) == 'object' ) {
40654 // then let's assume it's an array of objects..
40655 Roo.each(v, function(l) {
40663 setFromData: function(v)
40665 // this recieves an object, if setValues is called.
40667 this.el.dom.value = v[this.displayField];
40668 this.hiddenEl.dom.value = v[this.valueField];
40669 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40672 var kv = v[this.valueField];
40673 var dv = v[this.displayField];
40674 kv = typeof(kv) != 'string' ? '' : kv;
40675 dv = typeof(dv) != 'string' ? '' : dv;
40678 var keys = kv.split(',');
40679 var display = dv.split(',');
40680 for (var i = 0 ; i < keys.length; i++) {
40683 add[this.valueField] = keys[i];
40684 add[this.displayField] = display[i];
40692 * Validates the combox array value
40693 * @return {Boolean} True if the value is valid, else false
40695 validate : function(){
40696 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40697 this.clearInvalid();
40703 validateValue : function(value){
40704 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40712 isDirty : function() {
40713 if(this.disabled) {
40718 var d = Roo.decode(String(this.originalValue));
40720 return String(this.getValue()) !== String(this.originalValue);
40723 var originalValue = [];
40725 for (var i = 0; i < d.length; i++){
40726 originalValue.push(d[i][this.valueField]);
40729 return String(this.getValue()) !== String(originalValue.join(','));
40738 * @class Roo.form.ComboBoxArray.Item
40739 * @extends Roo.BoxComponent
40740 * A selected item in the list
40741 * Fred [x] Brian [x] [Pick another |v]
40744 * Create a new item.
40745 * @param {Object} config Configuration options
40748 Roo.form.ComboBoxArray.Item = function(config) {
40749 config.id = Roo.id();
40750 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40753 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40756 displayField : false,
40760 defaultAutoCreate : {
40762 cls: 'x-cbarray-item',
40769 src : Roo.BLANK_IMAGE_URL ,
40777 onRender : function(ct, position)
40779 Roo.form.Field.superclass.onRender.call(this, ct, position);
40782 var cfg = this.getAutoCreate();
40783 this.el = ct.createChild(cfg, position);
40786 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40788 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40789 this.cb.renderer(this.data) :
40790 String.format('{0}',this.data[this.displayField]);
40793 this.el.child('div').dom.setAttribute('qtip',
40794 String.format('{0}',this.data[this.tipField])
40797 this.el.child('img').on('click', this.remove, this);
40801 remove : function()
40803 if(this.cb.disabled){
40807 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40808 this.cb.items.remove(this);
40809 this.el.child('img').un('click', this.remove, this);
40811 this.cb.updateHiddenEl();
40813 this.cb.fireEvent('remove', this.cb, this);
40819 * Ext JS Library 1.1.1
40820 * Copyright(c) 2006-2007, Ext JS, LLC.
40822 * Originally Released Under LGPL - original licence link has changed is not relivant.
40825 * <script type="text/javascript">
40828 * @class Roo.form.Checkbox
40829 * @extends Roo.form.Field
40830 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40832 * Creates a new Checkbox
40833 * @param {Object} config Configuration options
40835 Roo.form.Checkbox = function(config){
40836 Roo.form.Checkbox.superclass.constructor.call(this, config);
40840 * Fires when the checkbox is checked or unchecked.
40841 * @param {Roo.form.Checkbox} this This checkbox
40842 * @param {Boolean} checked The new checked value
40848 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40850 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40852 focusClass : undefined,
40854 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40856 fieldClass: "x-form-field",
40858 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40862 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40863 * {tag: "input", type: "checkbox", autocomplete: "off"})
40865 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40867 * @cfg {String} boxLabel The text that appears beside the checkbox
40871 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40875 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40877 valueOff: '0', // value when not checked..
40879 actionMode : 'viewEl',
40882 itemCls : 'x-menu-check-item x-form-item',
40883 groupClass : 'x-menu-group-item',
40884 inputType : 'hidden',
40887 inSetChecked: false, // check that we are not calling self...
40889 inputElement: false, // real input element?
40890 basedOn: false, // ????
40892 isFormField: true, // not sure where this is needed!!!!
40894 onResize : function(){
40895 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40896 if(!this.boxLabel){
40897 this.el.alignTo(this.wrap, 'c-c');
40901 initEvents : function(){
40902 Roo.form.Checkbox.superclass.initEvents.call(this);
40903 this.el.on("click", this.onClick, this);
40904 this.el.on("change", this.onClick, this);
40908 getResizeEl : function(){
40912 getPositionEl : function(){
40917 onRender : function(ct, position){
40918 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40920 if(this.inputValue !== undefined){
40921 this.el.dom.value = this.inputValue;
40924 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40925 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40926 var viewEl = this.wrap.createChild({
40927 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40928 this.viewEl = viewEl;
40929 this.wrap.on('click', this.onClick, this);
40931 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40932 this.el.on('propertychange', this.setFromHidden, this); //ie
40937 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40938 // viewEl.on('click', this.onClick, this);
40940 //if(this.checked){
40941 this.setChecked(this.checked);
40943 //this.checked = this.el.dom;
40949 initValue : Roo.emptyFn,
40952 * Returns the checked state of the checkbox.
40953 * @return {Boolean} True if checked, else false
40955 getValue : function(){
40957 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40959 return this.valueOff;
40964 onClick : function(){
40965 if (this.disabled) {
40968 this.setChecked(!this.checked);
40970 //if(this.el.dom.checked != this.checked){
40971 // this.setValue(this.el.dom.checked);
40976 * Sets the checked state of the checkbox.
40977 * On is always based on a string comparison between inputValue and the param.
40978 * @param {Boolean/String} value - the value to set
40979 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40981 setValue : function(v,suppressEvent){
40984 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40985 //if(this.el && this.el.dom){
40986 // this.el.dom.checked = this.checked;
40987 // this.el.dom.defaultChecked = this.checked;
40989 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40990 //this.fireEvent("check", this, this.checked);
40993 setChecked : function(state,suppressEvent)
40995 if (this.inSetChecked) {
40996 this.checked = state;
41002 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41004 this.checked = state;
41005 if(suppressEvent !== true){
41006 this.fireEvent('check', this, state);
41008 this.inSetChecked = true;
41009 this.el.dom.value = state ? this.inputValue : this.valueOff;
41010 this.inSetChecked = false;
41013 // handle setting of hidden value by some other method!!?!?
41014 setFromHidden: function()
41019 //console.log("SET FROM HIDDEN");
41020 //alert('setFrom hidden');
41021 this.setValue(this.el.dom.value);
41024 onDestroy : function()
41027 Roo.get(this.viewEl).remove();
41030 Roo.form.Checkbox.superclass.onDestroy.call(this);
41035 * Ext JS Library 1.1.1
41036 * Copyright(c) 2006-2007, Ext JS, LLC.
41038 * Originally Released Under LGPL - original licence link has changed is not relivant.
41041 * <script type="text/javascript">
41045 * @class Roo.form.Radio
41046 * @extends Roo.form.Checkbox
41047 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41048 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41050 * Creates a new Radio
41051 * @param {Object} config Configuration options
41053 Roo.form.Radio = function(){
41054 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41056 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41057 inputType: 'radio',
41060 * If this radio is part of a group, it will return the selected value
41063 getGroupValue : function(){
41064 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41068 onRender : function(ct, position){
41069 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41071 if(this.inputValue !== undefined){
41072 this.el.dom.value = this.inputValue;
41075 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41076 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41077 //var viewEl = this.wrap.createChild({
41078 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41079 //this.viewEl = viewEl;
41080 //this.wrap.on('click', this.onClick, this);
41082 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41083 //this.el.on('propertychange', this.setFromHidden, this); //ie
41088 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41089 // viewEl.on('click', this.onClick, this);
41092 this.el.dom.checked = 'checked' ;
41098 });//<script type="text/javascript">
41101 * Based Ext JS Library 1.1.1
41102 * Copyright(c) 2006-2007, Ext JS, LLC.
41108 * @class Roo.HtmlEditorCore
41109 * @extends Roo.Component
41110 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41112 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41115 Roo.HtmlEditorCore = function(config){
41118 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41123 * @event initialize
41124 * Fires when the editor is fully initialized (including the iframe)
41125 * @param {Roo.HtmlEditorCore} this
41130 * Fires when the editor is first receives the focus. Any insertion must wait
41131 * until after this event.
41132 * @param {Roo.HtmlEditorCore} this
41136 * @event beforesync
41137 * Fires before the textarea is updated with content from the editor iframe. Return false
41138 * to cancel the sync.
41139 * @param {Roo.HtmlEditorCore} this
41140 * @param {String} html
41144 * @event beforepush
41145 * Fires before the iframe editor is updated with content from the textarea. Return false
41146 * to cancel the push.
41147 * @param {Roo.HtmlEditorCore} this
41148 * @param {String} html
41153 * Fires when the textarea is updated with content from the editor iframe.
41154 * @param {Roo.HtmlEditorCore} this
41155 * @param {String} html
41160 * Fires when the iframe editor is updated with content from the textarea.
41161 * @param {Roo.HtmlEditorCore} this
41162 * @param {String} html
41167 * @event editorevent
41168 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41169 * @param {Roo.HtmlEditorCore} this
41175 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41177 // defaults : white / black...
41178 this.applyBlacklists();
41185 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41189 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41195 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41200 * @cfg {Number} height (in pixels)
41204 * @cfg {Number} width (in pixels)
41209 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41212 stylesheets: false,
41217 // private properties
41218 validationEvent : false,
41220 initialized : false,
41222 sourceEditMode : false,
41223 onFocus : Roo.emptyFn,
41225 hideMode:'offsets',
41229 // blacklist + whitelisted elements..
41236 * Protected method that will not generally be called directly. It
41237 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41238 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41240 getDocMarkup : function(){
41244 // inherit styels from page...??
41245 if (this.stylesheets === false) {
41247 Roo.get(document.head).select('style').each(function(node) {
41248 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41251 Roo.get(document.head).select('link').each(function(node) {
41252 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41255 } else if (!this.stylesheets.length) {
41257 st = '<style type="text/css">' +
41258 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41264 st += '<style type="text/css">' +
41265 'IMG { cursor: pointer } ' +
41269 return '<html><head>' + st +
41270 //<style type="text/css">' +
41271 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41273 ' </head><body class="roo-htmleditor-body"></body></html>';
41277 onRender : function(ct, position)
41280 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41281 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41284 this.el.dom.style.border = '0 none';
41285 this.el.dom.setAttribute('tabIndex', -1);
41286 this.el.addClass('x-hidden hide');
41290 if(Roo.isIE){ // fix IE 1px bogus margin
41291 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41295 this.frameId = Roo.id();
41299 var iframe = this.owner.wrap.createChild({
41301 cls: 'form-control', // bootstrap..
41303 name: this.frameId,
41304 frameBorder : 'no',
41305 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41310 this.iframe = iframe.dom;
41312 this.assignDocWin();
41314 this.doc.designMode = 'on';
41317 this.doc.write(this.getDocMarkup());
41321 var task = { // must defer to wait for browser to be ready
41323 //console.log("run task?" + this.doc.readyState);
41324 this.assignDocWin();
41325 if(this.doc.body || this.doc.readyState == 'complete'){
41327 this.doc.designMode="on";
41331 Roo.TaskMgr.stop(task);
41332 this.initEditor.defer(10, this);
41339 Roo.TaskMgr.start(task);
41344 onResize : function(w, h)
41346 Roo.log('resize: ' +w + ',' + h );
41347 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41351 if(typeof w == 'number'){
41353 this.iframe.style.width = w + 'px';
41355 if(typeof h == 'number'){
41357 this.iframe.style.height = h + 'px';
41359 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41366 * Toggles the editor between standard and source edit mode.
41367 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41369 toggleSourceEdit : function(sourceEditMode){
41371 this.sourceEditMode = sourceEditMode === true;
41373 if(this.sourceEditMode){
41375 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41378 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41379 //this.iframe.className = '';
41382 //this.setSize(this.owner.wrap.getSize());
41383 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41390 * Protected method that will not generally be called directly. If you need/want
41391 * custom HTML cleanup, this is the method you should override.
41392 * @param {String} html The HTML to be cleaned
41393 * return {String} The cleaned HTML
41395 cleanHtml : function(html){
41396 html = String(html);
41397 if(html.length > 5){
41398 if(Roo.isSafari){ // strip safari nonsense
41399 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41402 if(html == ' '){
41409 * HTML Editor -> Textarea
41410 * Protected method that will not generally be called directly. Syncs the contents
41411 * of the editor iframe with the textarea.
41413 syncValue : function(){
41414 if(this.initialized){
41415 var bd = (this.doc.body || this.doc.documentElement);
41416 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41417 var html = bd.innerHTML;
41419 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41420 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41422 html = '<div style="'+m[0]+'">' + html + '</div>';
41425 html = this.cleanHtml(html);
41426 // fix up the special chars.. normaly like back quotes in word...
41427 // however we do not want to do this with chinese..
41428 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41429 var cc = b.charCodeAt();
41431 (cc >= 0x4E00 && cc < 0xA000 ) ||
41432 (cc >= 0x3400 && cc < 0x4E00 ) ||
41433 (cc >= 0xf900 && cc < 0xfb00 )
41439 if(this.owner.fireEvent('beforesync', this, html) !== false){
41440 this.el.dom.value = html;
41441 this.owner.fireEvent('sync', this, html);
41447 * Protected method that will not generally be called directly. Pushes the value of the textarea
41448 * into the iframe editor.
41450 pushValue : function(){
41451 if(this.initialized){
41452 var v = this.el.dom.value.trim();
41454 // if(v.length < 1){
41458 if(this.owner.fireEvent('beforepush', this, v) !== false){
41459 var d = (this.doc.body || this.doc.documentElement);
41461 this.cleanUpPaste();
41462 this.el.dom.value = d.innerHTML;
41463 this.owner.fireEvent('push', this, v);
41469 deferFocus : function(){
41470 this.focus.defer(10, this);
41474 focus : function(){
41475 if(this.win && !this.sourceEditMode){
41482 assignDocWin: function()
41484 var iframe = this.iframe;
41487 this.doc = iframe.contentWindow.document;
41488 this.win = iframe.contentWindow;
41490 // if (!Roo.get(this.frameId)) {
41493 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41494 // this.win = Roo.get(this.frameId).dom.contentWindow;
41496 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41500 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41501 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41506 initEditor : function(){
41507 //console.log("INIT EDITOR");
41508 this.assignDocWin();
41512 this.doc.designMode="on";
41514 this.doc.write(this.getDocMarkup());
41517 var dbody = (this.doc.body || this.doc.documentElement);
41518 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41519 // this copies styles from the containing element into thsi one..
41520 // not sure why we need all of this..
41521 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41523 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41524 //ss['background-attachment'] = 'fixed'; // w3c
41525 dbody.bgProperties = 'fixed'; // ie
41526 //Roo.DomHelper.applyStyles(dbody, ss);
41527 Roo.EventManager.on(this.doc, {
41528 //'mousedown': this.onEditorEvent,
41529 'mouseup': this.onEditorEvent,
41530 'dblclick': this.onEditorEvent,
41531 'click': this.onEditorEvent,
41532 'keyup': this.onEditorEvent,
41537 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41539 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41540 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41542 this.initialized = true;
41544 this.owner.fireEvent('initialize', this);
41549 onDestroy : function(){
41555 //for (var i =0; i < this.toolbars.length;i++) {
41556 // // fixme - ask toolbars for heights?
41557 // this.toolbars[i].onDestroy();
41560 //this.wrap.dom.innerHTML = '';
41561 //this.wrap.remove();
41566 onFirstFocus : function(){
41568 this.assignDocWin();
41571 this.activated = true;
41574 if(Roo.isGecko){ // prevent silly gecko errors
41576 var s = this.win.getSelection();
41577 if(!s.focusNode || s.focusNode.nodeType != 3){
41578 var r = s.getRangeAt(0);
41579 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41584 this.execCmd('useCSS', true);
41585 this.execCmd('styleWithCSS', false);
41588 this.owner.fireEvent('activate', this);
41592 adjustFont: function(btn){
41593 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41594 //if(Roo.isSafari){ // safari
41597 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41598 if(Roo.isSafari){ // safari
41599 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41600 v = (v < 10) ? 10 : v;
41601 v = (v > 48) ? 48 : v;
41602 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41607 v = Math.max(1, v+adjust);
41609 this.execCmd('FontSize', v );
41612 onEditorEvent : function(e)
41614 this.owner.fireEvent('editorevent', this, e);
41615 // this.updateToolbar();
41616 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41619 insertTag : function(tg)
41621 // could be a bit smarter... -> wrap the current selected tRoo..
41622 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41624 range = this.createRange(this.getSelection());
41625 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41626 wrappingNode.appendChild(range.extractContents());
41627 range.insertNode(wrappingNode);
41634 this.execCmd("formatblock", tg);
41638 insertText : function(txt)
41642 var range = this.createRange();
41643 range.deleteContents();
41644 //alert(Sender.getAttribute('label'));
41646 range.insertNode(this.doc.createTextNode(txt));
41652 * Executes a Midas editor command on the editor document and performs necessary focus and
41653 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41654 * @param {String} cmd The Midas command
41655 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41657 relayCmd : function(cmd, value){
41659 this.execCmd(cmd, value);
41660 this.owner.fireEvent('editorevent', this);
41661 //this.updateToolbar();
41662 this.owner.deferFocus();
41666 * Executes a Midas editor command directly on the editor document.
41667 * For visual commands, you should use {@link #relayCmd} instead.
41668 * <b>This should only be called after the editor is initialized.</b>
41669 * @param {String} cmd The Midas command
41670 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41672 execCmd : function(cmd, value){
41673 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41680 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41682 * @param {String} text | dom node..
41684 insertAtCursor : function(text)
41689 if(!this.activated){
41695 var r = this.doc.selection.createRange();
41706 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41710 // from jquery ui (MIT licenced)
41712 var win = this.win;
41714 if (win.getSelection && win.getSelection().getRangeAt) {
41715 range = win.getSelection().getRangeAt(0);
41716 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41717 range.insertNode(node);
41718 } else if (win.document.selection && win.document.selection.createRange) {
41719 // no firefox support
41720 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41721 win.document.selection.createRange().pasteHTML(txt);
41723 // no firefox support
41724 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41725 this.execCmd('InsertHTML', txt);
41734 mozKeyPress : function(e){
41736 var c = e.getCharCode(), cmd;
41739 c = String.fromCharCode(c).toLowerCase();
41753 this.cleanUpPaste.defer(100, this);
41761 e.preventDefault();
41769 fixKeys : function(){ // load time branching for fastest keydown performance
41771 return function(e){
41772 var k = e.getKey(), r;
41775 r = this.doc.selection.createRange();
41778 r.pasteHTML('    ');
41785 r = this.doc.selection.createRange();
41787 var target = r.parentElement();
41788 if(!target || target.tagName.toLowerCase() != 'li'){
41790 r.pasteHTML('<br />');
41796 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41797 this.cleanUpPaste.defer(100, this);
41803 }else if(Roo.isOpera){
41804 return function(e){
41805 var k = e.getKey();
41809 this.execCmd('InsertHTML','    ');
41812 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41813 this.cleanUpPaste.defer(100, this);
41818 }else if(Roo.isSafari){
41819 return function(e){
41820 var k = e.getKey();
41824 this.execCmd('InsertText','\t');
41828 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41829 this.cleanUpPaste.defer(100, this);
41837 getAllAncestors: function()
41839 var p = this.getSelectedNode();
41842 a.push(p); // push blank onto stack..
41843 p = this.getParentElement();
41847 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41851 a.push(this.doc.body);
41855 lastSelNode : false,
41858 getSelection : function()
41860 this.assignDocWin();
41861 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41864 getSelectedNode: function()
41866 // this may only work on Gecko!!!
41868 // should we cache this!!!!
41873 var range = this.createRange(this.getSelection()).cloneRange();
41876 var parent = range.parentElement();
41878 var testRange = range.duplicate();
41879 testRange.moveToElementText(parent);
41880 if (testRange.inRange(range)) {
41883 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41886 parent = parent.parentElement;
41891 // is ancestor a text element.
41892 var ac = range.commonAncestorContainer;
41893 if (ac.nodeType == 3) {
41894 ac = ac.parentNode;
41897 var ar = ac.childNodes;
41900 var other_nodes = [];
41901 var has_other_nodes = false;
41902 for (var i=0;i<ar.length;i++) {
41903 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41906 // fullly contained node.
41908 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41913 // probably selected..
41914 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41915 other_nodes.push(ar[i]);
41919 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41924 has_other_nodes = true;
41926 if (!nodes.length && other_nodes.length) {
41927 nodes= other_nodes;
41929 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41935 createRange: function(sel)
41937 // this has strange effects when using with
41938 // top toolbar - not sure if it's a great idea.
41939 //this.editor.contentWindow.focus();
41940 if (typeof sel != "undefined") {
41942 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41944 return this.doc.createRange();
41947 return this.doc.createRange();
41950 getParentElement: function()
41953 this.assignDocWin();
41954 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41956 var range = this.createRange(sel);
41959 var p = range.commonAncestorContainer;
41960 while (p.nodeType == 3) { // text node
41971 * Range intersection.. the hard stuff...
41975 * [ -- selected range --- ]
41979 * if end is before start or hits it. fail.
41980 * if start is after end or hits it fail.
41982 * if either hits (but other is outside. - then it's not
41988 // @see http://www.thismuchiknow.co.uk/?p=64.
41989 rangeIntersectsNode : function(range, node)
41991 var nodeRange = node.ownerDocument.createRange();
41993 nodeRange.selectNode(node);
41995 nodeRange.selectNodeContents(node);
41998 var rangeStartRange = range.cloneRange();
41999 rangeStartRange.collapse(true);
42001 var rangeEndRange = range.cloneRange();
42002 rangeEndRange.collapse(false);
42004 var nodeStartRange = nodeRange.cloneRange();
42005 nodeStartRange.collapse(true);
42007 var nodeEndRange = nodeRange.cloneRange();
42008 nodeEndRange.collapse(false);
42010 return rangeStartRange.compareBoundaryPoints(
42011 Range.START_TO_START, nodeEndRange) == -1 &&
42012 rangeEndRange.compareBoundaryPoints(
42013 Range.START_TO_START, nodeStartRange) == 1;
42017 rangeCompareNode : function(range, node)
42019 var nodeRange = node.ownerDocument.createRange();
42021 nodeRange.selectNode(node);
42023 nodeRange.selectNodeContents(node);
42027 range.collapse(true);
42029 nodeRange.collapse(true);
42031 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42032 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42034 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42036 var nodeIsBefore = ss == 1;
42037 var nodeIsAfter = ee == -1;
42039 if (nodeIsBefore && nodeIsAfter)
42041 if (!nodeIsBefore && nodeIsAfter)
42042 return 1; //right trailed.
42044 if (nodeIsBefore && !nodeIsAfter)
42045 return 2; // left trailed.
42050 // private? - in a new class?
42051 cleanUpPaste : function()
42053 // cleans up the whole document..
42054 Roo.log('cleanuppaste');
42056 this.cleanUpChildren(this.doc.body);
42057 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42058 if (clean != this.doc.body.innerHTML) {
42059 this.doc.body.innerHTML = clean;
42064 cleanWordChars : function(input) {// change the chars to hex code
42065 var he = Roo.HtmlEditorCore;
42067 var output = input;
42068 Roo.each(he.swapCodes, function(sw) {
42069 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42071 output = output.replace(swapper, sw[1]);
42078 cleanUpChildren : function (n)
42080 if (!n.childNodes.length) {
42083 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42084 this.cleanUpChild(n.childNodes[i]);
42091 cleanUpChild : function (node)
42094 //console.log(node);
42095 if (node.nodeName == "#text") {
42096 // clean up silly Windows -- stuff?
42099 if (node.nodeName == "#comment") {
42100 node.parentNode.removeChild(node);
42101 // clean up silly Windows -- stuff?
42104 var lcname = node.tagName.toLowerCase();
42105 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42106 // whitelist of tags..
42108 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42110 node.parentNode.removeChild(node);
42115 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42117 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42118 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42120 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42121 // remove_keep_children = true;
42124 if (remove_keep_children) {
42125 this.cleanUpChildren(node);
42126 // inserts everything just before this node...
42127 while (node.childNodes.length) {
42128 var cn = node.childNodes[0];
42129 node.removeChild(cn);
42130 node.parentNode.insertBefore(cn, node);
42132 node.parentNode.removeChild(node);
42136 if (!node.attributes || !node.attributes.length) {
42137 this.cleanUpChildren(node);
42141 function cleanAttr(n,v)
42144 if (v.match(/^\./) || v.match(/^\//)) {
42147 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42150 if (v.match(/^#/)) {
42153 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42154 node.removeAttribute(n);
42158 var cwhite = this.cwhite;
42159 var cblack = this.cblack;
42161 function cleanStyle(n,v)
42163 if (v.match(/expression/)) { //XSS?? should we even bother..
42164 node.removeAttribute(n);
42168 var parts = v.split(/;/);
42171 Roo.each(parts, function(p) {
42172 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42176 var l = p.split(':').shift().replace(/\s+/g,'');
42177 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42179 if ( cwhite.length && cblack.indexOf(l) > -1) {
42180 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42181 //node.removeAttribute(n);
42185 // only allow 'c whitelisted system attributes'
42186 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42187 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42188 //node.removeAttribute(n);
42198 if (clean.length) {
42199 node.setAttribute(n, clean.join(';'));
42201 node.removeAttribute(n);
42207 for (var i = node.attributes.length-1; i > -1 ; i--) {
42208 var a = node.attributes[i];
42211 if (a.name.toLowerCase().substr(0,2)=='on') {
42212 node.removeAttribute(a.name);
42215 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42216 node.removeAttribute(a.name);
42219 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42220 cleanAttr(a.name,a.value); // fixme..
42223 if (a.name == 'style') {
42224 cleanStyle(a.name,a.value);
42227 /// clean up MS crap..
42228 // tecnically this should be a list of valid class'es..
42231 if (a.name == 'class') {
42232 if (a.value.match(/^Mso/)) {
42233 node.className = '';
42236 if (a.value.match(/body/)) {
42237 node.className = '';
42248 this.cleanUpChildren(node);
42254 * Clean up MS wordisms...
42256 cleanWord : function(node)
42261 this.cleanWord(this.doc.body);
42264 if (node.nodeName == "#text") {
42265 // clean up silly Windows -- stuff?
42268 if (node.nodeName == "#comment") {
42269 node.parentNode.removeChild(node);
42270 // clean up silly Windows -- stuff?
42274 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42275 node.parentNode.removeChild(node);
42279 // remove - but keep children..
42280 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42281 while (node.childNodes.length) {
42282 var cn = node.childNodes[0];
42283 node.removeChild(cn);
42284 node.parentNode.insertBefore(cn, node);
42286 node.parentNode.removeChild(node);
42287 this.iterateChildren(node, this.cleanWord);
42291 if (node.className.length) {
42293 var cn = node.className.split(/\W+/);
42295 Roo.each(cn, function(cls) {
42296 if (cls.match(/Mso[a-zA-Z]+/)) {
42301 node.className = cna.length ? cna.join(' ') : '';
42303 node.removeAttribute("class");
42307 if (node.hasAttribute("lang")) {
42308 node.removeAttribute("lang");
42311 if (node.hasAttribute("style")) {
42313 var styles = node.getAttribute("style").split(";");
42315 Roo.each(styles, function(s) {
42316 if (!s.match(/:/)) {
42319 var kv = s.split(":");
42320 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42323 // what ever is left... we allow.
42326 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42327 if (!nstyle.length) {
42328 node.removeAttribute('style');
42331 this.iterateChildren(node, this.cleanWord);
42337 * iterateChildren of a Node, calling fn each time, using this as the scole..
42338 * @param {DomNode} node node to iterate children of.
42339 * @param {Function} fn method of this class to call on each item.
42341 iterateChildren : function(node, fn)
42343 if (!node.childNodes.length) {
42346 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42347 fn.call(this, node.childNodes[i])
42353 * cleanTableWidths.
42355 * Quite often pasting from word etc.. results in tables with column and widths.
42356 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
42359 cleanTableWidths : function(node)
42364 this.cleanTableWidths(this.doc.body);
42369 if (node.nodeName == "#text" || node.nodeName == "#comment") {
42372 Roo.log(node.tagName);
42373 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
42374 this.iterateChildren(node, this.cleanTableWidths);
42377 if (node.hasAttribute('width')) {
42378 node.removeAttribute('width');
42382 if (node.hasAttribute("style")) {
42385 var styles = node.getAttribute("style").split(";");
42387 Roo.each(styles, function(s) {
42388 if (!s.match(/:/)) {
42391 var kv = s.split(":");
42392 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
42395 // what ever is left... we allow.
42398 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42399 if (!nstyle.length) {
42400 node.removeAttribute('style');
42404 this.iterateChildren(node, this.cleanTableWidths);
42412 domToHTML : function(currentElement, depth, nopadtext) {
42414 depth = depth || 0;
42415 nopadtext = nopadtext || false;
42417 if (!currentElement) {
42418 return this.domToHTML(this.doc.body);
42421 //Roo.log(currentElement);
42423 var allText = false;
42424 var nodeName = currentElement.nodeName;
42425 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42427 if (nodeName == '#text') {
42429 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42434 if (nodeName != 'BODY') {
42437 // Prints the node tagName, such as <A>, <IMG>, etc
42440 for(i = 0; i < currentElement.attributes.length;i++) {
42442 var aname = currentElement.attributes.item(i).name;
42443 if (!currentElement.attributes.item(i).value.length) {
42446 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42449 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42458 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42461 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42466 // Traverse the tree
42468 var currentElementChild = currentElement.childNodes.item(i);
42469 var allText = true;
42470 var innerHTML = '';
42472 while (currentElementChild) {
42473 // Formatting code (indent the tree so it looks nice on the screen)
42474 var nopad = nopadtext;
42475 if (lastnode == 'SPAN') {
42479 if (currentElementChild.nodeName == '#text') {
42480 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42481 toadd = nopadtext ? toadd : toadd.trim();
42482 if (!nopad && toadd.length > 80) {
42483 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42485 innerHTML += toadd;
42488 currentElementChild = currentElement.childNodes.item(i);
42494 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42496 // Recursively traverse the tree structure of the child node
42497 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42498 lastnode = currentElementChild.nodeName;
42500 currentElementChild=currentElement.childNodes.item(i);
42506 // The remaining code is mostly for formatting the tree
42507 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42512 ret+= "</"+tagName+">";
42518 applyBlacklists : function()
42520 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42521 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42525 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42526 if (b.indexOf(tag) > -1) {
42529 this.white.push(tag);
42533 Roo.each(w, function(tag) {
42534 if (b.indexOf(tag) > -1) {
42537 if (this.white.indexOf(tag) > -1) {
42540 this.white.push(tag);
42545 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42546 if (w.indexOf(tag) > -1) {
42549 this.black.push(tag);
42553 Roo.each(b, function(tag) {
42554 if (w.indexOf(tag) > -1) {
42557 if (this.black.indexOf(tag) > -1) {
42560 this.black.push(tag);
42565 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42566 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42570 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42571 if (b.indexOf(tag) > -1) {
42574 this.cwhite.push(tag);
42578 Roo.each(w, function(tag) {
42579 if (b.indexOf(tag) > -1) {
42582 if (this.cwhite.indexOf(tag) > -1) {
42585 this.cwhite.push(tag);
42590 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42591 if (w.indexOf(tag) > -1) {
42594 this.cblack.push(tag);
42598 Roo.each(b, function(tag) {
42599 if (w.indexOf(tag) > -1) {
42602 if (this.cblack.indexOf(tag) > -1) {
42605 this.cblack.push(tag);
42610 setStylesheets : function(stylesheets)
42612 if(typeof(stylesheets) == 'string'){
42613 Roo.get(this.iframe.contentDocument.head).createChild({
42615 rel : 'stylesheet',
42624 Roo.each(stylesheets, function(s) {
42629 Roo.get(_this.iframe.contentDocument.head).createChild({
42631 rel : 'stylesheet',
42640 removeStylesheets : function()
42644 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42649 // hide stuff that is not compatible
42663 * @event specialkey
42667 * @cfg {String} fieldClass @hide
42670 * @cfg {String} focusClass @hide
42673 * @cfg {String} autoCreate @hide
42676 * @cfg {String} inputType @hide
42679 * @cfg {String} invalidClass @hide
42682 * @cfg {String} invalidText @hide
42685 * @cfg {String} msgFx @hide
42688 * @cfg {String} validateOnBlur @hide
42692 Roo.HtmlEditorCore.white = [
42693 'area', 'br', 'img', 'input', 'hr', 'wbr',
42695 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42696 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42697 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42698 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42699 'table', 'ul', 'xmp',
42701 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42704 'dir', 'menu', 'ol', 'ul', 'dl',
42710 Roo.HtmlEditorCore.black = [
42711 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42713 'base', 'basefont', 'bgsound', 'blink', 'body',
42714 'frame', 'frameset', 'head', 'html', 'ilayer',
42715 'iframe', 'layer', 'link', 'meta', 'object',
42716 'script', 'style' ,'title', 'xml' // clean later..
42718 Roo.HtmlEditorCore.clean = [
42719 'script', 'style', 'title', 'xml'
42721 Roo.HtmlEditorCore.remove = [
42726 Roo.HtmlEditorCore.ablack = [
42730 Roo.HtmlEditorCore.aclean = [
42731 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42735 Roo.HtmlEditorCore.pwhite= [
42736 'http', 'https', 'mailto'
42739 // white listed style attributes.
42740 Roo.HtmlEditorCore.cwhite= [
42741 // 'text-align', /// default is to allow most things..
42747 // black listed style attributes.
42748 Roo.HtmlEditorCore.cblack= [
42749 // 'font-size' -- this can be set by the project
42753 Roo.HtmlEditorCore.swapCodes =[
42764 //<script type="text/javascript">
42767 * Ext JS Library 1.1.1
42768 * Copyright(c) 2006-2007, Ext JS, LLC.
42774 Roo.form.HtmlEditor = function(config){
42778 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42780 if (!this.toolbars) {
42781 this.toolbars = [];
42783 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42789 * @class Roo.form.HtmlEditor
42790 * @extends Roo.form.Field
42791 * Provides a lightweight HTML Editor component.
42793 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42795 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42796 * supported by this editor.</b><br/><br/>
42797 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42798 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42800 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42802 * @cfg {Boolean} clearUp
42806 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42811 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42816 * @cfg {Number} height (in pixels)
42820 * @cfg {Number} width (in pixels)
42825 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42828 stylesheets: false,
42832 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42837 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42843 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42848 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42856 // private properties
42857 validationEvent : false,
42859 initialized : false,
42862 onFocus : Roo.emptyFn,
42864 hideMode:'offsets',
42866 actionMode : 'container', // defaults to hiding it...
42868 defaultAutoCreate : { // modified by initCompnoent..
42870 style:"width:500px;height:300px;",
42871 autocomplete: "new-password"
42875 initComponent : function(){
42878 * @event initialize
42879 * Fires when the editor is fully initialized (including the iframe)
42880 * @param {HtmlEditor} this
42885 * Fires when the editor is first receives the focus. Any insertion must wait
42886 * until after this event.
42887 * @param {HtmlEditor} this
42891 * @event beforesync
42892 * Fires before the textarea is updated with content from the editor iframe. Return false
42893 * to cancel the sync.
42894 * @param {HtmlEditor} this
42895 * @param {String} html
42899 * @event beforepush
42900 * Fires before the iframe editor is updated with content from the textarea. Return false
42901 * to cancel the push.
42902 * @param {HtmlEditor} this
42903 * @param {String} html
42908 * Fires when the textarea is updated with content from the editor iframe.
42909 * @param {HtmlEditor} this
42910 * @param {String} html
42915 * Fires when the iframe editor is updated with content from the textarea.
42916 * @param {HtmlEditor} this
42917 * @param {String} html
42921 * @event editmodechange
42922 * Fires when the editor switches edit modes
42923 * @param {HtmlEditor} this
42924 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42926 editmodechange: true,
42928 * @event editorevent
42929 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42930 * @param {HtmlEditor} this
42934 * @event firstfocus
42935 * Fires when on first focus - needed by toolbars..
42936 * @param {HtmlEditor} this
42941 * Auto save the htmlEditor value as a file into Events
42942 * @param {HtmlEditor} this
42946 * @event savedpreview
42947 * preview the saved version of htmlEditor
42948 * @param {HtmlEditor} this
42950 savedpreview: true,
42953 * @event stylesheetsclick
42954 * Fires when press the Sytlesheets button
42955 * @param {Roo.HtmlEditorCore} this
42957 stylesheetsclick: true
42959 this.defaultAutoCreate = {
42961 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42962 autocomplete: "new-password"
42967 * Protected method that will not generally be called directly. It
42968 * is called when the editor creates its toolbar. Override this method if you need to
42969 * add custom toolbar buttons.
42970 * @param {HtmlEditor} editor
42972 createToolbar : function(editor){
42973 Roo.log("create toolbars");
42974 if (!editor.toolbars || !editor.toolbars.length) {
42975 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42978 for (var i =0 ; i < editor.toolbars.length;i++) {
42979 editor.toolbars[i] = Roo.factory(
42980 typeof(editor.toolbars[i]) == 'string' ?
42981 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42982 Roo.form.HtmlEditor);
42983 editor.toolbars[i].init(editor);
42991 onRender : function(ct, position)
42994 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42996 this.wrap = this.el.wrap({
42997 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
43000 this.editorcore.onRender(ct, position);
43002 if (this.resizable) {
43003 this.resizeEl = new Roo.Resizable(this.wrap, {
43007 minHeight : this.height,
43008 height: this.height,
43009 handles : this.resizable,
43012 resize : function(r, w, h) {
43013 _t.onResize(w,h); // -something
43019 this.createToolbar(this);
43023 this.setSize(this.wrap.getSize());
43025 if (this.resizeEl) {
43026 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
43027 // should trigger onReize..
43030 this.keyNav = new Roo.KeyNav(this.el, {
43032 "tab" : function(e){
43033 e.preventDefault();
43035 var value = this.getValue();
43037 var start = this.el.dom.selectionStart;
43038 var end = this.el.dom.selectionEnd;
43042 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
43043 this.el.dom.setSelectionRange(end + 1, end + 1);
43047 var f = value.substring(0, start).split("\t");
43049 if(f.pop().length != 0){
43053 this.setValue(f.join("\t") + value.substring(end));
43054 this.el.dom.setSelectionRange(start - 1, start - 1);
43058 "home" : function(e){
43059 e.preventDefault();
43061 var curr = this.el.dom.selectionStart;
43062 var lines = this.getValue().split("\n");
43069 this.el.dom.setSelectionRange(0, 0);
43075 for (var i = 0; i < lines.length;i++) {
43076 pos += lines[i].length;
43086 pos -= lines[i].length;
43092 this.el.dom.setSelectionRange(pos, pos);
43096 this.el.dom.selectionStart = pos;
43097 this.el.dom.selectionEnd = curr;
43100 "end" : function(e){
43101 e.preventDefault();
43103 var curr = this.el.dom.selectionStart;
43104 var lines = this.getValue().split("\n");
43111 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43117 for (var i = 0; i < lines.length;i++) {
43119 pos += lines[i].length;
43133 this.el.dom.setSelectionRange(pos, pos);
43137 this.el.dom.selectionStart = curr;
43138 this.el.dom.selectionEnd = pos;
43143 doRelay : function(foo, bar, hname){
43144 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43150 // if(this.autosave && this.w){
43151 // this.autoSaveFn = setInterval(this.autosave, 1000);
43156 onResize : function(w, h)
43158 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43163 if(typeof w == 'number'){
43164 var aw = w - this.wrap.getFrameWidth('lr');
43165 this.el.setWidth(this.adjustWidth('textarea', aw));
43168 if(typeof h == 'number'){
43170 for (var i =0; i < this.toolbars.length;i++) {
43171 // fixme - ask toolbars for heights?
43172 tbh += this.toolbars[i].tb.el.getHeight();
43173 if (this.toolbars[i].footer) {
43174 tbh += this.toolbars[i].footer.el.getHeight();
43181 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43182 ah -= 5; // knock a few pixes off for look..
43184 this.el.setHeight(this.adjustWidth('textarea', ah));
43188 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43189 this.editorcore.onResize(ew,eh);
43194 * Toggles the editor between standard and source edit mode.
43195 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43197 toggleSourceEdit : function(sourceEditMode)
43199 this.editorcore.toggleSourceEdit(sourceEditMode);
43201 if(this.editorcore.sourceEditMode){
43202 Roo.log('editor - showing textarea');
43205 // Roo.log(this.syncValue());
43206 this.editorcore.syncValue();
43207 this.el.removeClass('x-hidden');
43208 this.el.dom.removeAttribute('tabIndex');
43211 for (var i = 0; i < this.toolbars.length; i++) {
43212 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43213 this.toolbars[i].tb.hide();
43214 this.toolbars[i].footer.hide();
43219 Roo.log('editor - hiding textarea');
43221 // Roo.log(this.pushValue());
43222 this.editorcore.pushValue();
43224 this.el.addClass('x-hidden');
43225 this.el.dom.setAttribute('tabIndex', -1);
43227 for (var i = 0; i < this.toolbars.length; i++) {
43228 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43229 this.toolbars[i].tb.show();
43230 this.toolbars[i].footer.show();
43234 //this.deferFocus();
43237 this.setSize(this.wrap.getSize());
43238 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43240 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43243 // private (for BoxComponent)
43244 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43246 // private (for BoxComponent)
43247 getResizeEl : function(){
43251 // private (for BoxComponent)
43252 getPositionEl : function(){
43257 initEvents : function(){
43258 this.originalValue = this.getValue();
43262 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43265 markInvalid : Roo.emptyFn,
43267 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43270 clearInvalid : Roo.emptyFn,
43272 setValue : function(v){
43273 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43274 this.editorcore.pushValue();
43279 deferFocus : function(){
43280 this.focus.defer(10, this);
43284 focus : function(){
43285 this.editorcore.focus();
43291 onDestroy : function(){
43297 for (var i =0; i < this.toolbars.length;i++) {
43298 // fixme - ask toolbars for heights?
43299 this.toolbars[i].onDestroy();
43302 this.wrap.dom.innerHTML = '';
43303 this.wrap.remove();
43308 onFirstFocus : function(){
43309 //Roo.log("onFirstFocus");
43310 this.editorcore.onFirstFocus();
43311 for (var i =0; i < this.toolbars.length;i++) {
43312 this.toolbars[i].onFirstFocus();
43318 syncValue : function()
43320 this.editorcore.syncValue();
43323 pushValue : function()
43325 this.editorcore.pushValue();
43328 setStylesheets : function(stylesheets)
43330 this.editorcore.setStylesheets(stylesheets);
43333 removeStylesheets : function()
43335 this.editorcore.removeStylesheets();
43339 // hide stuff that is not compatible
43353 * @event specialkey
43357 * @cfg {String} fieldClass @hide
43360 * @cfg {String} focusClass @hide
43363 * @cfg {String} autoCreate @hide
43366 * @cfg {String} inputType @hide
43369 * @cfg {String} invalidClass @hide
43372 * @cfg {String} invalidText @hide
43375 * @cfg {String} msgFx @hide
43378 * @cfg {String} validateOnBlur @hide
43382 // <script type="text/javascript">
43385 * Ext JS Library 1.1.1
43386 * Copyright(c) 2006-2007, Ext JS, LLC.
43392 * @class Roo.form.HtmlEditorToolbar1
43397 new Roo.form.HtmlEditor({
43400 new Roo.form.HtmlEditorToolbar1({
43401 disable : { fonts: 1 , format: 1, ..., ... , ...],
43407 * @cfg {Object} disable List of elements to disable..
43408 * @cfg {Array} btns List of additional buttons.
43412 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43415 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43418 Roo.apply(this, config);
43420 // default disabled, based on 'good practice'..
43421 this.disable = this.disable || {};
43422 Roo.applyIf(this.disable, {
43425 specialElements : true
43429 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43430 // dont call parent... till later.
43433 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43440 editorcore : false,
43442 * @cfg {Object} disable List of toolbar elements to disable
43449 * @cfg {String} createLinkText The default text for the create link prompt
43451 createLinkText : 'Please enter the URL for the link:',
43453 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43455 defaultLinkValue : 'http:/'+'/',
43459 * @cfg {Array} fontFamilies An array of available font families
43477 // "á" , ?? a acute?
43482 "°" // , // degrees
43484 // "é" , // e ecute
43485 // "ú" , // u ecute?
43488 specialElements : [
43490 text: "Insert Table",
43493 ihtml : '<table><tr><td>Cell</td></tr></table>'
43497 text: "Insert Image",
43500 ihtml : '<img src="about:blank"/>'
43509 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43510 "input:submit", "input:button", "select", "textarea", "label" ],
43513 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43515 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43523 * @cfg {String} defaultFont default font to use.
43525 defaultFont: 'tahoma',
43527 fontSelect : false,
43530 formatCombo : false,
43532 init : function(editor)
43534 this.editor = editor;
43535 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43536 var editorcore = this.editorcore;
43540 var fid = editorcore.frameId;
43542 function btn(id, toggle, handler){
43543 var xid = fid + '-'+ id ;
43547 cls : 'x-btn-icon x-edit-'+id,
43548 enableToggle:toggle !== false,
43549 scope: _t, // was editor...
43550 handler:handler||_t.relayBtnCmd,
43551 clickEvent:'mousedown',
43552 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43559 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43561 // stop form submits
43562 tb.el.on('click', function(e){
43563 e.preventDefault(); // what does this do?
43566 if(!this.disable.font) { // && !Roo.isSafari){
43567 /* why no safari for fonts
43568 editor.fontSelect = tb.el.createChild({
43571 cls:'x-font-select',
43572 html: this.createFontOptions()
43575 editor.fontSelect.on('change', function(){
43576 var font = editor.fontSelect.dom.value;
43577 editor.relayCmd('fontname', font);
43578 editor.deferFocus();
43582 editor.fontSelect.dom,
43588 if(!this.disable.formats){
43589 this.formatCombo = new Roo.form.ComboBox({
43590 store: new Roo.data.SimpleStore({
43593 data : this.formats // from states.js
43597 //autoCreate : {tag: "div", size: "20"},
43598 displayField:'tag',
43602 triggerAction: 'all',
43603 emptyText:'Add tag',
43604 selectOnFocus:true,
43607 'select': function(c, r, i) {
43608 editorcore.insertTag(r.get('tag'));
43614 tb.addField(this.formatCombo);
43618 if(!this.disable.format){
43625 if(!this.disable.fontSize){
43630 btn('increasefontsize', false, editorcore.adjustFont),
43631 btn('decreasefontsize', false, editorcore.adjustFont)
43636 if(!this.disable.colors){
43639 id:editorcore.frameId +'-forecolor',
43640 cls:'x-btn-icon x-edit-forecolor',
43641 clickEvent:'mousedown',
43642 tooltip: this.buttonTips['forecolor'] || undefined,
43644 menu : new Roo.menu.ColorMenu({
43645 allowReselect: true,
43646 focus: Roo.emptyFn,
43649 selectHandler: function(cp, color){
43650 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43651 editor.deferFocus();
43654 clickEvent:'mousedown'
43657 id:editorcore.frameId +'backcolor',
43658 cls:'x-btn-icon x-edit-backcolor',
43659 clickEvent:'mousedown',
43660 tooltip: this.buttonTips['backcolor'] || undefined,
43662 menu : new Roo.menu.ColorMenu({
43663 focus: Roo.emptyFn,
43666 allowReselect: true,
43667 selectHandler: function(cp, color){
43669 editorcore.execCmd('useCSS', false);
43670 editorcore.execCmd('hilitecolor', color);
43671 editorcore.execCmd('useCSS', true);
43672 editor.deferFocus();
43674 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43675 Roo.isSafari || Roo.isIE ? '#'+color : color);
43676 editor.deferFocus();
43680 clickEvent:'mousedown'
43685 // now add all the items...
43688 if(!this.disable.alignments){
43691 btn('justifyleft'),
43692 btn('justifycenter'),
43693 btn('justifyright')
43697 //if(!Roo.isSafari){
43698 if(!this.disable.links){
43701 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43705 if(!this.disable.lists){
43708 btn('insertorderedlist'),
43709 btn('insertunorderedlist')
43712 if(!this.disable.sourceEdit){
43715 btn('sourceedit', true, function(btn){
43716 this.toggleSourceEdit(btn.pressed);
43723 // special menu.. - needs to be tidied up..
43724 if (!this.disable.special) {
43727 cls: 'x-edit-none',
43733 for (var i =0; i < this.specialChars.length; i++) {
43734 smenu.menu.items.push({
43736 html: this.specialChars[i],
43737 handler: function(a,b) {
43738 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43739 //editor.insertAtCursor(a.html);
43753 if (!this.disable.cleanStyles) {
43755 cls: 'x-btn-icon x-btn-clear',
43761 for (var i =0; i < this.cleanStyles.length; i++) {
43762 cmenu.menu.items.push({
43763 actiontype : this.cleanStyles[i],
43764 html: 'Remove ' + this.cleanStyles[i],
43765 handler: function(a,b) {
43768 var c = Roo.get(editorcore.doc.body);
43769 c.select('[style]').each(function(s) {
43770 s.dom.style.removeProperty(a.actiontype);
43772 editorcore.syncValue();
43777 cmenu.menu.items.push({
43778 actiontype : 'tablewidths',
43779 html: 'Remove Table Widths',
43780 handler: function(a,b) {
43781 editorcore.cleanTableWidths();
43782 editorcore.syncValue();
43786 cmenu.menu.items.push({
43787 actiontype : 'word',
43788 html: 'Remove MS Word Formating',
43789 handler: function(a,b) {
43790 editorcore.cleanWord();
43791 editorcore.syncValue();
43796 cmenu.menu.items.push({
43797 actiontype : 'all',
43798 html: 'Remove All Styles',
43799 handler: function(a,b) {
43801 var c = Roo.get(editorcore.doc.body);
43802 c.select('[style]').each(function(s) {
43803 s.dom.removeAttribute('style');
43805 editorcore.syncValue();
43809 cmenu.menu.items.push({
43810 actiontype : 'tidy',
43811 html: 'Tidy HTML Source',
43812 handler: function(a,b) {
43813 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43814 editorcore.syncValue();
43823 if (!this.disable.specialElements) {
43826 cls: 'x-edit-none',
43831 for (var i =0; i < this.specialElements.length; i++) {
43832 semenu.menu.items.push(
43834 handler: function(a,b) {
43835 editor.insertAtCursor(this.ihtml);
43837 }, this.specialElements[i])
43849 for(var i =0; i< this.btns.length;i++) {
43850 var b = Roo.factory(this.btns[i],Roo.form);
43851 b.cls = 'x-edit-none';
43853 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43854 b.cls += ' x-init-enable';
43857 b.scope = editorcore;
43865 // disable everything...
43867 this.tb.items.each(function(item){
43870 item.id != editorcore.frameId+ '-sourceedit' &&
43871 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43877 this.rendered = true;
43879 // the all the btns;
43880 editor.on('editorevent', this.updateToolbar, this);
43881 // other toolbars need to implement this..
43882 //editor.on('editmodechange', this.updateToolbar, this);
43886 relayBtnCmd : function(btn) {
43887 this.editorcore.relayCmd(btn.cmd);
43889 // private used internally
43890 createLink : function(){
43891 Roo.log("create link?");
43892 var url = prompt(this.createLinkText, this.defaultLinkValue);
43893 if(url && url != 'http:/'+'/'){
43894 this.editorcore.relayCmd('createlink', url);
43900 * Protected method that will not generally be called directly. It triggers
43901 * a toolbar update by reading the markup state of the current selection in the editor.
43903 updateToolbar: function(){
43905 if(!this.editorcore.activated){
43906 this.editor.onFirstFocus();
43910 var btns = this.tb.items.map,
43911 doc = this.editorcore.doc,
43912 frameId = this.editorcore.frameId;
43914 if(!this.disable.font && !Roo.isSafari){
43916 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43917 if(name != this.fontSelect.dom.value){
43918 this.fontSelect.dom.value = name;
43922 if(!this.disable.format){
43923 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43924 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43925 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43927 if(!this.disable.alignments){
43928 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43929 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43930 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43932 if(!Roo.isSafari && !this.disable.lists){
43933 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43934 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43937 var ans = this.editorcore.getAllAncestors();
43938 if (this.formatCombo) {
43941 var store = this.formatCombo.store;
43942 this.formatCombo.setValue("");
43943 for (var i =0; i < ans.length;i++) {
43944 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43946 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43954 // hides menus... - so this cant be on a menu...
43955 Roo.menu.MenuMgr.hideAll();
43957 //this.editorsyncValue();
43961 createFontOptions : function(){
43962 var buf = [], fs = this.fontFamilies, ff, lc;
43966 for(var i = 0, len = fs.length; i< len; i++){
43968 lc = ff.toLowerCase();
43970 '<option value="',lc,'" style="font-family:',ff,';"',
43971 (this.defaultFont == lc ? ' selected="true">' : '>'),
43976 return buf.join('');
43979 toggleSourceEdit : function(sourceEditMode){
43981 Roo.log("toolbar toogle");
43982 if(sourceEditMode === undefined){
43983 sourceEditMode = !this.sourceEditMode;
43985 this.sourceEditMode = sourceEditMode === true;
43986 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43987 // just toggle the button?
43988 if(btn.pressed !== this.sourceEditMode){
43989 btn.toggle(this.sourceEditMode);
43993 if(sourceEditMode){
43994 Roo.log("disabling buttons");
43995 this.tb.items.each(function(item){
43996 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
44002 Roo.log("enabling buttons");
44003 if(this.editorcore.initialized){
44004 this.tb.items.each(function(item){
44010 Roo.log("calling toggole on editor");
44011 // tell the editor that it's been pressed..
44012 this.editor.toggleSourceEdit(sourceEditMode);
44016 * Object collection of toolbar tooltips for the buttons in the editor. The key
44017 * is the command id associated with that button and the value is a valid QuickTips object.
44022 title: 'Bold (Ctrl+B)',
44023 text: 'Make the selected text bold.',
44024 cls: 'x-html-editor-tip'
44027 title: 'Italic (Ctrl+I)',
44028 text: 'Make the selected text italic.',
44029 cls: 'x-html-editor-tip'
44037 title: 'Bold (Ctrl+B)',
44038 text: 'Make the selected text bold.',
44039 cls: 'x-html-editor-tip'
44042 title: 'Italic (Ctrl+I)',
44043 text: 'Make the selected text italic.',
44044 cls: 'x-html-editor-tip'
44047 title: 'Underline (Ctrl+U)',
44048 text: 'Underline the selected text.',
44049 cls: 'x-html-editor-tip'
44051 increasefontsize : {
44052 title: 'Grow Text',
44053 text: 'Increase the font size.',
44054 cls: 'x-html-editor-tip'
44056 decreasefontsize : {
44057 title: 'Shrink Text',
44058 text: 'Decrease the font size.',
44059 cls: 'x-html-editor-tip'
44062 title: 'Text Highlight Color',
44063 text: 'Change the background color of the selected text.',
44064 cls: 'x-html-editor-tip'
44067 title: 'Font Color',
44068 text: 'Change the color of the selected text.',
44069 cls: 'x-html-editor-tip'
44072 title: 'Align Text Left',
44073 text: 'Align text to the left.',
44074 cls: 'x-html-editor-tip'
44077 title: 'Center Text',
44078 text: 'Center text in the editor.',
44079 cls: 'x-html-editor-tip'
44082 title: 'Align Text Right',
44083 text: 'Align text to the right.',
44084 cls: 'x-html-editor-tip'
44086 insertunorderedlist : {
44087 title: 'Bullet List',
44088 text: 'Start a bulleted list.',
44089 cls: 'x-html-editor-tip'
44091 insertorderedlist : {
44092 title: 'Numbered List',
44093 text: 'Start a numbered list.',
44094 cls: 'x-html-editor-tip'
44097 title: 'Hyperlink',
44098 text: 'Make the selected text a hyperlink.',
44099 cls: 'x-html-editor-tip'
44102 title: 'Source Edit',
44103 text: 'Switch to source editing mode.',
44104 cls: 'x-html-editor-tip'
44108 onDestroy : function(){
44111 this.tb.items.each(function(item){
44113 item.menu.removeAll();
44115 item.menu.el.destroy();
44123 onFirstFocus: function() {
44124 this.tb.items.each(function(item){
44133 // <script type="text/javascript">
44136 * Ext JS Library 1.1.1
44137 * Copyright(c) 2006-2007, Ext JS, LLC.
44144 * @class Roo.form.HtmlEditor.ToolbarContext
44149 new Roo.form.HtmlEditor({
44152 { xtype: 'ToolbarStandard', styles : {} }
44153 { xtype: 'ToolbarContext', disable : {} }
44159 * @config : {Object} disable List of elements to disable.. (not done yet.)
44160 * @config : {Object} styles Map of styles available.
44164 Roo.form.HtmlEditor.ToolbarContext = function(config)
44167 Roo.apply(this, config);
44168 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44169 // dont call parent... till later.
44170 this.styles = this.styles || {};
44175 Roo.form.HtmlEditor.ToolbarContext.types = {
44187 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44253 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44258 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44268 style : 'fontFamily',
44269 displayField: 'display',
44270 optname : 'font-family',
44319 // should we really allow this??
44320 // should this just be
44331 style : 'fontFamily',
44332 displayField: 'display',
44333 optname : 'font-family',
44340 style : 'fontFamily',
44341 displayField: 'display',
44342 optname : 'font-family',
44349 style : 'fontFamily',
44350 displayField: 'display',
44351 optname : 'font-family',
44362 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44363 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44365 Roo.form.HtmlEditor.ToolbarContext.options = {
44367 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44368 [ 'Courier New', 'Courier New'],
44369 [ 'Tahoma', 'Tahoma'],
44370 [ 'Times New Roman,serif', 'Times'],
44371 [ 'Verdana','Verdana' ]
44375 // fixme - these need to be configurable..
44378 Roo.form.HtmlEditor.ToolbarContext.types
44381 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44388 editorcore : false,
44390 * @cfg {Object} disable List of toolbar elements to disable
44395 * @cfg {Object} styles List of styles
44396 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44398 * These must be defined in the page, so they get rendered correctly..
44409 init : function(editor)
44411 this.editor = editor;
44412 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44413 var editorcore = this.editorcore;
44415 var fid = editorcore.frameId;
44417 function btn(id, toggle, handler){
44418 var xid = fid + '-'+ id ;
44422 cls : 'x-btn-icon x-edit-'+id,
44423 enableToggle:toggle !== false,
44424 scope: editorcore, // was editor...
44425 handler:handler||editorcore.relayBtnCmd,
44426 clickEvent:'mousedown',
44427 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44431 // create a new element.
44432 var wdiv = editor.wrap.createChild({
44434 }, editor.wrap.dom.firstChild.nextSibling, true);
44436 // can we do this more than once??
44438 // stop form submits
44441 // disable everything...
44442 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44443 this.toolbars = {};
44445 for (var i in ty) {
44447 this.toolbars[i] = this.buildToolbar(ty[i],i);
44449 this.tb = this.toolbars.BODY;
44451 this.buildFooter();
44452 this.footer.show();
44453 editor.on('hide', function( ) { this.footer.hide() }, this);
44454 editor.on('show', function( ) { this.footer.show() }, this);
44457 this.rendered = true;
44459 // the all the btns;
44460 editor.on('editorevent', this.updateToolbar, this);
44461 // other toolbars need to implement this..
44462 //editor.on('editmodechange', this.updateToolbar, this);
44468 * Protected method that will not generally be called directly. It triggers
44469 * a toolbar update by reading the markup state of the current selection in the editor.
44471 * Note you can force an update by calling on('editorevent', scope, false)
44473 updateToolbar: function(editor,ev,sel){
44476 // capture mouse up - this is handy for selecting images..
44477 // perhaps should go somewhere else...
44478 if(!this.editorcore.activated){
44479 this.editor.onFirstFocus();
44485 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44486 // selectNode - might want to handle IE?
44488 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44489 ev.target && ev.target.tagName == 'IMG') {
44490 // they have click on an image...
44491 // let's see if we can change the selection...
44494 var nodeRange = sel.ownerDocument.createRange();
44496 nodeRange.selectNode(sel);
44498 nodeRange.selectNodeContents(sel);
44500 //nodeRange.collapse(true);
44501 var s = this.editorcore.win.getSelection();
44502 s.removeAllRanges();
44503 s.addRange(nodeRange);
44507 var updateFooter = sel ? false : true;
44510 var ans = this.editorcore.getAllAncestors();
44513 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44516 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44517 sel = sel ? sel : this.editorcore.doc.body;
44518 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44521 // pick a menu that exists..
44522 var tn = sel.tagName.toUpperCase();
44523 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44525 tn = sel.tagName.toUpperCase();
44527 var lastSel = this.tb.selectedNode
44529 this.tb.selectedNode = sel;
44531 // if current menu does not match..
44533 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
44536 ///console.log("show: " + tn);
44537 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44540 this.tb.items.first().el.innerHTML = tn + ': ';
44543 // update attributes
44544 if (this.tb.fields) {
44545 this.tb.fields.each(function(e) {
44547 e.setValue(sel.style[e.stylename]);
44550 e.setValue(sel.getAttribute(e.attrname));
44554 var hasStyles = false;
44555 for(var i in this.styles) {
44562 var st = this.tb.fields.item(0);
44564 st.store.removeAll();
44567 var cn = sel.className.split(/\s+/);
44570 if (this.styles['*']) {
44572 Roo.each(this.styles['*'], function(v) {
44573 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44576 if (this.styles[tn]) {
44577 Roo.each(this.styles[tn], function(v) {
44578 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44582 st.store.loadData(avs);
44586 // flag our selected Node.
44587 this.tb.selectedNode = sel;
44590 Roo.menu.MenuMgr.hideAll();
44594 if (!updateFooter) {
44595 //this.footDisp.dom.innerHTML = '';
44598 // update the footer
44602 this.footerEls = ans.reverse();
44603 Roo.each(this.footerEls, function(a,i) {
44604 if (!a) { return; }
44605 html += html.length ? ' > ' : '';
44607 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44612 var sz = this.footDisp.up('td').getSize();
44613 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44614 this.footDisp.dom.style.marginLeft = '5px';
44616 this.footDisp.dom.style.overflow = 'hidden';
44618 this.footDisp.dom.innerHTML = html;
44620 //this.editorsyncValue();
44627 onDestroy : function(){
44630 this.tb.items.each(function(item){
44632 item.menu.removeAll();
44634 item.menu.el.destroy();
44642 onFirstFocus: function() {
44643 // need to do this for all the toolbars..
44644 this.tb.items.each(function(item){
44648 buildToolbar: function(tlist, nm)
44650 var editor = this.editor;
44651 var editorcore = this.editorcore;
44652 // create a new element.
44653 var wdiv = editor.wrap.createChild({
44655 }, editor.wrap.dom.firstChild.nextSibling, true);
44658 var tb = new Roo.Toolbar(wdiv);
44661 tb.add(nm+ ": ");
44664 for(var i in this.styles) {
44669 if (styles && styles.length) {
44671 // this needs a multi-select checkbox...
44672 tb.addField( new Roo.form.ComboBox({
44673 store: new Roo.data.SimpleStore({
44675 fields: ['val', 'selected'],
44678 name : '-roo-edit-className',
44679 attrname : 'className',
44680 displayField: 'val',
44684 triggerAction: 'all',
44685 emptyText:'Select Style',
44686 selectOnFocus:true,
44689 'select': function(c, r, i) {
44690 // initial support only for on class per el..
44691 tb.selectedNode.className = r ? r.get('val') : '';
44692 editorcore.syncValue();
44699 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44700 var tbops = tbc.options;
44702 for (var i in tlist) {
44704 var item = tlist[i];
44705 tb.add(item.title + ": ");
44708 //optname == used so you can configure the options available..
44709 var opts = item.opts ? item.opts : false;
44710 if (item.optname) {
44711 opts = tbops[item.optname];
44716 // opts == pulldown..
44717 tb.addField( new Roo.form.ComboBox({
44718 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44720 fields: ['val', 'display'],
44723 name : '-roo-edit-' + i,
44725 stylename : item.style ? item.style : false,
44726 displayField: item.displayField ? item.displayField : 'val',
44727 valueField : 'val',
44729 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44731 triggerAction: 'all',
44732 emptyText:'Select',
44733 selectOnFocus:true,
44734 width: item.width ? item.width : 130,
44736 'select': function(c, r, i) {
44738 tb.selectedNode.style[c.stylename] = r.get('val');
44741 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44750 tb.addField( new Roo.form.TextField({
44753 //allowBlank:false,
44758 tb.addField( new Roo.form.TextField({
44759 name: '-roo-edit-' + i,
44766 'change' : function(f, nv, ov) {
44767 tb.selectedNode.setAttribute(f.attrname, nv);
44780 text: 'Stylesheets',
44783 click : function ()
44785 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44793 text: 'Remove Tag',
44796 click : function ()
44799 // undo does not work.
44801 var sn = tb.selectedNode;
44803 var pn = sn.parentNode;
44805 var stn = sn.childNodes[0];
44806 var en = sn.childNodes[sn.childNodes.length - 1 ];
44807 while (sn.childNodes.length) {
44808 var node = sn.childNodes[0];
44809 sn.removeChild(node);
44811 pn.insertBefore(node, sn);
44814 pn.removeChild(sn);
44815 var range = editorcore.createRange();
44817 range.setStart(stn,0);
44818 range.setEnd(en,0); //????
44819 //range.selectNode(sel);
44822 var selection = editorcore.getSelection();
44823 selection.removeAllRanges();
44824 selection.addRange(range);
44828 //_this.updateToolbar(null, null, pn);
44829 _this.updateToolbar(null, null, null);
44830 _this.footDisp.dom.innerHTML = '';
44840 tb.el.on('click', function(e){
44841 e.preventDefault(); // what does this do?
44843 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44846 // dont need to disable them... as they will get hidden
44851 buildFooter : function()
44854 var fel = this.editor.wrap.createChild();
44855 this.footer = new Roo.Toolbar(fel);
44856 // toolbar has scrolly on left / right?
44857 var footDisp= new Roo.Toolbar.Fill();
44863 handler : function() {
44864 _t.footDisp.scrollTo('left',0,true)
44868 this.footer.add( footDisp );
44873 handler : function() {
44875 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44879 var fel = Roo.get(footDisp.el);
44880 fel.addClass('x-editor-context');
44881 this.footDispWrap = fel;
44882 this.footDispWrap.overflow = 'hidden';
44884 this.footDisp = fel.createChild();
44885 this.footDispWrap.on('click', this.onContextClick, this)
44889 onContextClick : function (ev,dom)
44891 ev.preventDefault();
44892 var cn = dom.className;
44894 if (!cn.match(/x-ed-loc-/)) {
44897 var n = cn.split('-').pop();
44898 var ans = this.footerEls;
44902 var range = this.editorcore.createRange();
44904 range.selectNodeContents(sel);
44905 //range.selectNode(sel);
44908 var selection = this.editorcore.getSelection();
44909 selection.removeAllRanges();
44910 selection.addRange(range);
44914 this.updateToolbar(null, null, sel);
44931 * Ext JS Library 1.1.1
44932 * Copyright(c) 2006-2007, Ext JS, LLC.
44934 * Originally Released Under LGPL - original licence link has changed is not relivant.
44937 * <script type="text/javascript">
44941 * @class Roo.form.BasicForm
44942 * @extends Roo.util.Observable
44943 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44945 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44946 * @param {Object} config Configuration options
44948 Roo.form.BasicForm = function(el, config){
44949 this.allItems = [];
44950 this.childForms = [];
44951 Roo.apply(this, config);
44953 * The Roo.form.Field items in this form.
44954 * @type MixedCollection
44958 this.items = new Roo.util.MixedCollection(false, function(o){
44959 return o.id || (o.id = Roo.id());
44963 * @event beforeaction
44964 * Fires before any action is performed. Return false to cancel the action.
44965 * @param {Form} this
44966 * @param {Action} action The action to be performed
44968 beforeaction: true,
44970 * @event actionfailed
44971 * Fires when an action fails.
44972 * @param {Form} this
44973 * @param {Action} action The action that failed
44975 actionfailed : true,
44977 * @event actioncomplete
44978 * Fires when an action is completed.
44979 * @param {Form} this
44980 * @param {Action} action The action that completed
44982 actioncomplete : true
44987 Roo.form.BasicForm.superclass.constructor.call(this);
44990 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44992 * @cfg {String} method
44993 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44996 * @cfg {DataReader} reader
44997 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44998 * This is optional as there is built-in support for processing JSON.
45001 * @cfg {DataReader} errorReader
45002 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
45003 * This is completely optional as there is built-in support for processing JSON.
45006 * @cfg {String} url
45007 * The URL to use for form actions if one isn't supplied in the action options.
45010 * @cfg {Boolean} fileUpload
45011 * Set to true if this form is a file upload.
45015 * @cfg {Object} baseParams
45016 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
45021 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
45026 activeAction : null,
45029 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
45030 * or setValues() data instead of when the form was first created.
45032 trackResetOnLoad : false,
45036 * childForms - used for multi-tab forms
45039 childForms : false,
45042 * allItems - full list of fields.
45048 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
45049 * element by passing it or its id or mask the form itself by passing in true.
45052 waitMsgTarget : false,
45055 initEl : function(el){
45056 this.el = Roo.get(el);
45057 this.id = this.el.id || Roo.id();
45058 this.el.on('submit', this.onSubmit, this);
45059 this.el.addClass('x-form');
45063 onSubmit : function(e){
45068 * Returns true if client-side validation on the form is successful.
45071 isValid : function(){
45073 this.items.each(function(f){
45082 * Returns true if any fields in this form have changed since their original load.
45085 isDirty : function(){
45087 this.items.each(function(f){
45097 * Performs a predefined action (submit or load) or custom actions you define on this form.
45098 * @param {String} actionName The name of the action type
45099 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45100 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45101 * accept other config options):
45103 Property Type Description
45104 ---------------- --------------- ----------------------------------------------------------------------------------
45105 url String The url for the action (defaults to the form's url)
45106 method String The form method to use (defaults to the form's method, or POST if not defined)
45107 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45108 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45109 validate the form on the client (defaults to false)
45111 * @return {BasicForm} this
45113 doAction : function(action, options){
45114 if(typeof action == 'string'){
45115 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45117 if(this.fireEvent('beforeaction', this, action) !== false){
45118 this.beforeAction(action);
45119 action.run.defer(100, action);
45125 * Shortcut to do a submit action.
45126 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45127 * @return {BasicForm} this
45129 submit : function(options){
45130 this.doAction('submit', options);
45135 * Shortcut to do a load action.
45136 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45137 * @return {BasicForm} this
45139 load : function(options){
45140 this.doAction('load', options);
45145 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45146 * @param {Record} record The record to edit
45147 * @return {BasicForm} this
45149 updateRecord : function(record){
45150 record.beginEdit();
45151 var fs = record.fields;
45152 fs.each(function(f){
45153 var field = this.findField(f.name);
45155 record.set(f.name, field.getValue());
45163 * Loads an Roo.data.Record into this form.
45164 * @param {Record} record The record to load
45165 * @return {BasicForm} this
45167 loadRecord : function(record){
45168 this.setValues(record.data);
45173 beforeAction : function(action){
45174 var o = action.options;
45177 if(this.waitMsgTarget === true){
45178 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45179 }else if(this.waitMsgTarget){
45180 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45181 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45183 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45189 afterAction : function(action, success){
45190 this.activeAction = null;
45191 var o = action.options;
45193 if(this.waitMsgTarget === true){
45195 }else if(this.waitMsgTarget){
45196 this.waitMsgTarget.unmask();
45198 Roo.MessageBox.updateProgress(1);
45199 Roo.MessageBox.hide();
45206 Roo.callback(o.success, o.scope, [this, action]);
45207 this.fireEvent('actioncomplete', this, action);
45211 // failure condition..
45212 // we have a scenario where updates need confirming.
45213 // eg. if a locking scenario exists..
45214 // we look for { errors : { needs_confirm : true }} in the response.
45216 (typeof(action.result) != 'undefined') &&
45217 (typeof(action.result.errors) != 'undefined') &&
45218 (typeof(action.result.errors.needs_confirm) != 'undefined')
45221 Roo.MessageBox.confirm(
45222 "Change requires confirmation",
45223 action.result.errorMsg,
45228 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45238 Roo.callback(o.failure, o.scope, [this, action]);
45239 // show an error message if no failed handler is set..
45240 if (!this.hasListener('actionfailed')) {
45241 Roo.MessageBox.alert("Error",
45242 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45243 action.result.errorMsg :
45244 "Saving Failed, please check your entries or try again"
45248 this.fireEvent('actionfailed', this, action);
45254 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45255 * @param {String} id The value to search for
45258 findField : function(id){
45259 var field = this.items.get(id);
45261 this.items.each(function(f){
45262 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45268 return field || null;
45272 * Add a secondary form to this one,
45273 * Used to provide tabbed forms. One form is primary, with hidden values
45274 * which mirror the elements from the other forms.
45276 * @param {Roo.form.Form} form to add.
45279 addForm : function(form)
45282 if (this.childForms.indexOf(form) > -1) {
45286 this.childForms.push(form);
45288 Roo.each(form.allItems, function (fe) {
45290 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45291 if (this.findField(n)) { // already added..
45294 var add = new Roo.form.Hidden({
45297 add.render(this.el);
45304 * Mark fields in this form invalid in bulk.
45305 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45306 * @return {BasicForm} this
45308 markInvalid : function(errors){
45309 if(errors instanceof Array){
45310 for(var i = 0, len = errors.length; i < len; i++){
45311 var fieldError = errors[i];
45312 var f = this.findField(fieldError.id);
45314 f.markInvalid(fieldError.msg);
45320 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45321 field.markInvalid(errors[id]);
45325 Roo.each(this.childForms || [], function (f) {
45326 f.markInvalid(errors);
45333 * Set values for fields in this form in bulk.
45334 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45335 * @return {BasicForm} this
45337 setValues : function(values){
45338 if(values instanceof Array){ // array of objects
45339 for(var i = 0, len = values.length; i < len; i++){
45341 var f = this.findField(v.id);
45343 f.setValue(v.value);
45344 if(this.trackResetOnLoad){
45345 f.originalValue = f.getValue();
45349 }else{ // object hash
45352 if(typeof values[id] != 'function' && (field = this.findField(id))){
45354 if (field.setFromData &&
45355 field.valueField &&
45356 field.displayField &&
45357 // combos' with local stores can
45358 // be queried via setValue()
45359 // to set their value..
45360 (field.store && !field.store.isLocal)
45364 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45365 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45366 field.setFromData(sd);
45369 field.setValue(values[id]);
45373 if(this.trackResetOnLoad){
45374 field.originalValue = field.getValue();
45380 Roo.each(this.childForms || [], function (f) {
45381 f.setValues(values);
45388 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45389 * they are returned as an array.
45390 * @param {Boolean} asString
45393 getValues : function(asString){
45394 if (this.childForms) {
45395 // copy values from the child forms
45396 Roo.each(this.childForms, function (f) {
45397 this.setValues(f.getValues());
45403 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45404 if(asString === true){
45407 return Roo.urlDecode(fs);
45411 * Returns the fields in this form as an object with key/value pairs.
45412 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45415 getFieldValues : function(with_hidden)
45417 if (this.childForms) {
45418 // copy values from the child forms
45419 // should this call getFieldValues - probably not as we do not currently copy
45420 // hidden fields when we generate..
45421 Roo.each(this.childForms, function (f) {
45422 this.setValues(f.getValues());
45427 this.items.each(function(f){
45428 if (!f.getName()) {
45431 var v = f.getValue();
45432 if (f.inputType =='radio') {
45433 if (typeof(ret[f.getName()]) == 'undefined') {
45434 ret[f.getName()] = ''; // empty..
45437 if (!f.el.dom.checked) {
45441 v = f.el.dom.value;
45445 // not sure if this supported any more..
45446 if ((typeof(v) == 'object') && f.getRawValue) {
45447 v = f.getRawValue() ; // dates..
45449 // combo boxes where name != hiddenName...
45450 if (f.name != f.getName()) {
45451 ret[f.name] = f.getRawValue();
45453 ret[f.getName()] = v;
45460 * Clears all invalid messages in this form.
45461 * @return {BasicForm} this
45463 clearInvalid : function(){
45464 this.items.each(function(f){
45468 Roo.each(this.childForms || [], function (f) {
45477 * Resets this form.
45478 * @return {BasicForm} this
45480 reset : function(){
45481 this.items.each(function(f){
45485 Roo.each(this.childForms || [], function (f) {
45494 * Add Roo.form components to this form.
45495 * @param {Field} field1
45496 * @param {Field} field2 (optional)
45497 * @param {Field} etc (optional)
45498 * @return {BasicForm} this
45501 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45507 * Removes a field from the items collection (does NOT remove its markup).
45508 * @param {Field} field
45509 * @return {BasicForm} this
45511 remove : function(field){
45512 this.items.remove(field);
45517 * Looks at the fields in this form, checks them for an id attribute,
45518 * and calls applyTo on the existing dom element with that id.
45519 * @return {BasicForm} this
45521 render : function(){
45522 this.items.each(function(f){
45523 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45531 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45532 * @param {Object} values
45533 * @return {BasicForm} this
45535 applyToFields : function(o){
45536 this.items.each(function(f){
45543 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45544 * @param {Object} values
45545 * @return {BasicForm} this
45547 applyIfToFields : function(o){
45548 this.items.each(function(f){
45556 Roo.BasicForm = Roo.form.BasicForm;/*
45558 * Ext JS Library 1.1.1
45559 * Copyright(c) 2006-2007, Ext JS, LLC.
45561 * Originally Released Under LGPL - original licence link has changed is not relivant.
45564 * <script type="text/javascript">
45568 * @class Roo.form.Form
45569 * @extends Roo.form.BasicForm
45570 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45572 * @param {Object} config Configuration options
45574 Roo.form.Form = function(config){
45576 if (config.items) {
45577 xitems = config.items;
45578 delete config.items;
45582 Roo.form.Form.superclass.constructor.call(this, null, config);
45583 this.url = this.url || this.action;
45585 this.root = new Roo.form.Layout(Roo.applyIf({
45589 this.active = this.root;
45591 * Array of all the buttons that have been added to this form via {@link addButton}
45595 this.allItems = [];
45598 * @event clientvalidation
45599 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45600 * @param {Form} this
45601 * @param {Boolean} valid true if the form has passed client-side validation
45603 clientvalidation: true,
45606 * Fires when the form is rendered
45607 * @param {Roo.form.Form} form
45612 if (this.progressUrl) {
45613 // push a hidden field onto the list of fields..
45617 name : 'UPLOAD_IDENTIFIER'
45622 Roo.each(xitems, this.addxtype, this);
45628 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45630 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45633 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45636 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45638 buttonAlign:'center',
45641 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45646 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45647 * This property cascades to child containers if not set.
45652 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45653 * fires a looping event with that state. This is required to bind buttons to the valid
45654 * state using the config value formBind:true on the button.
45656 monitorValid : false,
45659 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45664 * @cfg {String} progressUrl - Url to return progress data
45667 progressUrl : false,
45670 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45671 * fields are added and the column is closed. If no fields are passed the column remains open
45672 * until end() is called.
45673 * @param {Object} config The config to pass to the column
45674 * @param {Field} field1 (optional)
45675 * @param {Field} field2 (optional)
45676 * @param {Field} etc (optional)
45677 * @return Column The column container object
45679 column : function(c){
45680 var col = new Roo.form.Column(c);
45682 if(arguments.length > 1){ // duplicate code required because of Opera
45683 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45690 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45691 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45692 * until end() is called.
45693 * @param {Object} config The config to pass to the fieldset
45694 * @param {Field} field1 (optional)
45695 * @param {Field} field2 (optional)
45696 * @param {Field} etc (optional)
45697 * @return FieldSet The fieldset container object
45699 fieldset : function(c){
45700 var fs = new Roo.form.FieldSet(c);
45702 if(arguments.length > 1){ // duplicate code required because of Opera
45703 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45710 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45711 * fields are added and the container is closed. If no fields are passed the container remains open
45712 * until end() is called.
45713 * @param {Object} config The config to pass to the Layout
45714 * @param {Field} field1 (optional)
45715 * @param {Field} field2 (optional)
45716 * @param {Field} etc (optional)
45717 * @return Layout The container object
45719 container : function(c){
45720 var l = new Roo.form.Layout(c);
45722 if(arguments.length > 1){ // duplicate code required because of Opera
45723 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45730 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45731 * @param {Object} container A Roo.form.Layout or subclass of Layout
45732 * @return {Form} this
45734 start : function(c){
45735 // cascade label info
45736 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45737 this.active.stack.push(c);
45738 c.ownerCt = this.active;
45744 * Closes the current open container
45745 * @return {Form} this
45748 if(this.active == this.root){
45751 this.active = this.active.ownerCt;
45756 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45757 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45758 * as the label of the field.
45759 * @param {Field} field1
45760 * @param {Field} field2 (optional)
45761 * @param {Field} etc. (optional)
45762 * @return {Form} this
45765 this.active.stack.push.apply(this.active.stack, arguments);
45766 this.allItems.push.apply(this.allItems,arguments);
45768 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45769 if(a[i].isFormField){
45774 Roo.form.Form.superclass.add.apply(this, r);
45784 * Find any element that has been added to a form, using it's ID or name
45785 * This can include framesets, columns etc. along with regular fields..
45786 * @param {String} id - id or name to find.
45788 * @return {Element} e - or false if nothing found.
45790 findbyId : function(id)
45796 Roo.each(this.allItems, function(f){
45797 if (f.id == id || f.name == id ){
45808 * Render this form into the passed container. This should only be called once!
45809 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45810 * @return {Form} this
45812 render : function(ct)
45818 var o = this.autoCreate || {
45820 method : this.method || 'POST',
45821 id : this.id || Roo.id()
45823 this.initEl(ct.createChild(o));
45825 this.root.render(this.el);
45829 this.items.each(function(f){
45830 f.render('x-form-el-'+f.id);
45833 if(this.buttons.length > 0){
45834 // tables are required to maintain order and for correct IE layout
45835 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45836 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45837 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45839 var tr = tb.getElementsByTagName('tr')[0];
45840 for(var i = 0, len = this.buttons.length; i < len; i++) {
45841 var b = this.buttons[i];
45842 var td = document.createElement('td');
45843 td.className = 'x-form-btn-td';
45844 b.render(tr.appendChild(td));
45847 if(this.monitorValid){ // initialize after render
45848 this.startMonitoring();
45850 this.fireEvent('rendered', this);
45855 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45856 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45857 * object or a valid Roo.DomHelper element config
45858 * @param {Function} handler The function called when the button is clicked
45859 * @param {Object} scope (optional) The scope of the handler function
45860 * @return {Roo.Button}
45862 addButton : function(config, handler, scope){
45866 minWidth: this.minButtonWidth,
45869 if(typeof config == "string"){
45872 Roo.apply(bc, config);
45874 var btn = new Roo.Button(null, bc);
45875 this.buttons.push(btn);
45880 * Adds a series of form elements (using the xtype property as the factory method.
45881 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45882 * @param {Object} config
45885 addxtype : function()
45887 var ar = Array.prototype.slice.call(arguments, 0);
45889 for(var i = 0; i < ar.length; i++) {
45891 continue; // skip -- if this happends something invalid got sent, we
45892 // should ignore it, as basically that interface element will not show up
45893 // and that should be pretty obvious!!
45896 if (Roo.form[ar[i].xtype]) {
45898 var fe = Roo.factory(ar[i], Roo.form);
45904 fe.store.form = this;
45909 this.allItems.push(fe);
45910 if (fe.items && fe.addxtype) {
45911 fe.addxtype.apply(fe, fe.items);
45921 // console.log('adding ' + ar[i].xtype);
45923 if (ar[i].xtype == 'Button') {
45924 //console.log('adding button');
45925 //console.log(ar[i]);
45926 this.addButton(ar[i]);
45927 this.allItems.push(fe);
45931 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45932 alert('end is not supported on xtype any more, use items');
45934 // //console.log('adding end');
45942 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45943 * option "monitorValid"
45945 startMonitoring : function(){
45948 Roo.TaskMgr.start({
45949 run : this.bindHandler,
45950 interval : this.monitorPoll || 200,
45957 * Stops monitoring of the valid state of this form
45959 stopMonitoring : function(){
45960 this.bound = false;
45964 bindHandler : function(){
45966 return false; // stops binding
45969 this.items.each(function(f){
45970 if(!f.isValid(true)){
45975 for(var i = 0, len = this.buttons.length; i < len; i++){
45976 var btn = this.buttons[i];
45977 if(btn.formBind === true && btn.disabled === valid){
45978 btn.setDisabled(!valid);
45981 this.fireEvent('clientvalidation', this, valid);
45995 Roo.Form = Roo.form.Form;
45998 * Ext JS Library 1.1.1
45999 * Copyright(c) 2006-2007, Ext JS, LLC.
46001 * Originally Released Under LGPL - original licence link has changed is not relivant.
46004 * <script type="text/javascript">
46007 // as we use this in bootstrap.
46008 Roo.namespace('Roo.form');
46010 * @class Roo.form.Action
46011 * Internal Class used to handle form actions
46013 * @param {Roo.form.BasicForm} el The form element or its id
46014 * @param {Object} config Configuration options
46019 // define the action interface
46020 Roo.form.Action = function(form, options){
46022 this.options = options || {};
46025 * Client Validation Failed
46028 Roo.form.Action.CLIENT_INVALID = 'client';
46030 * Server Validation Failed
46033 Roo.form.Action.SERVER_INVALID = 'server';
46035 * Connect to Server Failed
46038 Roo.form.Action.CONNECT_FAILURE = 'connect';
46040 * Reading Data from Server Failed
46043 Roo.form.Action.LOAD_FAILURE = 'load';
46045 Roo.form.Action.prototype = {
46047 failureType : undefined,
46048 response : undefined,
46049 result : undefined,
46051 // interface method
46052 run : function(options){
46056 // interface method
46057 success : function(response){
46061 // interface method
46062 handleResponse : function(response){
46066 // default connection failure
46067 failure : function(response){
46069 this.response = response;
46070 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46071 this.form.afterAction(this, false);
46074 processResponse : function(response){
46075 this.response = response;
46076 if(!response.responseText){
46079 this.result = this.handleResponse(response);
46080 return this.result;
46083 // utility functions used internally
46084 getUrl : function(appendParams){
46085 var url = this.options.url || this.form.url || this.form.el.dom.action;
46087 var p = this.getParams();
46089 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46095 getMethod : function(){
46096 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46099 getParams : function(){
46100 var bp = this.form.baseParams;
46101 var p = this.options.params;
46103 if(typeof p == "object"){
46104 p = Roo.urlEncode(Roo.applyIf(p, bp));
46105 }else if(typeof p == 'string' && bp){
46106 p += '&' + Roo.urlEncode(bp);
46109 p = Roo.urlEncode(bp);
46114 createCallback : function(){
46116 success: this.success,
46117 failure: this.failure,
46119 timeout: (this.form.timeout*1000),
46120 upload: this.form.fileUpload ? this.success : undefined
46125 Roo.form.Action.Submit = function(form, options){
46126 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46129 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46132 haveProgress : false,
46133 uploadComplete : false,
46135 // uploadProgress indicator.
46136 uploadProgress : function()
46138 if (!this.form.progressUrl) {
46142 if (!this.haveProgress) {
46143 Roo.MessageBox.progress("Uploading", "Uploading");
46145 if (this.uploadComplete) {
46146 Roo.MessageBox.hide();
46150 this.haveProgress = true;
46152 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46154 var c = new Roo.data.Connection();
46156 url : this.form.progressUrl,
46161 success : function(req){
46162 //console.log(data);
46166 rdata = Roo.decode(req.responseText)
46168 Roo.log("Invalid data from server..");
46172 if (!rdata || !rdata.success) {
46174 Roo.MessageBox.alert(Roo.encode(rdata));
46177 var data = rdata.data;
46179 if (this.uploadComplete) {
46180 Roo.MessageBox.hide();
46185 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46186 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46189 this.uploadProgress.defer(2000,this);
46192 failure: function(data) {
46193 Roo.log('progress url failed ');
46204 // run get Values on the form, so it syncs any secondary forms.
46205 this.form.getValues();
46207 var o = this.options;
46208 var method = this.getMethod();
46209 var isPost = method == 'POST';
46210 if(o.clientValidation === false || this.form.isValid()){
46212 if (this.form.progressUrl) {
46213 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46214 (new Date() * 1) + '' + Math.random());
46219 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46220 form:this.form.el.dom,
46221 url:this.getUrl(!isPost),
46223 params:isPost ? this.getParams() : null,
46224 isUpload: this.form.fileUpload
46227 this.uploadProgress();
46229 }else if (o.clientValidation !== false){ // client validation failed
46230 this.failureType = Roo.form.Action.CLIENT_INVALID;
46231 this.form.afterAction(this, false);
46235 success : function(response)
46237 this.uploadComplete= true;
46238 if (this.haveProgress) {
46239 Roo.MessageBox.hide();
46243 var result = this.processResponse(response);
46244 if(result === true || result.success){
46245 this.form.afterAction(this, true);
46249 this.form.markInvalid(result.errors);
46250 this.failureType = Roo.form.Action.SERVER_INVALID;
46252 this.form.afterAction(this, false);
46254 failure : function(response)
46256 this.uploadComplete= true;
46257 if (this.haveProgress) {
46258 Roo.MessageBox.hide();
46261 this.response = response;
46262 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46263 this.form.afterAction(this, false);
46266 handleResponse : function(response){
46267 if(this.form.errorReader){
46268 var rs = this.form.errorReader.read(response);
46271 for(var i = 0, len = rs.records.length; i < len; i++) {
46272 var r = rs.records[i];
46273 errors[i] = r.data;
46276 if(errors.length < 1){
46280 success : rs.success,
46286 ret = Roo.decode(response.responseText);
46290 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46300 Roo.form.Action.Load = function(form, options){
46301 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46302 this.reader = this.form.reader;
46305 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46310 Roo.Ajax.request(Roo.apply(
46311 this.createCallback(), {
46312 method:this.getMethod(),
46313 url:this.getUrl(false),
46314 params:this.getParams()
46318 success : function(response){
46320 var result = this.processResponse(response);
46321 if(result === true || !result.success || !result.data){
46322 this.failureType = Roo.form.Action.LOAD_FAILURE;
46323 this.form.afterAction(this, false);
46326 this.form.clearInvalid();
46327 this.form.setValues(result.data);
46328 this.form.afterAction(this, true);
46331 handleResponse : function(response){
46332 if(this.form.reader){
46333 var rs = this.form.reader.read(response);
46334 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46336 success : rs.success,
46340 return Roo.decode(response.responseText);
46344 Roo.form.Action.ACTION_TYPES = {
46345 'load' : Roo.form.Action.Load,
46346 'submit' : Roo.form.Action.Submit
46349 * Ext JS Library 1.1.1
46350 * Copyright(c) 2006-2007, Ext JS, LLC.
46352 * Originally Released Under LGPL - original licence link has changed is not relivant.
46355 * <script type="text/javascript">
46359 * @class Roo.form.Layout
46360 * @extends Roo.Component
46361 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46363 * @param {Object} config Configuration options
46365 Roo.form.Layout = function(config){
46367 if (config.items) {
46368 xitems = config.items;
46369 delete config.items;
46371 Roo.form.Layout.superclass.constructor.call(this, config);
46373 Roo.each(xitems, this.addxtype, this);
46377 Roo.extend(Roo.form.Layout, Roo.Component, {
46379 * @cfg {String/Object} autoCreate
46380 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46383 * @cfg {String/Object/Function} style
46384 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46385 * a function which returns such a specification.
46388 * @cfg {String} labelAlign
46389 * Valid values are "left," "top" and "right" (defaults to "left")
46392 * @cfg {Number} labelWidth
46393 * Fixed width in pixels of all field labels (defaults to undefined)
46396 * @cfg {Boolean} clear
46397 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46401 * @cfg {String} labelSeparator
46402 * The separator to use after field labels (defaults to ':')
46404 labelSeparator : ':',
46406 * @cfg {Boolean} hideLabels
46407 * True to suppress the display of field labels in this layout (defaults to false)
46409 hideLabels : false,
46412 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46417 onRender : function(ct, position){
46418 if(this.el){ // from markup
46419 this.el = Roo.get(this.el);
46420 }else { // generate
46421 var cfg = this.getAutoCreate();
46422 this.el = ct.createChild(cfg, position);
46425 this.el.applyStyles(this.style);
46427 if(this.labelAlign){
46428 this.el.addClass('x-form-label-'+this.labelAlign);
46430 if(this.hideLabels){
46431 this.labelStyle = "display:none";
46432 this.elementStyle = "padding-left:0;";
46434 if(typeof this.labelWidth == 'number'){
46435 this.labelStyle = "width:"+this.labelWidth+"px;";
46436 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46438 if(this.labelAlign == 'top'){
46439 this.labelStyle = "width:auto;";
46440 this.elementStyle = "padding-left:0;";
46443 var stack = this.stack;
46444 var slen = stack.length;
46446 if(!this.fieldTpl){
46447 var t = new Roo.Template(
46448 '<div class="x-form-item {5}">',
46449 '<label for="{0}" style="{2}">{1}{4}</label>',
46450 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46452 '</div><div class="x-form-clear-left"></div>'
46454 t.disableFormats = true;
46456 Roo.form.Layout.prototype.fieldTpl = t;
46458 for(var i = 0; i < slen; i++) {
46459 if(stack[i].isFormField){
46460 this.renderField(stack[i]);
46462 this.renderComponent(stack[i]);
46467 this.el.createChild({cls:'x-form-clear'});
46472 renderField : function(f){
46473 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46476 f.labelStyle||this.labelStyle||'', //2
46477 this.elementStyle||'', //3
46478 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46479 f.itemCls||this.itemCls||'' //5
46480 ], true).getPrevSibling());
46484 renderComponent : function(c){
46485 c.render(c.isLayout ? this.el : this.el.createChild());
46488 * Adds a object form elements (using the xtype property as the factory method.)
46489 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46490 * @param {Object} config
46492 addxtype : function(o)
46494 // create the lement.
46495 o.form = this.form;
46496 var fe = Roo.factory(o, Roo.form);
46497 this.form.allItems.push(fe);
46498 this.stack.push(fe);
46500 if (fe.isFormField) {
46501 this.form.items.add(fe);
46509 * @class Roo.form.Column
46510 * @extends Roo.form.Layout
46511 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46513 * @param {Object} config Configuration options
46515 Roo.form.Column = function(config){
46516 Roo.form.Column.superclass.constructor.call(this, config);
46519 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46521 * @cfg {Number/String} width
46522 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46525 * @cfg {String/Object} autoCreate
46526 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46530 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46533 onRender : function(ct, position){
46534 Roo.form.Column.superclass.onRender.call(this, ct, position);
46536 this.el.setWidth(this.width);
46543 * @class Roo.form.Row
46544 * @extends Roo.form.Layout
46545 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46547 * @param {Object} config Configuration options
46551 Roo.form.Row = function(config){
46552 Roo.form.Row.superclass.constructor.call(this, config);
46555 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46557 * @cfg {Number/String} width
46558 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46561 * @cfg {Number/String} height
46562 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46564 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46568 onRender : function(ct, position){
46569 //console.log('row render');
46571 var t = new Roo.Template(
46572 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46573 '<label for="{0}" style="{2}">{1}{4}</label>',
46574 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46578 t.disableFormats = true;
46580 Roo.form.Layout.prototype.rowTpl = t;
46582 this.fieldTpl = this.rowTpl;
46584 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46585 var labelWidth = 100;
46587 if ((this.labelAlign != 'top')) {
46588 if (typeof this.labelWidth == 'number') {
46589 labelWidth = this.labelWidth
46591 this.padWidth = 20 + labelWidth;
46595 Roo.form.Column.superclass.onRender.call(this, ct, position);
46597 this.el.setWidth(this.width);
46600 this.el.setHeight(this.height);
46605 renderField : function(f){
46606 f.fieldEl = this.fieldTpl.append(this.el, [
46607 f.id, f.fieldLabel,
46608 f.labelStyle||this.labelStyle||'',
46609 this.elementStyle||'',
46610 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46611 f.itemCls||this.itemCls||'',
46612 f.width ? f.width + this.padWidth : 160 + this.padWidth
46619 * @class Roo.form.FieldSet
46620 * @extends Roo.form.Layout
46621 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46623 * @param {Object} config Configuration options
46625 Roo.form.FieldSet = function(config){
46626 Roo.form.FieldSet.superclass.constructor.call(this, config);
46629 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46631 * @cfg {String} legend
46632 * The text to display as the legend for the FieldSet (defaults to '')
46635 * @cfg {String/Object} autoCreate
46636 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46640 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46643 onRender : function(ct, position){
46644 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46646 this.setLegend(this.legend);
46651 setLegend : function(text){
46653 this.el.child('legend').update(text);
46658 * Ext JS Library 1.1.1
46659 * Copyright(c) 2006-2007, Ext JS, LLC.
46661 * Originally Released Under LGPL - original licence link has changed is not relivant.
46664 * <script type="text/javascript">
46667 * @class Roo.form.VTypes
46668 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46671 Roo.form.VTypes = function(){
46672 // closure these in so they are only created once.
46673 var alpha = /^[a-zA-Z_]+$/;
46674 var alphanum = /^[a-zA-Z0-9_]+$/;
46675 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46676 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46678 // All these messages and functions are configurable
46681 * The function used to validate email addresses
46682 * @param {String} value The email address
46684 'email' : function(v){
46685 return email.test(v);
46688 * The error text to display when the email validation function returns false
46691 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46693 * The keystroke filter mask to be applied on email input
46696 'emailMask' : /[a-z0-9_\.\-@]/i,
46699 * The function used to validate URLs
46700 * @param {String} value The URL
46702 'url' : function(v){
46703 return url.test(v);
46706 * The error text to display when the url validation function returns false
46709 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46712 * The function used to validate alpha values
46713 * @param {String} value The value
46715 'alpha' : function(v){
46716 return alpha.test(v);
46719 * The error text to display when the alpha validation function returns false
46722 'alphaText' : 'This field should only contain letters and _',
46724 * The keystroke filter mask to be applied on alpha input
46727 'alphaMask' : /[a-z_]/i,
46730 * The function used to validate alphanumeric values
46731 * @param {String} value The value
46733 'alphanum' : function(v){
46734 return alphanum.test(v);
46737 * The error text to display when the alphanumeric validation function returns false
46740 'alphanumText' : 'This field should only contain letters, numbers and _',
46742 * The keystroke filter mask to be applied on alphanumeric input
46745 'alphanumMask' : /[a-z0-9_]/i
46747 }();//<script type="text/javascript">
46750 * @class Roo.form.FCKeditor
46751 * @extends Roo.form.TextArea
46752 * Wrapper around the FCKEditor http://www.fckeditor.net
46754 * Creates a new FCKeditor
46755 * @param {Object} config Configuration options
46757 Roo.form.FCKeditor = function(config){
46758 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46761 * @event editorinit
46762 * Fired when the editor is initialized - you can add extra handlers here..
46763 * @param {FCKeditor} this
46764 * @param {Object} the FCK object.
46771 Roo.form.FCKeditor.editors = { };
46772 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46774 //defaultAutoCreate : {
46775 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46779 * @cfg {Object} fck options - see fck manual for details.
46784 * @cfg {Object} fck toolbar set (Basic or Default)
46786 toolbarSet : 'Basic',
46788 * @cfg {Object} fck BasePath
46790 basePath : '/fckeditor/',
46798 onRender : function(ct, position)
46801 this.defaultAutoCreate = {
46803 style:"width:300px;height:60px;",
46804 autocomplete: "new-password"
46807 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46810 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46811 if(this.preventScrollbars){
46812 this.el.setStyle("overflow", "hidden");
46814 this.el.setHeight(this.growMin);
46817 //console.log('onrender' + this.getId() );
46818 Roo.form.FCKeditor.editors[this.getId()] = this;
46821 this.replaceTextarea() ;
46825 getEditor : function() {
46826 return this.fckEditor;
46829 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46830 * @param {Mixed} value The value to set
46834 setValue : function(value)
46836 //console.log('setValue: ' + value);
46838 if(typeof(value) == 'undefined') { // not sure why this is happending...
46841 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46843 //if(!this.el || !this.getEditor()) {
46844 // this.value = value;
46845 //this.setValue.defer(100,this,[value]);
46849 if(!this.getEditor()) {
46853 this.getEditor().SetData(value);
46860 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46861 * @return {Mixed} value The field value
46863 getValue : function()
46866 if (this.frame && this.frame.dom.style.display == 'none') {
46867 return Roo.form.FCKeditor.superclass.getValue.call(this);
46870 if(!this.el || !this.getEditor()) {
46872 // this.getValue.defer(100,this);
46877 var value=this.getEditor().GetData();
46878 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46879 return Roo.form.FCKeditor.superclass.getValue.call(this);
46885 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46886 * @return {Mixed} value The field value
46888 getRawValue : function()
46890 if (this.frame && this.frame.dom.style.display == 'none') {
46891 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46894 if(!this.el || !this.getEditor()) {
46895 //this.getRawValue.defer(100,this);
46902 var value=this.getEditor().GetData();
46903 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46904 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46908 setSize : function(w,h) {
46912 //if (this.frame && this.frame.dom.style.display == 'none') {
46913 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46916 //if(!this.el || !this.getEditor()) {
46917 // this.setSize.defer(100,this, [w,h]);
46923 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46925 this.frame.dom.setAttribute('width', w);
46926 this.frame.dom.setAttribute('height', h);
46927 this.frame.setSize(w,h);
46931 toggleSourceEdit : function(value) {
46935 this.el.dom.style.display = value ? '' : 'none';
46936 this.frame.dom.style.display = value ? 'none' : '';
46941 focus: function(tag)
46943 if (this.frame.dom.style.display == 'none') {
46944 return Roo.form.FCKeditor.superclass.focus.call(this);
46946 if(!this.el || !this.getEditor()) {
46947 this.focus.defer(100,this, [tag]);
46954 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46955 this.getEditor().Focus();
46957 if (!this.getEditor().Selection.GetSelection()) {
46958 this.focus.defer(100,this, [tag]);
46963 var r = this.getEditor().EditorDocument.createRange();
46964 r.setStart(tgs[0],0);
46965 r.setEnd(tgs[0],0);
46966 this.getEditor().Selection.GetSelection().removeAllRanges();
46967 this.getEditor().Selection.GetSelection().addRange(r);
46968 this.getEditor().Focus();
46975 replaceTextarea : function()
46977 if ( document.getElementById( this.getId() + '___Frame' ) )
46979 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46981 // We must check the elements firstly using the Id and then the name.
46982 var oTextarea = document.getElementById( this.getId() );
46984 var colElementsByName = document.getElementsByName( this.getId() ) ;
46986 oTextarea.style.display = 'none' ;
46988 if ( oTextarea.tabIndex ) {
46989 this.TabIndex = oTextarea.tabIndex ;
46992 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46993 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46994 this.frame = Roo.get(this.getId() + '___Frame')
46997 _getConfigHtml : function()
47001 for ( var o in this.fckconfig ) {
47002 sConfig += sConfig.length > 0 ? '&' : '';
47003 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
47006 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
47010 _getIFrameHtml : function()
47012 var sFile = 'fckeditor.html' ;
47013 /* no idea what this is about..
47016 if ( (/fcksource=true/i).test( window.top.location.search ) )
47017 sFile = 'fckeditor.original.html' ;
47022 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
47023 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
47026 var html = '<iframe id="' + this.getId() +
47027 '___Frame" src="' + sLink +
47028 '" width="' + this.width +
47029 '" height="' + this.height + '"' +
47030 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
47031 ' frameborder="0" scrolling="no"></iframe>' ;
47036 _insertHtmlBefore : function( html, element )
47038 if ( element.insertAdjacentHTML ) {
47040 element.insertAdjacentHTML( 'beforeBegin', html ) ;
47042 var oRange = document.createRange() ;
47043 oRange.setStartBefore( element ) ;
47044 var oFragment = oRange.createContextualFragment( html );
47045 element.parentNode.insertBefore( oFragment, element ) ;
47058 //Roo.reg('fckeditor', Roo.form.FCKeditor);
47060 function FCKeditor_OnComplete(editorInstance){
47061 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
47062 f.fckEditor = editorInstance;
47063 //console.log("loaded");
47064 f.fireEvent('editorinit', f, editorInstance);
47084 //<script type="text/javascript">
47086 * @class Roo.form.GridField
47087 * @extends Roo.form.Field
47088 * Embed a grid (or editable grid into a form)
47091 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47093 * xgrid.store = Roo.data.Store
47094 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47095 * xgrid.store.reader = Roo.data.JsonReader
47099 * Creates a new GridField
47100 * @param {Object} config Configuration options
47102 Roo.form.GridField = function(config){
47103 Roo.form.GridField.superclass.constructor.call(this, config);
47107 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47109 * @cfg {Number} width - used to restrict width of grid..
47113 * @cfg {Number} height - used to restrict height of grid..
47117 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47123 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47124 * {tag: "input", type: "checkbox", autocomplete: "off"})
47126 // defaultAutoCreate : { tag: 'div' },
47127 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47129 * @cfg {String} addTitle Text to include for adding a title.
47133 onResize : function(){
47134 Roo.form.Field.superclass.onResize.apply(this, arguments);
47137 initEvents : function(){
47138 // Roo.form.Checkbox.superclass.initEvents.call(this);
47139 // has no events...
47144 getResizeEl : function(){
47148 getPositionEl : function(){
47153 onRender : function(ct, position){
47155 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47156 var style = this.style;
47159 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47160 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47161 this.viewEl = this.wrap.createChild({ tag: 'div' });
47163 this.viewEl.applyStyles(style);
47166 this.viewEl.setWidth(this.width);
47169 this.viewEl.setHeight(this.height);
47171 //if(this.inputValue !== undefined){
47172 //this.setValue(this.value);
47175 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47178 this.grid.render();
47179 this.grid.getDataSource().on('remove', this.refreshValue, this);
47180 this.grid.getDataSource().on('update', this.refreshValue, this);
47181 this.grid.on('afteredit', this.refreshValue, this);
47187 * Sets the value of the item.
47188 * @param {String} either an object or a string..
47190 setValue : function(v){
47192 v = v || []; // empty set..
47193 // this does not seem smart - it really only affects memoryproxy grids..
47194 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47195 var ds = this.grid.getDataSource();
47196 // assumes a json reader..
47198 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47199 ds.loadData( data);
47201 // clear selection so it does not get stale.
47202 if (this.grid.sm) {
47203 this.grid.sm.clearSelections();
47206 Roo.form.GridField.superclass.setValue.call(this, v);
47207 this.refreshValue();
47208 // should load data in the grid really....
47212 refreshValue: function() {
47214 this.grid.getDataSource().each(function(r) {
47217 this.el.dom.value = Roo.encode(val);
47225 * Ext JS Library 1.1.1
47226 * Copyright(c) 2006-2007, Ext JS, LLC.
47228 * Originally Released Under LGPL - original licence link has changed is not relivant.
47231 * <script type="text/javascript">
47234 * @class Roo.form.DisplayField
47235 * @extends Roo.form.Field
47236 * A generic Field to display non-editable data.
47238 * Creates a new Display Field item.
47239 * @param {Object} config Configuration options
47241 Roo.form.DisplayField = function(config){
47242 Roo.form.DisplayField.superclass.constructor.call(this, config);
47246 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47247 inputType: 'hidden',
47253 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47255 focusClass : undefined,
47257 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47259 fieldClass: 'x-form-field',
47262 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47264 valueRenderer: undefined,
47268 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47269 * {tag: "input", type: "checkbox", autocomplete: "off"})
47272 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47274 onResize : function(){
47275 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47279 initEvents : function(){
47280 // Roo.form.Checkbox.superclass.initEvents.call(this);
47281 // has no events...
47286 getResizeEl : function(){
47290 getPositionEl : function(){
47295 onRender : function(ct, position){
47297 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47298 //if(this.inputValue !== undefined){
47299 this.wrap = this.el.wrap();
47301 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47303 if (this.bodyStyle) {
47304 this.viewEl.applyStyles(this.bodyStyle);
47306 //this.viewEl.setStyle('padding', '2px');
47308 this.setValue(this.value);
47313 initValue : Roo.emptyFn,
47318 onClick : function(){
47323 * Sets the checked state of the checkbox.
47324 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47326 setValue : function(v){
47328 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47329 // this might be called before we have a dom element..
47330 if (!this.viewEl) {
47333 this.viewEl.dom.innerHTML = html;
47334 Roo.form.DisplayField.superclass.setValue.call(this, v);
47344 * @class Roo.form.DayPicker
47345 * @extends Roo.form.Field
47346 * A Day picker show [M] [T] [W] ....
47348 * Creates a new Day Picker
47349 * @param {Object} config Configuration options
47351 Roo.form.DayPicker= function(config){
47352 Roo.form.DayPicker.superclass.constructor.call(this, config);
47356 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47358 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47360 focusClass : undefined,
47362 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47364 fieldClass: "x-form-field",
47367 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47368 * {tag: "input", type: "checkbox", autocomplete: "off"})
47370 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47373 actionMode : 'viewEl',
47377 inputType : 'hidden',
47380 inputElement: false, // real input element?
47381 basedOn: false, // ????
47383 isFormField: true, // not sure where this is needed!!!!
47385 onResize : function(){
47386 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47387 if(!this.boxLabel){
47388 this.el.alignTo(this.wrap, 'c-c');
47392 initEvents : function(){
47393 Roo.form.Checkbox.superclass.initEvents.call(this);
47394 this.el.on("click", this.onClick, this);
47395 this.el.on("change", this.onClick, this);
47399 getResizeEl : function(){
47403 getPositionEl : function(){
47409 onRender : function(ct, position){
47410 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47412 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47414 var r1 = '<table><tr>';
47415 var r2 = '<tr class="x-form-daypick-icons">';
47416 for (var i=0; i < 7; i++) {
47417 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47418 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47421 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47422 viewEl.select('img').on('click', this.onClick, this);
47423 this.viewEl = viewEl;
47426 // this will not work on Chrome!!!
47427 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47428 this.el.on('propertychange', this.setFromHidden, this); //ie
47436 initValue : Roo.emptyFn,
47439 * Returns the checked state of the checkbox.
47440 * @return {Boolean} True if checked, else false
47442 getValue : function(){
47443 return this.el.dom.value;
47448 onClick : function(e){
47449 //this.setChecked(!this.checked);
47450 Roo.get(e.target).toggleClass('x-menu-item-checked');
47451 this.refreshValue();
47452 //if(this.el.dom.checked != this.checked){
47453 // this.setValue(this.el.dom.checked);
47458 refreshValue : function()
47461 this.viewEl.select('img',true).each(function(e,i,n) {
47462 val += e.is(".x-menu-item-checked") ? String(n) : '';
47464 this.setValue(val, true);
47468 * Sets the checked state of the checkbox.
47469 * On is always based on a string comparison between inputValue and the param.
47470 * @param {Boolean/String} value - the value to set
47471 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47473 setValue : function(v,suppressEvent){
47474 if (!this.el.dom) {
47477 var old = this.el.dom.value ;
47478 this.el.dom.value = v;
47479 if (suppressEvent) {
47483 // update display..
47484 this.viewEl.select('img',true).each(function(e,i,n) {
47486 var on = e.is(".x-menu-item-checked");
47487 var newv = v.indexOf(String(n)) > -1;
47489 e.toggleClass('x-menu-item-checked');
47495 this.fireEvent('change', this, v, old);
47500 // handle setting of hidden value by some other method!!?!?
47501 setFromHidden: function()
47506 //console.log("SET FROM HIDDEN");
47507 //alert('setFrom hidden');
47508 this.setValue(this.el.dom.value);
47511 onDestroy : function()
47514 Roo.get(this.viewEl).remove();
47517 Roo.form.DayPicker.superclass.onDestroy.call(this);
47521 * RooJS Library 1.1.1
47522 * Copyright(c) 2008-2011 Alan Knowles
47529 * @class Roo.form.ComboCheck
47530 * @extends Roo.form.ComboBox
47531 * A combobox for multiple select items.
47533 * FIXME - could do with a reset button..
47536 * Create a new ComboCheck
47537 * @param {Object} config Configuration options
47539 Roo.form.ComboCheck = function(config){
47540 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47541 // should verify some data...
47543 // hiddenName = required..
47544 // displayField = required
47545 // valudField == required
47546 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47548 Roo.each(req, function(e) {
47549 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47550 throw "Roo.form.ComboCheck : missing value for: " + e;
47557 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47562 selectedClass: 'x-menu-item-checked',
47565 onRender : function(ct, position){
47571 var cls = 'x-combo-list';
47574 this.tpl = new Roo.Template({
47575 html : '<div class="'+cls+'-item x-menu-check-item">' +
47576 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47577 '<span>{' + this.displayField + '}</span>' +
47584 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47585 this.view.singleSelect = false;
47586 this.view.multiSelect = true;
47587 this.view.toggleSelect = true;
47588 this.pageTb.add(new Roo.Toolbar.Fill(), {
47591 handler: function()
47598 onViewOver : function(e, t){
47604 onViewClick : function(doFocus,index){
47608 select: function () {
47609 //Roo.log("SELECT CALLED");
47612 selectByValue : function(xv, scrollIntoView){
47613 var ar = this.getValueArray();
47616 Roo.each(ar, function(v) {
47617 if(v === undefined || v === null){
47620 var r = this.findRecord(this.valueField, v);
47622 sels.push(this.store.indexOf(r))
47626 this.view.select(sels);
47632 onSelect : function(record, index){
47633 // Roo.log("onselect Called");
47634 // this is only called by the clear button now..
47635 this.view.clearSelections();
47636 this.setValue('[]');
47637 if (this.value != this.valueBefore) {
47638 this.fireEvent('change', this, this.value, this.valueBefore);
47639 this.valueBefore = this.value;
47642 getValueArray : function()
47647 //Roo.log(this.value);
47648 if (typeof(this.value) == 'undefined') {
47651 var ar = Roo.decode(this.value);
47652 return ar instanceof Array ? ar : []; //?? valid?
47655 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47660 expand : function ()
47663 Roo.form.ComboCheck.superclass.expand.call(this);
47664 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47665 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47670 collapse : function(){
47671 Roo.form.ComboCheck.superclass.collapse.call(this);
47672 var sl = this.view.getSelectedIndexes();
47673 var st = this.store;
47677 Roo.each(sl, function(i) {
47679 nv.push(r.get(this.valueField));
47681 this.setValue(Roo.encode(nv));
47682 if (this.value != this.valueBefore) {
47684 this.fireEvent('change', this, this.value, this.valueBefore);
47685 this.valueBefore = this.value;
47690 setValue : function(v){
47694 var vals = this.getValueArray();
47696 Roo.each(vals, function(k) {
47697 var r = this.findRecord(this.valueField, k);
47699 tv.push(r.data[this.displayField]);
47700 }else if(this.valueNotFoundText !== undefined){
47701 tv.push( this.valueNotFoundText );
47706 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47707 this.hiddenField.value = v;
47713 * Ext JS Library 1.1.1
47714 * Copyright(c) 2006-2007, Ext JS, LLC.
47716 * Originally Released Under LGPL - original licence link has changed is not relivant.
47719 * <script type="text/javascript">
47723 * @class Roo.form.Signature
47724 * @extends Roo.form.Field
47728 * @param {Object} config Configuration options
47731 Roo.form.Signature = function(config){
47732 Roo.form.Signature.superclass.constructor.call(this, config);
47734 this.addEvents({// not in used??
47737 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47738 * @param {Roo.form.Signature} combo This combo box
47743 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47744 * @param {Roo.form.ComboBox} combo This combo box
47745 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47751 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47753 * @cfg {Object} labels Label to use when rendering a form.
47757 * confirm : "Confirm"
47762 confirm : "Confirm"
47765 * @cfg {Number} width The signature panel width (defaults to 300)
47769 * @cfg {Number} height The signature panel height (defaults to 100)
47773 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47775 allowBlank : false,
47778 // {Object} signPanel The signature SVG panel element (defaults to {})
47780 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47781 isMouseDown : false,
47782 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47783 isConfirmed : false,
47784 // {String} signatureTmp SVG mapping string (defaults to empty string)
47788 defaultAutoCreate : { // modified by initCompnoent..
47794 onRender : function(ct, position){
47796 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47798 this.wrap = this.el.wrap({
47799 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47802 this.createToolbar(this);
47803 this.signPanel = this.wrap.createChild({
47805 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47809 this.svgID = Roo.id();
47810 this.svgEl = this.signPanel.createChild({
47811 xmlns : 'http://www.w3.org/2000/svg',
47813 id : this.svgID + "-svg",
47815 height: this.height,
47816 viewBox: '0 0 '+this.width+' '+this.height,
47820 id: this.svgID + "-svg-r",
47822 height: this.height,
47827 id: this.svgID + "-svg-l",
47829 y1: (this.height*0.8), // start set the line in 80% of height
47830 x2: this.width, // end
47831 y2: (this.height*0.8), // end set the line in 80% of height
47833 'stroke-width': "1",
47834 'stroke-dasharray': "3",
47835 'shape-rendering': "crispEdges",
47836 'pointer-events': "none"
47840 id: this.svgID + "-svg-p",
47842 'stroke-width': "3",
47844 'pointer-events': 'none'
47849 this.svgBox = this.svgEl.dom.getScreenCTM();
47851 createSVG : function(){
47852 var svg = this.signPanel;
47853 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47856 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47857 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47858 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47859 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47860 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47861 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47862 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47865 isTouchEvent : function(e){
47866 return e.type.match(/^touch/);
47868 getCoords : function (e) {
47869 var pt = this.svgEl.dom.createSVGPoint();
47872 if (this.isTouchEvent(e)) {
47873 pt.x = e.targetTouches[0].clientX
47874 pt.y = e.targetTouches[0].clientY;
47876 var a = this.svgEl.dom.getScreenCTM();
47877 var b = a.inverse();
47878 var mx = pt.matrixTransform(b);
47879 return mx.x + ',' + mx.y;
47881 //mouse event headler
47882 down : function (e) {
47883 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47884 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47886 this.isMouseDown = true;
47888 e.preventDefault();
47890 move : function (e) {
47891 if (this.isMouseDown) {
47892 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47893 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47896 e.preventDefault();
47898 up : function (e) {
47899 this.isMouseDown = false;
47900 var sp = this.signatureTmp.split(' ');
47903 if(!sp[sp.length-2].match(/^L/)){
47907 this.signatureTmp = sp.join(" ");
47910 if(this.getValue() != this.signatureTmp){
47911 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47912 this.isConfirmed = false;
47914 e.preventDefault();
47918 * Protected method that will not generally be called directly. It
47919 * is called when the editor creates its toolbar. Override this method if you need to
47920 * add custom toolbar buttons.
47921 * @param {HtmlEditor} editor
47923 createToolbar : function(editor){
47924 function btn(id, toggle, handler){
47925 var xid = fid + '-'+ id ;
47929 cls : 'x-btn-icon x-edit-'+id,
47930 enableToggle:toggle !== false,
47931 scope: editor, // was editor...
47932 handler:handler||editor.relayBtnCmd,
47933 clickEvent:'mousedown',
47934 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47940 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47944 cls : ' x-signature-btn x-signature-'+id,
47945 scope: editor, // was editor...
47946 handler: this.reset,
47947 clickEvent:'mousedown',
47948 text: this.labels.clear
47955 cls : ' x-signature-btn x-signature-'+id,
47956 scope: editor, // was editor...
47957 handler: this.confirmHandler,
47958 clickEvent:'mousedown',
47959 text: this.labels.confirm
47966 * when user is clicked confirm then show this image.....
47968 * @return {String} Image Data URI
47970 getImageDataURI : function(){
47971 var svg = this.svgEl.dom.parentNode.innerHTML;
47972 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47977 * @return {Boolean} this.isConfirmed
47979 getConfirmed : function(){
47980 return this.isConfirmed;
47984 * @return {Number} this.width
47986 getWidth : function(){
47991 * @return {Number} this.height
47993 getHeight : function(){
47994 return this.height;
47997 getSignature : function(){
47998 return this.signatureTmp;
48001 reset : function(){
48002 this.signatureTmp = '';
48003 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48004 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
48005 this.isConfirmed = false;
48006 Roo.form.Signature.superclass.reset.call(this);
48008 setSignature : function(s){
48009 this.signatureTmp = s;
48010 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
48011 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
48013 this.isConfirmed = false;
48014 Roo.form.Signature.superclass.reset.call(this);
48017 // Roo.log(this.signPanel.dom.contentWindow.up())
48020 setConfirmed : function(){
48024 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
48027 confirmHandler : function(){
48028 if(!this.getSignature()){
48032 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
48033 this.setValue(this.getSignature());
48034 this.isConfirmed = true;
48036 this.fireEvent('confirm', this);
48039 // Subclasses should provide the validation implementation by overriding this
48040 validateValue : function(value){
48041 if(this.allowBlank){
48045 if(this.isConfirmed){
48052 * Ext JS Library 1.1.1
48053 * Copyright(c) 2006-2007, Ext JS, LLC.
48055 * Originally Released Under LGPL - original licence link has changed is not relivant.
48058 * <script type="text/javascript">
48063 * @class Roo.form.ComboBox
48064 * @extends Roo.form.TriggerField
48065 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
48067 * Create a new ComboBox.
48068 * @param {Object} config Configuration options
48070 Roo.form.Select = function(config){
48071 Roo.form.Select.superclass.constructor.call(this, config);
48075 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
48077 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
48080 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
48081 * rendering into an Roo.Editor, defaults to false)
48084 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48085 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48088 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48091 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48092 * the dropdown list (defaults to undefined, with no header element)
48096 * @cfg {String/Roo.Template} tpl The template to use to render the output
48100 defaultAutoCreate : {tag: "select" },
48102 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48104 listWidth: undefined,
48106 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48107 * mode = 'remote' or 'text' if mode = 'local')
48109 displayField: undefined,
48111 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48112 * mode = 'remote' or 'value' if mode = 'local').
48113 * Note: use of a valueField requires the user make a selection
48114 * in order for a value to be mapped.
48116 valueField: undefined,
48120 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48121 * field's data value (defaults to the underlying DOM element's name)
48123 hiddenName: undefined,
48125 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48129 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48131 selectedClass: 'x-combo-selected',
48133 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48134 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48135 * which displays a downward arrow icon).
48137 triggerClass : 'x-form-arrow-trigger',
48139 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48143 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48144 * anchor positions (defaults to 'tl-bl')
48146 listAlign: 'tl-bl?',
48148 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48152 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48153 * query specified by the allQuery config option (defaults to 'query')
48155 triggerAction: 'query',
48157 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48158 * (defaults to 4, does not apply if editable = false)
48162 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48163 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48167 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48168 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48172 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48173 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48177 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48178 * when editable = true (defaults to false)
48180 selectOnFocus:false,
48182 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48184 queryParam: 'query',
48186 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48187 * when mode = 'remote' (defaults to 'Loading...')
48189 loadingText: 'Loading...',
48191 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48195 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48199 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48200 * traditional select (defaults to true)
48204 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48208 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48212 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48213 * listWidth has a higher value)
48217 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48218 * allow the user to set arbitrary text into the field (defaults to false)
48220 forceSelection:false,
48222 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48223 * if typeAhead = true (defaults to 250)
48225 typeAheadDelay : 250,
48227 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48228 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48230 valueNotFoundText : undefined,
48233 * @cfg {String} defaultValue The value displayed after loading the store.
48238 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48240 blockFocus : false,
48243 * @cfg {Boolean} disableClear Disable showing of clear button.
48245 disableClear : false,
48247 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48249 alwaysQuery : false,
48255 // element that contains real text value.. (when hidden is used..)
48258 onRender : function(ct, position){
48259 Roo.form.Field.prototype.onRender.call(this, ct, position);
48262 this.store.on('beforeload', this.onBeforeLoad, this);
48263 this.store.on('load', this.onLoad, this);
48264 this.store.on('loadexception', this.onLoadException, this);
48265 this.store.load({});
48273 initEvents : function(){
48274 //Roo.form.ComboBox.superclass.initEvents.call(this);
48278 onDestroy : function(){
48281 this.store.un('beforeload', this.onBeforeLoad, this);
48282 this.store.un('load', this.onLoad, this);
48283 this.store.un('loadexception', this.onLoadException, this);
48285 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48289 fireKey : function(e){
48290 if(e.isNavKeyPress() && !this.list.isVisible()){
48291 this.fireEvent("specialkey", this, e);
48296 onResize: function(w, h){
48304 * Allow or prevent the user from directly editing the field text. If false is passed,
48305 * the user will only be able to select from the items defined in the dropdown list. This method
48306 * is the runtime equivalent of setting the 'editable' config option at config time.
48307 * @param {Boolean} value True to allow the user to directly edit the field text
48309 setEditable : function(value){
48314 onBeforeLoad : function(){
48316 Roo.log("Select before load");
48319 this.innerList.update(this.loadingText ?
48320 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48321 //this.restrictHeight();
48322 this.selectedIndex = -1;
48326 onLoad : function(){
48329 var dom = this.el.dom;
48330 dom.innerHTML = '';
48331 var od = dom.ownerDocument;
48333 if (this.emptyText) {
48334 var op = od.createElement('option');
48335 op.setAttribute('value', '');
48336 op.innerHTML = String.format('{0}', this.emptyText);
48337 dom.appendChild(op);
48339 if(this.store.getCount() > 0){
48341 var vf = this.valueField;
48342 var df = this.displayField;
48343 this.store.data.each(function(r) {
48344 // which colmsn to use... testing - cdoe / title..
48345 var op = od.createElement('option');
48346 op.setAttribute('value', r.data[vf]);
48347 op.innerHTML = String.format('{0}', r.data[df]);
48348 dom.appendChild(op);
48350 if (typeof(this.defaultValue != 'undefined')) {
48351 this.setValue(this.defaultValue);
48356 //this.onEmptyResults();
48361 onLoadException : function()
48363 dom.innerHTML = '';
48365 Roo.log("Select on load exception");
48369 Roo.log(this.store.reader.jsonData);
48370 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48371 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48377 onTypeAhead : function(){
48382 onSelect : function(record, index){
48383 Roo.log('on select?');
48385 if(this.fireEvent('beforeselect', this, record, index) !== false){
48386 this.setFromData(index > -1 ? record.data : false);
48388 this.fireEvent('select', this, record, index);
48393 * Returns the currently selected field value or empty string if no value is set.
48394 * @return {String} value The selected value
48396 getValue : function(){
48397 var dom = this.el.dom;
48398 this.value = dom.options[dom.selectedIndex].value;
48404 * Clears any text/value currently set in the field
48406 clearValue : function(){
48408 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48413 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48414 * will be displayed in the field. If the value does not match the data value of an existing item,
48415 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48416 * Otherwise the field will be blank (although the value will still be set).
48417 * @param {String} value The value to match
48419 setValue : function(v){
48420 var d = this.el.dom;
48421 for (var i =0; i < d.options.length;i++) {
48422 if (v == d.options[i].value) {
48423 d.selectedIndex = i;
48431 * @property {Object} the last set data for the element
48436 * Sets the value of the field based on a object which is related to the record format for the store.
48437 * @param {Object} value the value to set as. or false on reset?
48439 setFromData : function(o){
48440 Roo.log('setfrom data?');
48446 reset : function(){
48450 findRecord : function(prop, value){
48455 if(this.store.getCount() > 0){
48456 this.store.each(function(r){
48457 if(r.data[prop] == value){
48467 getName: function()
48469 // returns hidden if it's set..
48470 if (!this.rendered) {return ''};
48471 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48479 onEmptyResults : function(){
48480 Roo.log('empty results');
48485 * Returns true if the dropdown list is expanded, else false.
48487 isExpanded : function(){
48492 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48493 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48494 * @param {String} value The data value of the item to select
48495 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48496 * selected item if it is not currently in view (defaults to true)
48497 * @return {Boolean} True if the value matched an item in the list, else false
48499 selectByValue : function(v, scrollIntoView){
48500 Roo.log('select By Value');
48503 if(v !== undefined && v !== null){
48504 var r = this.findRecord(this.valueField || this.displayField, v);
48506 this.select(this.store.indexOf(r), scrollIntoView);
48514 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48515 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48516 * @param {Number} index The zero-based index of the list item to select
48517 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48518 * selected item if it is not currently in view (defaults to true)
48520 select : function(index, scrollIntoView){
48521 Roo.log('select ');
48524 this.selectedIndex = index;
48525 this.view.select(index);
48526 if(scrollIntoView !== false){
48527 var el = this.view.getNode(index);
48529 this.innerList.scrollChildIntoView(el, false);
48537 validateBlur : function(){
48544 initQuery : function(){
48545 this.doQuery(this.getRawValue());
48549 doForce : function(){
48550 if(this.el.dom.value.length > 0){
48551 this.el.dom.value =
48552 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48558 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48559 * query allowing the query action to be canceled if needed.
48560 * @param {String} query The SQL query to execute
48561 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48562 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48563 * saved in the current store (defaults to false)
48565 doQuery : function(q, forceAll){
48567 Roo.log('doQuery?');
48568 if(q === undefined || q === null){
48573 forceAll: forceAll,
48577 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48581 forceAll = qe.forceAll;
48582 if(forceAll === true || (q.length >= this.minChars)){
48583 if(this.lastQuery != q || this.alwaysQuery){
48584 this.lastQuery = q;
48585 if(this.mode == 'local'){
48586 this.selectedIndex = -1;
48588 this.store.clearFilter();
48590 this.store.filter(this.displayField, q);
48594 this.store.baseParams[this.queryParam] = q;
48596 params: this.getParams(q)
48601 this.selectedIndex = -1;
48608 getParams : function(q){
48610 //p[this.queryParam] = q;
48613 p.limit = this.pageSize;
48619 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48621 collapse : function(){
48626 collapseIf : function(e){
48631 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48633 expand : function(){
48641 * @cfg {Boolean} grow
48645 * @cfg {Number} growMin
48649 * @cfg {Number} growMax
48657 setWidth : function()
48661 getResizeEl : function(){
48664 });//<script type="text/javasscript">
48668 * @class Roo.DDView
48669 * A DnD enabled version of Roo.View.
48670 * @param {Element/String} container The Element in which to create the View.
48671 * @param {String} tpl The template string used to create the markup for each element of the View
48672 * @param {Object} config The configuration properties. These include all the config options of
48673 * {@link Roo.View} plus some specific to this class.<br>
48675 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48676 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48678 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48679 .x-view-drag-insert-above {
48680 border-top:1px dotted #3366cc;
48682 .x-view-drag-insert-below {
48683 border-bottom:1px dotted #3366cc;
48689 Roo.DDView = function(container, tpl, config) {
48690 Roo.DDView.superclass.constructor.apply(this, arguments);
48691 this.getEl().setStyle("outline", "0px none");
48692 this.getEl().unselectable();
48693 if (this.dragGroup) {
48694 this.setDraggable(this.dragGroup.split(","));
48696 if (this.dropGroup) {
48697 this.setDroppable(this.dropGroup.split(","));
48699 if (this.deletable) {
48700 this.setDeletable();
48702 this.isDirtyFlag = false;
48708 Roo.extend(Roo.DDView, Roo.View, {
48709 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48710 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48711 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48712 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48716 reset: Roo.emptyFn,
48718 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48720 validate: function() {
48724 destroy: function() {
48725 this.purgeListeners();
48726 this.getEl.removeAllListeners();
48727 this.getEl().remove();
48728 if (this.dragZone) {
48729 if (this.dragZone.destroy) {
48730 this.dragZone.destroy();
48733 if (this.dropZone) {
48734 if (this.dropZone.destroy) {
48735 this.dropZone.destroy();
48740 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48741 getName: function() {
48745 /** Loads the View from a JSON string representing the Records to put into the Store. */
48746 setValue: function(v) {
48748 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48751 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48752 this.store.proxy = new Roo.data.MemoryProxy(data);
48756 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48757 getValue: function() {
48759 this.store.each(function(rec) {
48760 result += rec.id + ',';
48762 return result.substr(0, result.length - 1) + ')';
48765 getIds: function() {
48766 var i = 0, result = new Array(this.store.getCount());
48767 this.store.each(function(rec) {
48768 result[i++] = rec.id;
48773 isDirty: function() {
48774 return this.isDirtyFlag;
48778 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48779 * whole Element becomes the target, and this causes the drop gesture to append.
48781 getTargetFromEvent : function(e) {
48782 var target = e.getTarget();
48783 while ((target !== null) && (target.parentNode != this.el.dom)) {
48784 target = target.parentNode;
48787 target = this.el.dom.lastChild || this.el.dom;
48793 * Create the drag data which consists of an object which has the property "ddel" as
48794 * the drag proxy element.
48796 getDragData : function(e) {
48797 var target = this.findItemFromChild(e.getTarget());
48799 this.handleSelection(e);
48800 var selNodes = this.getSelectedNodes();
48803 copy: this.copy || (this.allowCopy && e.ctrlKey),
48807 var selectedIndices = this.getSelectedIndexes();
48808 for (var i = 0; i < selectedIndices.length; i++) {
48809 dragData.records.push(this.store.getAt(selectedIndices[i]));
48811 if (selNodes.length == 1) {
48812 dragData.ddel = target.cloneNode(true); // the div element
48814 var div = document.createElement('div'); // create the multi element drag "ghost"
48815 div.className = 'multi-proxy';
48816 for (var i = 0, len = selNodes.length; i < len; i++) {
48817 div.appendChild(selNodes[i].cloneNode(true));
48819 dragData.ddel = div;
48821 //console.log(dragData)
48822 //console.log(dragData.ddel.innerHTML)
48825 //console.log('nodragData')
48829 /** Specify to which ddGroup items in this DDView may be dragged. */
48830 setDraggable: function(ddGroup) {
48831 if (ddGroup instanceof Array) {
48832 Roo.each(ddGroup, this.setDraggable, this);
48835 if (this.dragZone) {
48836 this.dragZone.addToGroup(ddGroup);
48838 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48839 containerScroll: true,
48843 // Draggability implies selection. DragZone's mousedown selects the element.
48844 if (!this.multiSelect) { this.singleSelect = true; }
48846 // Wire the DragZone's handlers up to methods in *this*
48847 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48851 /** Specify from which ddGroup this DDView accepts drops. */
48852 setDroppable: function(ddGroup) {
48853 if (ddGroup instanceof Array) {
48854 Roo.each(ddGroup, this.setDroppable, this);
48857 if (this.dropZone) {
48858 this.dropZone.addToGroup(ddGroup);
48860 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48861 containerScroll: true,
48865 // Wire the DropZone's handlers up to methods in *this*
48866 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48867 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48868 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48869 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48870 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48874 /** Decide whether to drop above or below a View node. */
48875 getDropPoint : function(e, n, dd){
48876 if (n == this.el.dom) { return "above"; }
48877 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48878 var c = t + (b - t) / 2;
48879 var y = Roo.lib.Event.getPageY(e);
48887 onNodeEnter : function(n, dd, e, data){
48891 onNodeOver : function(n, dd, e, data){
48892 var pt = this.getDropPoint(e, n, dd);
48893 // set the insert point style on the target node
48894 var dragElClass = this.dropNotAllowed;
48897 if (pt == "above"){
48898 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48899 targetElClass = "x-view-drag-insert-above";
48901 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48902 targetElClass = "x-view-drag-insert-below";
48904 if (this.lastInsertClass != targetElClass){
48905 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48906 this.lastInsertClass = targetElClass;
48909 return dragElClass;
48912 onNodeOut : function(n, dd, e, data){
48913 this.removeDropIndicators(n);
48916 onNodeDrop : function(n, dd, e, data){
48917 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48920 var pt = this.getDropPoint(e, n, dd);
48921 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48922 if (pt == "below") { insertAt++; }
48923 for (var i = 0; i < data.records.length; i++) {
48924 var r = data.records[i];
48925 var dup = this.store.getById(r.id);
48926 if (dup && (dd != this.dragZone)) {
48927 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48930 this.store.insert(insertAt++, r.copy());
48932 data.source.isDirtyFlag = true;
48934 this.store.insert(insertAt++, r);
48936 this.isDirtyFlag = true;
48939 this.dragZone.cachedTarget = null;
48943 removeDropIndicators : function(n){
48945 Roo.fly(n).removeClass([
48946 "x-view-drag-insert-above",
48947 "x-view-drag-insert-below"]);
48948 this.lastInsertClass = "_noclass";
48953 * Utility method. Add a delete option to the DDView's context menu.
48954 * @param {String} imageUrl The URL of the "delete" icon image.
48956 setDeletable: function(imageUrl) {
48957 if (!this.singleSelect && !this.multiSelect) {
48958 this.singleSelect = true;
48960 var c = this.getContextMenu();
48961 this.contextMenu.on("itemclick", function(item) {
48964 this.remove(this.getSelectedIndexes());
48968 this.contextMenu.add({
48975 /** Return the context menu for this DDView. */
48976 getContextMenu: function() {
48977 if (!this.contextMenu) {
48978 // Create the View's context menu
48979 this.contextMenu = new Roo.menu.Menu({
48980 id: this.id + "-contextmenu"
48982 this.el.on("contextmenu", this.showContextMenu, this);
48984 return this.contextMenu;
48987 disableContextMenu: function() {
48988 if (this.contextMenu) {
48989 this.el.un("contextmenu", this.showContextMenu, this);
48993 showContextMenu: function(e, item) {
48994 item = this.findItemFromChild(e.getTarget());
48997 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48998 this.contextMenu.showAt(e.getXY());
49003 * Remove {@link Roo.data.Record}s at the specified indices.
49004 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
49006 remove: function(selectedIndices) {
49007 selectedIndices = [].concat(selectedIndices);
49008 for (var i = 0; i < selectedIndices.length; i++) {
49009 var rec = this.store.getAt(selectedIndices[i]);
49010 this.store.remove(rec);
49015 * Double click fires the event, but also, if this is draggable, and there is only one other
49016 * related DropZone, it transfers the selected node.
49018 onDblClick : function(e){
49019 var item = this.findItemFromChild(e.getTarget());
49021 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
49024 if (this.dragGroup) {
49025 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
49026 while (targets.indexOf(this.dropZone) > -1) {
49027 targets.remove(this.dropZone);
49029 if (targets.length == 1) {
49030 this.dragZone.cachedTarget = null;
49031 var el = Roo.get(targets[0].getEl());
49032 var box = el.getBox(true);
49033 targets[0].onNodeDrop(el.dom, {
49035 xy: [box.x, box.y + box.height - 1]
49036 }, null, this.getDragData(e));
49042 handleSelection: function(e) {
49043 this.dragZone.cachedTarget = null;
49044 var item = this.findItemFromChild(e.getTarget());
49046 this.clearSelections(true);
49049 if (item && (this.multiSelect || this.singleSelect)){
49050 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
49051 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
49052 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
49053 this.unselect(item);
49055 this.select(item, this.multiSelect && e.ctrlKey);
49056 this.lastSelection = item;
49061 onItemClick : function(item, index, e){
49062 if(this.fireEvent("beforeclick", this, index, item, e) === false){
49068 unselect : function(nodeInfo, suppressEvent){
49069 var node = this.getNode(nodeInfo);
49070 if(node && this.isSelected(node)){
49071 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
49072 Roo.fly(node).removeClass(this.selectedClass);
49073 this.selections.remove(node);
49074 if(!suppressEvent){
49075 this.fireEvent("selectionchange", this, this.selections);
49083 * Ext JS Library 1.1.1
49084 * Copyright(c) 2006-2007, Ext JS, LLC.
49086 * Originally Released Under LGPL - original licence link has changed is not relivant.
49089 * <script type="text/javascript">
49093 * @class Roo.LayoutManager
49094 * @extends Roo.util.Observable
49095 * Base class for layout managers.
49097 Roo.LayoutManager = function(container, config){
49098 Roo.LayoutManager.superclass.constructor.call(this);
49099 this.el = Roo.get(container);
49100 // ie scrollbar fix
49101 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49102 document.body.scroll = "no";
49103 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49104 this.el.position('relative');
49106 this.id = this.el.id;
49107 this.el.addClass("x-layout-container");
49108 /** false to disable window resize monitoring @type Boolean */
49109 this.monitorWindowResize = true;
49114 * Fires when a layout is performed.
49115 * @param {Roo.LayoutManager} this
49119 * @event regionresized
49120 * Fires when the user resizes a region.
49121 * @param {Roo.LayoutRegion} region The resized region
49122 * @param {Number} newSize The new size (width for east/west, height for north/south)
49124 "regionresized" : true,
49126 * @event regioncollapsed
49127 * Fires when a region is collapsed.
49128 * @param {Roo.LayoutRegion} region The collapsed region
49130 "regioncollapsed" : true,
49132 * @event regionexpanded
49133 * Fires when a region is expanded.
49134 * @param {Roo.LayoutRegion} region The expanded region
49136 "regionexpanded" : true
49138 this.updating = false;
49139 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49142 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49144 * Returns true if this layout is currently being updated
49145 * @return {Boolean}
49147 isUpdating : function(){
49148 return this.updating;
49152 * Suspend the LayoutManager from doing auto-layouts while
49153 * making multiple add or remove calls
49155 beginUpdate : function(){
49156 this.updating = true;
49160 * Restore auto-layouts and optionally disable the manager from performing a layout
49161 * @param {Boolean} noLayout true to disable a layout update
49163 endUpdate : function(noLayout){
49164 this.updating = false;
49170 layout: function(){
49174 onRegionResized : function(region, newSize){
49175 this.fireEvent("regionresized", region, newSize);
49179 onRegionCollapsed : function(region){
49180 this.fireEvent("regioncollapsed", region);
49183 onRegionExpanded : function(region){
49184 this.fireEvent("regionexpanded", region);
49188 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49189 * performs box-model adjustments.
49190 * @return {Object} The size as an object {width: (the width), height: (the height)}
49192 getViewSize : function(){
49194 if(this.el.dom != document.body){
49195 size = this.el.getSize();
49197 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49199 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49200 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49205 * Returns the Element this layout is bound to.
49206 * @return {Roo.Element}
49208 getEl : function(){
49213 * Returns the specified region.
49214 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49215 * @return {Roo.LayoutRegion}
49217 getRegion : function(target){
49218 return this.regions[target.toLowerCase()];
49221 onWindowResize : function(){
49222 if(this.monitorWindowResize){
49228 * Ext JS Library 1.1.1
49229 * Copyright(c) 2006-2007, Ext JS, LLC.
49231 * Originally Released Under LGPL - original licence link has changed is not relivant.
49234 * <script type="text/javascript">
49237 * @class Roo.BorderLayout
49238 * @extends Roo.LayoutManager
49239 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49240 * please see: <br><br>
49241 * <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>
49242 * <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>
49245 var layout = new Roo.BorderLayout(document.body, {
49279 preferredTabWidth: 150
49284 var CP = Roo.ContentPanel;
49286 layout.beginUpdate();
49287 layout.add("north", new CP("north", "North"));
49288 layout.add("south", new CP("south", {title: "South", closable: true}));
49289 layout.add("west", new CP("west", {title: "West"}));
49290 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49291 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49292 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49293 layout.getRegion("center").showPanel("center1");
49294 layout.endUpdate();
49297 <b>The container the layout is rendered into can be either the body element or any other element.
49298 If it is not the body element, the container needs to either be an absolute positioned element,
49299 or you will need to add "position:relative" to the css of the container. You will also need to specify
49300 the container size if it is not the body element.</b>
49303 * Create a new BorderLayout
49304 * @param {String/HTMLElement/Element} container The container this layout is bound to
49305 * @param {Object} config Configuration options
49307 Roo.BorderLayout = function(container, config){
49308 config = config || {};
49309 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49310 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49311 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49312 var target = this.factory.validRegions[i];
49313 if(config[target]){
49314 this.addRegion(target, config[target]);
49319 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49321 * Creates and adds a new region if it doesn't already exist.
49322 * @param {String} target The target region key (north, south, east, west or center).
49323 * @param {Object} config The regions config object
49324 * @return {BorderLayoutRegion} The new region
49326 addRegion : function(target, config){
49327 if(!this.regions[target]){
49328 var r = this.factory.create(target, this, config);
49329 this.bindRegion(target, r);
49331 return this.regions[target];
49335 bindRegion : function(name, r){
49336 this.regions[name] = r;
49337 r.on("visibilitychange", this.layout, this);
49338 r.on("paneladded", this.layout, this);
49339 r.on("panelremoved", this.layout, this);
49340 r.on("invalidated", this.layout, this);
49341 r.on("resized", this.onRegionResized, this);
49342 r.on("collapsed", this.onRegionCollapsed, this);
49343 r.on("expanded", this.onRegionExpanded, this);
49347 * Performs a layout update.
49349 layout : function(){
49350 if(this.updating) return;
49351 var size = this.getViewSize();
49352 var w = size.width;
49353 var h = size.height;
49358 //var x = 0, y = 0;
49360 var rs = this.regions;
49361 var north = rs["north"];
49362 var south = rs["south"];
49363 var west = rs["west"];
49364 var east = rs["east"];
49365 var center = rs["center"];
49366 //if(this.hideOnLayout){ // not supported anymore
49367 //c.el.setStyle("display", "none");
49369 if(north && north.isVisible()){
49370 var b = north.getBox();
49371 var m = north.getMargins();
49372 b.width = w - (m.left+m.right);
49375 centerY = b.height + b.y + m.bottom;
49376 centerH -= centerY;
49377 north.updateBox(this.safeBox(b));
49379 if(south && south.isVisible()){
49380 var b = south.getBox();
49381 var m = south.getMargins();
49382 b.width = w - (m.left+m.right);
49384 var totalHeight = (b.height + m.top + m.bottom);
49385 b.y = h - totalHeight + m.top;
49386 centerH -= totalHeight;
49387 south.updateBox(this.safeBox(b));
49389 if(west && west.isVisible()){
49390 var b = west.getBox();
49391 var m = west.getMargins();
49392 b.height = centerH - (m.top+m.bottom);
49394 b.y = centerY + m.top;
49395 var totalWidth = (b.width + m.left + m.right);
49396 centerX += totalWidth;
49397 centerW -= totalWidth;
49398 west.updateBox(this.safeBox(b));
49400 if(east && east.isVisible()){
49401 var b = east.getBox();
49402 var m = east.getMargins();
49403 b.height = centerH - (m.top+m.bottom);
49404 var totalWidth = (b.width + m.left + m.right);
49405 b.x = w - totalWidth + m.left;
49406 b.y = centerY + m.top;
49407 centerW -= totalWidth;
49408 east.updateBox(this.safeBox(b));
49411 var m = center.getMargins();
49413 x: centerX + m.left,
49414 y: centerY + m.top,
49415 width: centerW - (m.left+m.right),
49416 height: centerH - (m.top+m.bottom)
49418 //if(this.hideOnLayout){
49419 //center.el.setStyle("display", "block");
49421 center.updateBox(this.safeBox(centerBox));
49424 this.fireEvent("layout", this);
49428 safeBox : function(box){
49429 box.width = Math.max(0, box.width);
49430 box.height = Math.max(0, box.height);
49435 * Adds a ContentPanel (or subclass) to this layout.
49436 * @param {String} target The target region key (north, south, east, west or center).
49437 * @param {Roo.ContentPanel} panel The panel to add
49438 * @return {Roo.ContentPanel} The added panel
49440 add : function(target, panel){
49442 target = target.toLowerCase();
49443 return this.regions[target].add(panel);
49447 * Remove a ContentPanel (or subclass) to this layout.
49448 * @param {String} target The target region key (north, south, east, west or center).
49449 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49450 * @return {Roo.ContentPanel} The removed panel
49452 remove : function(target, panel){
49453 target = target.toLowerCase();
49454 return this.regions[target].remove(panel);
49458 * Searches all regions for a panel with the specified id
49459 * @param {String} panelId
49460 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49462 findPanel : function(panelId){
49463 var rs = this.regions;
49464 for(var target in rs){
49465 if(typeof rs[target] != "function"){
49466 var p = rs[target].getPanel(panelId);
49476 * Searches all regions for a panel with the specified id and activates (shows) it.
49477 * @param {String/ContentPanel} panelId The panels id or the panel itself
49478 * @return {Roo.ContentPanel} The shown panel or null
49480 showPanel : function(panelId) {
49481 var rs = this.regions;
49482 for(var target in rs){
49483 var r = rs[target];
49484 if(typeof r != "function"){
49485 if(r.hasPanel(panelId)){
49486 return r.showPanel(panelId);
49494 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49495 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49497 restoreState : function(provider){
49499 provider = Roo.state.Manager;
49501 var sm = new Roo.LayoutStateManager();
49502 sm.init(this, provider);
49506 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49507 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49508 * a valid ContentPanel config object. Example:
49510 // Create the main layout
49511 var layout = new Roo.BorderLayout('main-ct', {
49522 // Create and add multiple ContentPanels at once via configs
49525 id: 'source-files',
49527 title:'Ext Source Files',
49540 * @param {Object} regions An object containing ContentPanel configs by region name
49542 batchAdd : function(regions){
49543 this.beginUpdate();
49544 for(var rname in regions){
49545 var lr = this.regions[rname];
49547 this.addTypedPanels(lr, regions[rname]);
49554 addTypedPanels : function(lr, ps){
49555 if(typeof ps == 'string'){
49556 lr.add(new Roo.ContentPanel(ps));
49558 else if(ps instanceof Array){
49559 for(var i =0, len = ps.length; i < len; i++){
49560 this.addTypedPanels(lr, ps[i]);
49563 else if(!ps.events){ // raw config?
49565 delete ps.el; // prevent conflict
49566 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49568 else { // panel object assumed!
49573 * Adds a xtype elements to the layout.
49577 xtype : 'ContentPanel',
49584 xtype : 'NestedLayoutPanel',
49590 items : [ ... list of content panels or nested layout panels.. ]
49594 * @param {Object} cfg Xtype definition of item to add.
49596 addxtype : function(cfg)
49598 // basically accepts a pannel...
49599 // can accept a layout region..!?!?
49600 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49602 if (!cfg.xtype.match(/Panel$/)) {
49607 if (typeof(cfg.region) == 'undefined') {
49608 Roo.log("Failed to add Panel, region was not set");
49612 var region = cfg.region;
49618 xitems = cfg.items;
49625 case 'ContentPanel': // ContentPanel (el, cfg)
49626 case 'ScrollPanel': // ContentPanel (el, cfg)
49628 if(cfg.autoCreate) {
49629 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49631 var el = this.el.createChild();
49632 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49635 this.add(region, ret);
49639 case 'TreePanel': // our new panel!
49640 cfg.el = this.el.createChild();
49641 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49642 this.add(region, ret);
49645 case 'NestedLayoutPanel':
49646 // create a new Layout (which is a Border Layout...
49647 var el = this.el.createChild();
49648 var clayout = cfg.layout;
49650 clayout.items = clayout.items || [];
49651 // replace this exitems with the clayout ones..
49652 xitems = clayout.items;
49655 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49656 cfg.background = false;
49658 var layout = new Roo.BorderLayout(el, clayout);
49660 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49661 //console.log('adding nested layout panel ' + cfg.toSource());
49662 this.add(region, ret);
49663 nb = {}; /// find first...
49668 // needs grid and region
49670 //var el = this.getRegion(region).el.createChild();
49671 var el = this.el.createChild();
49672 // create the grid first...
49674 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49676 if (region == 'center' && this.active ) {
49677 cfg.background = false;
49679 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49681 this.add(region, ret);
49682 if (cfg.background) {
49683 ret.on('activate', function(gp) {
49684 if (!gp.grid.rendered) {
49699 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49701 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49702 this.add(region, ret);
49705 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49709 // GridPanel (grid, cfg)
49712 this.beginUpdate();
49716 Roo.each(xitems, function(i) {
49717 region = nb && i.region ? i.region : false;
49719 var add = ret.addxtype(i);
49722 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49723 if (!i.background) {
49724 abn[region] = nb[region] ;
49731 // make the last non-background panel active..
49732 //if (nb) { Roo.log(abn); }
49735 for(var r in abn) {
49736 region = this.getRegion(r);
49738 // tried using nb[r], but it does not work..
49740 region.showPanel(abn[r]);
49751 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49752 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49753 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49754 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49757 var CP = Roo.ContentPanel;
49759 var layout = Roo.BorderLayout.create({
49763 panels: [new CP("north", "North")]
49772 panels: [new CP("west", {title: "West"})]
49781 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49790 panels: [new CP("south", {title: "South", closable: true})]
49797 preferredTabWidth: 150,
49799 new CP("center1", {title: "Close Me", closable: true}),
49800 new CP("center2", {title: "Center Panel", closable: false})
49805 layout.getRegion("center").showPanel("center1");
49810 Roo.BorderLayout.create = function(config, targetEl){
49811 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49812 layout.beginUpdate();
49813 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49814 for(var j = 0, jlen = regions.length; j < jlen; j++){
49815 var lr = regions[j];
49816 if(layout.regions[lr] && config[lr].panels){
49817 var r = layout.regions[lr];
49818 var ps = config[lr].panels;
49819 layout.addTypedPanels(r, ps);
49822 layout.endUpdate();
49827 Roo.BorderLayout.RegionFactory = {
49829 validRegions : ["north","south","east","west","center"],
49832 create : function(target, mgr, config){
49833 target = target.toLowerCase();
49834 if(config.lightweight || config.basic){
49835 return new Roo.BasicLayoutRegion(mgr, config, target);
49839 return new Roo.NorthLayoutRegion(mgr, config);
49841 return new Roo.SouthLayoutRegion(mgr, config);
49843 return new Roo.EastLayoutRegion(mgr, config);
49845 return new Roo.WestLayoutRegion(mgr, config);
49847 return new Roo.CenterLayoutRegion(mgr, config);
49849 throw 'Layout region "'+target+'" not supported.';
49853 * Ext JS Library 1.1.1
49854 * Copyright(c) 2006-2007, Ext JS, LLC.
49856 * Originally Released Under LGPL - original licence link has changed is not relivant.
49859 * <script type="text/javascript">
49863 * @class Roo.BasicLayoutRegion
49864 * @extends Roo.util.Observable
49865 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49866 * and does not have a titlebar, tabs or any other features. All it does is size and position
49867 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49869 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49871 this.position = pos;
49874 * @scope Roo.BasicLayoutRegion
49878 * @event beforeremove
49879 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49880 * @param {Roo.LayoutRegion} this
49881 * @param {Roo.ContentPanel} panel The panel
49882 * @param {Object} e The cancel event object
49884 "beforeremove" : true,
49886 * @event invalidated
49887 * Fires when the layout for this region is changed.
49888 * @param {Roo.LayoutRegion} this
49890 "invalidated" : true,
49892 * @event visibilitychange
49893 * Fires when this region is shown or hidden
49894 * @param {Roo.LayoutRegion} this
49895 * @param {Boolean} visibility true or false
49897 "visibilitychange" : true,
49899 * @event paneladded
49900 * Fires when a panel is added.
49901 * @param {Roo.LayoutRegion} this
49902 * @param {Roo.ContentPanel} panel The panel
49904 "paneladded" : true,
49906 * @event panelremoved
49907 * Fires when a panel is removed.
49908 * @param {Roo.LayoutRegion} this
49909 * @param {Roo.ContentPanel} panel The panel
49911 "panelremoved" : true,
49914 * Fires when this region is collapsed.
49915 * @param {Roo.LayoutRegion} this
49917 "collapsed" : true,
49920 * Fires when this region is expanded.
49921 * @param {Roo.LayoutRegion} this
49926 * Fires when this region is slid into view.
49927 * @param {Roo.LayoutRegion} this
49929 "slideshow" : true,
49932 * Fires when this region slides out of view.
49933 * @param {Roo.LayoutRegion} this
49935 "slidehide" : true,
49937 * @event panelactivated
49938 * Fires when a panel is activated.
49939 * @param {Roo.LayoutRegion} this
49940 * @param {Roo.ContentPanel} panel The activated panel
49942 "panelactivated" : true,
49945 * Fires when the user resizes this region.
49946 * @param {Roo.LayoutRegion} this
49947 * @param {Number} newSize The new size (width for east/west, height for north/south)
49951 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49952 this.panels = new Roo.util.MixedCollection();
49953 this.panels.getKey = this.getPanelId.createDelegate(this);
49955 this.activePanel = null;
49956 // ensure listeners are added...
49958 if (config.listeners || config.events) {
49959 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49960 listeners : config.listeners || {},
49961 events : config.events || {}
49965 if(skipConfig !== true){
49966 this.applyConfig(config);
49970 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49971 getPanelId : function(p){
49975 applyConfig : function(config){
49976 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49977 this.config = config;
49982 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49983 * the width, for horizontal (north, south) the height.
49984 * @param {Number} newSize The new width or height
49986 resizeTo : function(newSize){
49987 var el = this.el ? this.el :
49988 (this.activePanel ? this.activePanel.getEl() : null);
49990 switch(this.position){
49993 el.setWidth(newSize);
49994 this.fireEvent("resized", this, newSize);
49998 el.setHeight(newSize);
49999 this.fireEvent("resized", this, newSize);
50005 getBox : function(){
50006 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
50009 getMargins : function(){
50010 return this.margins;
50013 updateBox : function(box){
50015 var el = this.activePanel.getEl();
50016 el.dom.style.left = box.x + "px";
50017 el.dom.style.top = box.y + "px";
50018 this.activePanel.setSize(box.width, box.height);
50022 * Returns the container element for this region.
50023 * @return {Roo.Element}
50025 getEl : function(){
50026 return this.activePanel;
50030 * Returns true if this region is currently visible.
50031 * @return {Boolean}
50033 isVisible : function(){
50034 return this.activePanel ? true : false;
50037 setActivePanel : function(panel){
50038 panel = this.getPanel(panel);
50039 if(this.activePanel && this.activePanel != panel){
50040 this.activePanel.setActiveState(false);
50041 this.activePanel.getEl().setLeftTop(-10000,-10000);
50043 this.activePanel = panel;
50044 panel.setActiveState(true);
50046 panel.setSize(this.box.width, this.box.height);
50048 this.fireEvent("panelactivated", this, panel);
50049 this.fireEvent("invalidated");
50053 * Show the specified panel.
50054 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
50055 * @return {Roo.ContentPanel} The shown panel or null
50057 showPanel : function(panel){
50058 if(panel = this.getPanel(panel)){
50059 this.setActivePanel(panel);
50065 * Get the active panel for this region.
50066 * @return {Roo.ContentPanel} The active panel or null
50068 getActivePanel : function(){
50069 return this.activePanel;
50073 * Add the passed ContentPanel(s)
50074 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50075 * @return {Roo.ContentPanel} The panel added (if only one was added)
50077 add : function(panel){
50078 if(arguments.length > 1){
50079 for(var i = 0, len = arguments.length; i < len; i++) {
50080 this.add(arguments[i]);
50084 if(this.hasPanel(panel)){
50085 this.showPanel(panel);
50088 var el = panel.getEl();
50089 if(el.dom.parentNode != this.mgr.el.dom){
50090 this.mgr.el.dom.appendChild(el.dom);
50092 if(panel.setRegion){
50093 panel.setRegion(this);
50095 this.panels.add(panel);
50096 el.setStyle("position", "absolute");
50097 if(!panel.background){
50098 this.setActivePanel(panel);
50099 if(this.config.initialSize && this.panels.getCount()==1){
50100 this.resizeTo(this.config.initialSize);
50103 this.fireEvent("paneladded", this, panel);
50108 * Returns true if the panel is in this region.
50109 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50110 * @return {Boolean}
50112 hasPanel : function(panel){
50113 if(typeof panel == "object"){ // must be panel obj
50114 panel = panel.getId();
50116 return this.getPanel(panel) ? true : false;
50120 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50121 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50122 * @param {Boolean} preservePanel Overrides the config preservePanel option
50123 * @return {Roo.ContentPanel} The panel that was removed
50125 remove : function(panel, preservePanel){
50126 panel = this.getPanel(panel);
50131 this.fireEvent("beforeremove", this, panel, e);
50132 if(e.cancel === true){
50135 var panelId = panel.getId();
50136 this.panels.removeKey(panelId);
50141 * Returns the panel specified or null if it's not in this region.
50142 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50143 * @return {Roo.ContentPanel}
50145 getPanel : function(id){
50146 if(typeof id == "object"){ // must be panel obj
50149 return this.panels.get(id);
50153 * Returns this regions position (north/south/east/west/center).
50156 getPosition: function(){
50157 return this.position;
50161 * Ext JS Library 1.1.1
50162 * Copyright(c) 2006-2007, Ext JS, LLC.
50164 * Originally Released Under LGPL - original licence link has changed is not relivant.
50167 * <script type="text/javascript">
50171 * @class Roo.LayoutRegion
50172 * @extends Roo.BasicLayoutRegion
50173 * This class represents a region in a layout manager.
50174 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50175 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50176 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50177 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50178 * @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})
50179 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50180 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50181 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50182 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50183 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50184 * @cfg {String} title The title for the region (overrides panel titles)
50185 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50186 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50187 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50188 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50189 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50190 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50191 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50192 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50193 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50194 * @cfg {Boolean} showPin True to show a pin button
50195 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50196 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50197 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50198 * @cfg {Number} width For East/West panels
50199 * @cfg {Number} height For North/South panels
50200 * @cfg {Boolean} split To show the splitter
50201 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50203 Roo.LayoutRegion = function(mgr, config, pos){
50204 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50205 var dh = Roo.DomHelper;
50206 /** This region's container element
50207 * @type Roo.Element */
50208 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50209 /** This region's title element
50210 * @type Roo.Element */
50212 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50213 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50214 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50216 this.titleEl.enableDisplayMode();
50217 /** This region's title text element
50218 * @type HTMLElement */
50219 this.titleTextEl = this.titleEl.dom.firstChild;
50220 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50221 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50222 this.closeBtn.enableDisplayMode();
50223 this.closeBtn.on("click", this.closeClicked, this);
50224 this.closeBtn.hide();
50226 this.createBody(config);
50227 this.visible = true;
50228 this.collapsed = false;
50230 if(config.hideWhenEmpty){
50232 this.on("paneladded", this.validateVisibility, this);
50233 this.on("panelremoved", this.validateVisibility, this);
50235 this.applyConfig(config);
50238 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50240 createBody : function(){
50241 /** This region's body element
50242 * @type Roo.Element */
50243 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50246 applyConfig : function(c){
50247 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50248 var dh = Roo.DomHelper;
50249 if(c.titlebar !== false){
50250 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50251 this.collapseBtn.on("click", this.collapse, this);
50252 this.collapseBtn.enableDisplayMode();
50254 if(c.showPin === true || this.showPin){
50255 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50256 this.stickBtn.enableDisplayMode();
50257 this.stickBtn.on("click", this.expand, this);
50258 this.stickBtn.hide();
50261 /** This region's collapsed element
50262 * @type Roo.Element */
50263 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50264 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50266 if(c.floatable !== false){
50267 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50268 this.collapsedEl.on("click", this.collapseClick, this);
50271 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50272 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50273 id: "message", unselectable: "on", style:{"float":"left"}});
50274 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50276 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50277 this.expandBtn.on("click", this.expand, this);
50279 if(this.collapseBtn){
50280 this.collapseBtn.setVisible(c.collapsible == true);
50282 this.cmargins = c.cmargins || this.cmargins ||
50283 (this.position == "west" || this.position == "east" ?
50284 {top: 0, left: 2, right:2, bottom: 0} :
50285 {top: 2, left: 0, right:0, bottom: 2});
50286 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50287 this.bottomTabs = c.tabPosition != "top";
50288 this.autoScroll = c.autoScroll || false;
50289 if(this.autoScroll){
50290 this.bodyEl.setStyle("overflow", "auto");
50292 this.bodyEl.setStyle("overflow", "hidden");
50294 //if(c.titlebar !== false){
50295 if((!c.titlebar && !c.title) || c.titlebar === false){
50296 this.titleEl.hide();
50298 this.titleEl.show();
50300 this.titleTextEl.innerHTML = c.title;
50304 this.duration = c.duration || .30;
50305 this.slideDuration = c.slideDuration || .45;
50308 this.collapse(true);
50315 * Returns true if this region is currently visible.
50316 * @return {Boolean}
50318 isVisible : function(){
50319 return this.visible;
50323 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50324 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50326 setCollapsedTitle : function(title){
50327 title = title || " ";
50328 if(this.collapsedTitleTextEl){
50329 this.collapsedTitleTextEl.innerHTML = title;
50333 getBox : function(){
50335 if(!this.collapsed){
50336 b = this.el.getBox(false, true);
50338 b = this.collapsedEl.getBox(false, true);
50343 getMargins : function(){
50344 return this.collapsed ? this.cmargins : this.margins;
50347 highlight : function(){
50348 this.el.addClass("x-layout-panel-dragover");
50351 unhighlight : function(){
50352 this.el.removeClass("x-layout-panel-dragover");
50355 updateBox : function(box){
50357 if(!this.collapsed){
50358 this.el.dom.style.left = box.x + "px";
50359 this.el.dom.style.top = box.y + "px";
50360 this.updateBody(box.width, box.height);
50362 this.collapsedEl.dom.style.left = box.x + "px";
50363 this.collapsedEl.dom.style.top = box.y + "px";
50364 this.collapsedEl.setSize(box.width, box.height);
50367 this.tabs.autoSizeTabs();
50371 updateBody : function(w, h){
50373 this.el.setWidth(w);
50374 w -= this.el.getBorderWidth("rl");
50375 if(this.config.adjustments){
50376 w += this.config.adjustments[0];
50380 this.el.setHeight(h);
50381 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50382 h -= this.el.getBorderWidth("tb");
50383 if(this.config.adjustments){
50384 h += this.config.adjustments[1];
50386 this.bodyEl.setHeight(h);
50388 h = this.tabs.syncHeight(h);
50391 if(this.panelSize){
50392 w = w !== null ? w : this.panelSize.width;
50393 h = h !== null ? h : this.panelSize.height;
50395 if(this.activePanel){
50396 var el = this.activePanel.getEl();
50397 w = w !== null ? w : el.getWidth();
50398 h = h !== null ? h : el.getHeight();
50399 this.panelSize = {width: w, height: h};
50400 this.activePanel.setSize(w, h);
50402 if(Roo.isIE && this.tabs){
50403 this.tabs.el.repaint();
50408 * Returns the container element for this region.
50409 * @return {Roo.Element}
50411 getEl : function(){
50416 * Hides this region.
50419 if(!this.collapsed){
50420 this.el.dom.style.left = "-2000px";
50423 this.collapsedEl.dom.style.left = "-2000px";
50424 this.collapsedEl.hide();
50426 this.visible = false;
50427 this.fireEvent("visibilitychange", this, false);
50431 * Shows this region if it was previously hidden.
50434 if(!this.collapsed){
50437 this.collapsedEl.show();
50439 this.visible = true;
50440 this.fireEvent("visibilitychange", this, true);
50443 closeClicked : function(){
50444 if(this.activePanel){
50445 this.remove(this.activePanel);
50449 collapseClick : function(e){
50451 e.stopPropagation();
50454 e.stopPropagation();
50460 * Collapses this region.
50461 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50463 collapse : function(skipAnim){
50464 if(this.collapsed) return;
50465 this.collapsed = true;
50467 this.split.el.hide();
50469 if(this.config.animate && skipAnim !== true){
50470 this.fireEvent("invalidated", this);
50471 this.animateCollapse();
50473 this.el.setLocation(-20000,-20000);
50475 this.collapsedEl.show();
50476 this.fireEvent("collapsed", this);
50477 this.fireEvent("invalidated", this);
50481 animateCollapse : function(){
50486 * Expands this region if it was previously collapsed.
50487 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50488 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50490 expand : function(e, skipAnim){
50491 if(e) e.stopPropagation();
50492 if(!this.collapsed || this.el.hasActiveFx()) return;
50494 this.afterSlideIn();
50497 this.collapsed = false;
50498 if(this.config.animate && skipAnim !== true){
50499 this.animateExpand();
50503 this.split.el.show();
50505 this.collapsedEl.setLocation(-2000,-2000);
50506 this.collapsedEl.hide();
50507 this.fireEvent("invalidated", this);
50508 this.fireEvent("expanded", this);
50512 animateExpand : function(){
50516 initTabs : function()
50518 this.bodyEl.setStyle("overflow", "hidden");
50519 var ts = new Roo.TabPanel(
50522 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50523 disableTooltips: this.config.disableTabTips,
50524 toolbar : this.config.toolbar
50527 if(this.config.hideTabs){
50528 ts.stripWrap.setDisplayed(false);
50531 ts.resizeTabs = this.config.resizeTabs === true;
50532 ts.minTabWidth = this.config.minTabWidth || 40;
50533 ts.maxTabWidth = this.config.maxTabWidth || 250;
50534 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50535 ts.monitorResize = false;
50536 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50537 ts.bodyEl.addClass('x-layout-tabs-body');
50538 this.panels.each(this.initPanelAsTab, this);
50541 initPanelAsTab : function(panel){
50542 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50543 this.config.closeOnTab && panel.isClosable());
50544 if(panel.tabTip !== undefined){
50545 ti.setTooltip(panel.tabTip);
50547 ti.on("activate", function(){
50548 this.setActivePanel(panel);
50550 if(this.config.closeOnTab){
50551 ti.on("beforeclose", function(t, e){
50553 this.remove(panel);
50559 updatePanelTitle : function(panel, title){
50560 if(this.activePanel == panel){
50561 this.updateTitle(title);
50564 var ti = this.tabs.getTab(panel.getEl().id);
50566 if(panel.tabTip !== undefined){
50567 ti.setTooltip(panel.tabTip);
50572 updateTitle : function(title){
50573 if(this.titleTextEl && !this.config.title){
50574 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50578 setActivePanel : function(panel){
50579 panel = this.getPanel(panel);
50580 if(this.activePanel && this.activePanel != panel){
50581 this.activePanel.setActiveState(false);
50583 this.activePanel = panel;
50584 panel.setActiveState(true);
50585 if(this.panelSize){
50586 panel.setSize(this.panelSize.width, this.panelSize.height);
50589 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50591 this.updateTitle(panel.getTitle());
50593 this.fireEvent("invalidated", this);
50595 this.fireEvent("panelactivated", this, panel);
50599 * Shows the specified panel.
50600 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50601 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50603 showPanel : function(panel)
50605 panel = this.getPanel(panel);
50608 var tab = this.tabs.getTab(panel.getEl().id);
50609 if(tab.isHidden()){
50610 this.tabs.unhideTab(tab.id);
50614 this.setActivePanel(panel);
50621 * Get the active panel for this region.
50622 * @return {Roo.ContentPanel} The active panel or null
50624 getActivePanel : function(){
50625 return this.activePanel;
50628 validateVisibility : function(){
50629 if(this.panels.getCount() < 1){
50630 this.updateTitle(" ");
50631 this.closeBtn.hide();
50634 if(!this.isVisible()){
50641 * Adds the passed ContentPanel(s) to this region.
50642 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50643 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50645 add : function(panel){
50646 if(arguments.length > 1){
50647 for(var i = 0, len = arguments.length; i < len; i++) {
50648 this.add(arguments[i]);
50652 if(this.hasPanel(panel)){
50653 this.showPanel(panel);
50656 panel.setRegion(this);
50657 this.panels.add(panel);
50658 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50659 this.bodyEl.dom.appendChild(panel.getEl().dom);
50660 if(panel.background !== true){
50661 this.setActivePanel(panel);
50663 this.fireEvent("paneladded", this, panel);
50669 this.initPanelAsTab(panel);
50671 if(panel.background !== true){
50672 this.tabs.activate(panel.getEl().id);
50674 this.fireEvent("paneladded", this, panel);
50679 * Hides the tab for the specified panel.
50680 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50682 hidePanel : function(panel){
50683 if(this.tabs && (panel = this.getPanel(panel))){
50684 this.tabs.hideTab(panel.getEl().id);
50689 * Unhides the tab for a previously hidden panel.
50690 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50692 unhidePanel : function(panel){
50693 if(this.tabs && (panel = this.getPanel(panel))){
50694 this.tabs.unhideTab(panel.getEl().id);
50698 clearPanels : function(){
50699 while(this.panels.getCount() > 0){
50700 this.remove(this.panels.first());
50705 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50706 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50707 * @param {Boolean} preservePanel Overrides the config preservePanel option
50708 * @return {Roo.ContentPanel} The panel that was removed
50710 remove : function(panel, preservePanel){
50711 panel = this.getPanel(panel);
50716 this.fireEvent("beforeremove", this, panel, e);
50717 if(e.cancel === true){
50720 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50721 var panelId = panel.getId();
50722 this.panels.removeKey(panelId);
50724 document.body.appendChild(panel.getEl().dom);
50727 this.tabs.removeTab(panel.getEl().id);
50728 }else if (!preservePanel){
50729 this.bodyEl.dom.removeChild(panel.getEl().dom);
50731 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50732 var p = this.panels.first();
50733 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50734 tempEl.appendChild(p.getEl().dom);
50735 this.bodyEl.update("");
50736 this.bodyEl.dom.appendChild(p.getEl().dom);
50738 this.updateTitle(p.getTitle());
50740 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50741 this.setActivePanel(p);
50743 panel.setRegion(null);
50744 if(this.activePanel == panel){
50745 this.activePanel = null;
50747 if(this.config.autoDestroy !== false && preservePanel !== true){
50748 try{panel.destroy();}catch(e){}
50750 this.fireEvent("panelremoved", this, panel);
50755 * Returns the TabPanel component used by this region
50756 * @return {Roo.TabPanel}
50758 getTabs : function(){
50762 createTool : function(parentEl, className){
50763 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50764 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50765 btn.addClassOnOver("x-layout-tools-button-over");
50770 * Ext JS Library 1.1.1
50771 * Copyright(c) 2006-2007, Ext JS, LLC.
50773 * Originally Released Under LGPL - original licence link has changed is not relivant.
50776 * <script type="text/javascript">
50782 * @class Roo.SplitLayoutRegion
50783 * @extends Roo.LayoutRegion
50784 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50786 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50787 this.cursor = cursor;
50788 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50791 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50792 splitTip : "Drag to resize.",
50793 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50794 useSplitTips : false,
50796 applyConfig : function(config){
50797 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50800 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50801 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50802 /** The SplitBar for this region
50803 * @type Roo.SplitBar */
50804 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50805 this.split.on("moved", this.onSplitMove, this);
50806 this.split.useShim = config.useShim === true;
50807 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50808 if(this.useSplitTips){
50809 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50811 if(config.collapsible){
50812 this.split.el.on("dblclick", this.collapse, this);
50815 if(typeof config.minSize != "undefined"){
50816 this.split.minSize = config.minSize;
50818 if(typeof config.maxSize != "undefined"){
50819 this.split.maxSize = config.maxSize;
50821 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50822 this.hideSplitter();
50827 getHMaxSize : function(){
50828 var cmax = this.config.maxSize || 10000;
50829 var center = this.mgr.getRegion("center");
50830 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50833 getVMaxSize : function(){
50834 var cmax = this.config.maxSize || 10000;
50835 var center = this.mgr.getRegion("center");
50836 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50839 onSplitMove : function(split, newSize){
50840 this.fireEvent("resized", this, newSize);
50844 * Returns the {@link Roo.SplitBar} for this region.
50845 * @return {Roo.SplitBar}
50847 getSplitBar : function(){
50852 this.hideSplitter();
50853 Roo.SplitLayoutRegion.superclass.hide.call(this);
50856 hideSplitter : function(){
50858 this.split.el.setLocation(-2000,-2000);
50859 this.split.el.hide();
50865 this.split.el.show();
50867 Roo.SplitLayoutRegion.superclass.show.call(this);
50870 beforeSlide: function(){
50871 if(Roo.isGecko){// firefox overflow auto bug workaround
50872 this.bodyEl.clip();
50873 if(this.tabs) this.tabs.bodyEl.clip();
50874 if(this.activePanel){
50875 this.activePanel.getEl().clip();
50877 if(this.activePanel.beforeSlide){
50878 this.activePanel.beforeSlide();
50884 afterSlide : function(){
50885 if(Roo.isGecko){// firefox overflow auto bug workaround
50886 this.bodyEl.unclip();
50887 if(this.tabs) this.tabs.bodyEl.unclip();
50888 if(this.activePanel){
50889 this.activePanel.getEl().unclip();
50890 if(this.activePanel.afterSlide){
50891 this.activePanel.afterSlide();
50897 initAutoHide : function(){
50898 if(this.autoHide !== false){
50899 if(!this.autoHideHd){
50900 var st = new Roo.util.DelayedTask(this.slideIn, this);
50901 this.autoHideHd = {
50902 "mouseout": function(e){
50903 if(!e.within(this.el, true)){
50907 "mouseover" : function(e){
50913 this.el.on(this.autoHideHd);
50917 clearAutoHide : function(){
50918 if(this.autoHide !== false){
50919 this.el.un("mouseout", this.autoHideHd.mouseout);
50920 this.el.un("mouseover", this.autoHideHd.mouseover);
50924 clearMonitor : function(){
50925 Roo.get(document).un("click", this.slideInIf, this);
50928 // these names are backwards but not changed for compat
50929 slideOut : function(){
50930 if(this.isSlid || this.el.hasActiveFx()){
50933 this.isSlid = true;
50934 if(this.collapseBtn){
50935 this.collapseBtn.hide();
50937 this.closeBtnState = this.closeBtn.getStyle('display');
50938 this.closeBtn.hide();
50940 this.stickBtn.show();
50943 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50944 this.beforeSlide();
50945 this.el.setStyle("z-index", 10001);
50946 this.el.slideIn(this.getSlideAnchor(), {
50947 callback: function(){
50949 this.initAutoHide();
50950 Roo.get(document).on("click", this.slideInIf, this);
50951 this.fireEvent("slideshow", this);
50958 afterSlideIn : function(){
50959 this.clearAutoHide();
50960 this.isSlid = false;
50961 this.clearMonitor();
50962 this.el.setStyle("z-index", "");
50963 if(this.collapseBtn){
50964 this.collapseBtn.show();
50966 this.closeBtn.setStyle('display', this.closeBtnState);
50968 this.stickBtn.hide();
50970 this.fireEvent("slidehide", this);
50973 slideIn : function(cb){
50974 if(!this.isSlid || this.el.hasActiveFx()){
50978 this.isSlid = false;
50979 this.beforeSlide();
50980 this.el.slideOut(this.getSlideAnchor(), {
50981 callback: function(){
50982 this.el.setLeftTop(-10000, -10000);
50984 this.afterSlideIn();
50992 slideInIf : function(e){
50993 if(!e.within(this.el)){
50998 animateCollapse : function(){
50999 this.beforeSlide();
51000 this.el.setStyle("z-index", 20000);
51001 var anchor = this.getSlideAnchor();
51002 this.el.slideOut(anchor, {
51003 callback : function(){
51004 this.el.setStyle("z-index", "");
51005 this.collapsedEl.slideIn(anchor, {duration:.3});
51007 this.el.setLocation(-10000,-10000);
51009 this.fireEvent("collapsed", this);
51016 animateExpand : function(){
51017 this.beforeSlide();
51018 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
51019 this.el.setStyle("z-index", 20000);
51020 this.collapsedEl.hide({
51023 this.el.slideIn(this.getSlideAnchor(), {
51024 callback : function(){
51025 this.el.setStyle("z-index", "");
51028 this.split.el.show();
51030 this.fireEvent("invalidated", this);
51031 this.fireEvent("expanded", this);
51059 getAnchor : function(){
51060 return this.anchors[this.position];
51063 getCollapseAnchor : function(){
51064 return this.canchors[this.position];
51067 getSlideAnchor : function(){
51068 return this.sanchors[this.position];
51071 getAlignAdj : function(){
51072 var cm = this.cmargins;
51073 switch(this.position){
51089 getExpandAdj : function(){
51090 var c = this.collapsedEl, cm = this.cmargins;
51091 switch(this.position){
51093 return [-(cm.right+c.getWidth()+cm.left), 0];
51096 return [cm.right+c.getWidth()+cm.left, 0];
51099 return [0, -(cm.top+cm.bottom+c.getHeight())];
51102 return [0, cm.top+cm.bottom+c.getHeight()];
51108 * Ext JS Library 1.1.1
51109 * Copyright(c) 2006-2007, Ext JS, LLC.
51111 * Originally Released Under LGPL - original licence link has changed is not relivant.
51114 * <script type="text/javascript">
51117 * These classes are private internal classes
51119 Roo.CenterLayoutRegion = function(mgr, config){
51120 Roo.LayoutRegion.call(this, mgr, config, "center");
51121 this.visible = true;
51122 this.minWidth = config.minWidth || 20;
51123 this.minHeight = config.minHeight || 20;
51126 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51128 // center panel can't be hidden
51132 // center panel can't be hidden
51135 getMinWidth: function(){
51136 return this.minWidth;
51139 getMinHeight: function(){
51140 return this.minHeight;
51145 Roo.NorthLayoutRegion = function(mgr, config){
51146 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51148 this.split.placement = Roo.SplitBar.TOP;
51149 this.split.orientation = Roo.SplitBar.VERTICAL;
51150 this.split.el.addClass("x-layout-split-v");
51152 var size = config.initialSize || config.height;
51153 if(typeof size != "undefined"){
51154 this.el.setHeight(size);
51157 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51158 orientation: Roo.SplitBar.VERTICAL,
51159 getBox : function(){
51160 if(this.collapsed){
51161 return this.collapsedEl.getBox();
51163 var box = this.el.getBox();
51165 box.height += this.split.el.getHeight();
51170 updateBox : function(box){
51171 if(this.split && !this.collapsed){
51172 box.height -= this.split.el.getHeight();
51173 this.split.el.setLeft(box.x);
51174 this.split.el.setTop(box.y+box.height);
51175 this.split.el.setWidth(box.width);
51177 if(this.collapsed){
51178 this.updateBody(box.width, null);
51180 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51184 Roo.SouthLayoutRegion = function(mgr, config){
51185 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51187 this.split.placement = Roo.SplitBar.BOTTOM;
51188 this.split.orientation = Roo.SplitBar.VERTICAL;
51189 this.split.el.addClass("x-layout-split-v");
51191 var size = config.initialSize || config.height;
51192 if(typeof size != "undefined"){
51193 this.el.setHeight(size);
51196 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51197 orientation: Roo.SplitBar.VERTICAL,
51198 getBox : function(){
51199 if(this.collapsed){
51200 return this.collapsedEl.getBox();
51202 var box = this.el.getBox();
51204 var sh = this.split.el.getHeight();
51211 updateBox : function(box){
51212 if(this.split && !this.collapsed){
51213 var sh = this.split.el.getHeight();
51216 this.split.el.setLeft(box.x);
51217 this.split.el.setTop(box.y-sh);
51218 this.split.el.setWidth(box.width);
51220 if(this.collapsed){
51221 this.updateBody(box.width, null);
51223 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51227 Roo.EastLayoutRegion = function(mgr, config){
51228 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51230 this.split.placement = Roo.SplitBar.RIGHT;
51231 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51232 this.split.el.addClass("x-layout-split-h");
51234 var size = config.initialSize || config.width;
51235 if(typeof size != "undefined"){
51236 this.el.setWidth(size);
51239 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51240 orientation: Roo.SplitBar.HORIZONTAL,
51241 getBox : function(){
51242 if(this.collapsed){
51243 return this.collapsedEl.getBox();
51245 var box = this.el.getBox();
51247 var sw = this.split.el.getWidth();
51254 updateBox : function(box){
51255 if(this.split && !this.collapsed){
51256 var sw = this.split.el.getWidth();
51258 this.split.el.setLeft(box.x);
51259 this.split.el.setTop(box.y);
51260 this.split.el.setHeight(box.height);
51263 if(this.collapsed){
51264 this.updateBody(null, box.height);
51266 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51270 Roo.WestLayoutRegion = function(mgr, config){
51271 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51273 this.split.placement = Roo.SplitBar.LEFT;
51274 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51275 this.split.el.addClass("x-layout-split-h");
51277 var size = config.initialSize || config.width;
51278 if(typeof size != "undefined"){
51279 this.el.setWidth(size);
51282 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51283 orientation: Roo.SplitBar.HORIZONTAL,
51284 getBox : function(){
51285 if(this.collapsed){
51286 return this.collapsedEl.getBox();
51288 var box = this.el.getBox();
51290 box.width += this.split.el.getWidth();
51295 updateBox : function(box){
51296 if(this.split && !this.collapsed){
51297 var sw = this.split.el.getWidth();
51299 this.split.el.setLeft(box.x+box.width);
51300 this.split.el.setTop(box.y);
51301 this.split.el.setHeight(box.height);
51303 if(this.collapsed){
51304 this.updateBody(null, box.height);
51306 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51311 * Ext JS Library 1.1.1
51312 * Copyright(c) 2006-2007, Ext JS, LLC.
51314 * Originally Released Under LGPL - original licence link has changed is not relivant.
51317 * <script type="text/javascript">
51322 * Private internal class for reading and applying state
51324 Roo.LayoutStateManager = function(layout){
51325 // default empty state
51334 Roo.LayoutStateManager.prototype = {
51335 init : function(layout, provider){
51336 this.provider = provider;
51337 var state = provider.get(layout.id+"-layout-state");
51339 var wasUpdating = layout.isUpdating();
51341 layout.beginUpdate();
51343 for(var key in state){
51344 if(typeof state[key] != "function"){
51345 var rstate = state[key];
51346 var r = layout.getRegion(key);
51349 r.resizeTo(rstate.size);
51351 if(rstate.collapsed == true){
51354 r.expand(null, true);
51360 layout.endUpdate();
51362 this.state = state;
51364 this.layout = layout;
51365 layout.on("regionresized", this.onRegionResized, this);
51366 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51367 layout.on("regionexpanded", this.onRegionExpanded, this);
51370 storeState : function(){
51371 this.provider.set(this.layout.id+"-layout-state", this.state);
51374 onRegionResized : function(region, newSize){
51375 this.state[region.getPosition()].size = newSize;
51379 onRegionCollapsed : function(region){
51380 this.state[region.getPosition()].collapsed = true;
51384 onRegionExpanded : function(region){
51385 this.state[region.getPosition()].collapsed = false;
51390 * Ext JS Library 1.1.1
51391 * Copyright(c) 2006-2007, Ext JS, LLC.
51393 * Originally Released Under LGPL - original licence link has changed is not relivant.
51396 * <script type="text/javascript">
51399 * @class Roo.ContentPanel
51400 * @extends Roo.util.Observable
51401 * A basic ContentPanel element.
51402 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51403 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51404 * @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
51405 * @cfg {Boolean} closable True if the panel can be closed/removed
51406 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51407 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51408 * @cfg {Toolbar} toolbar A toolbar for this panel
51409 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51410 * @cfg {String} title The title for this panel
51411 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51412 * @cfg {String} url Calls {@link #setUrl} with this value
51413 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51414 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51415 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51416 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51419 * Create a new ContentPanel.
51420 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51421 * @param {String/Object} config A string to set only the title or a config object
51422 * @param {String} content (optional) Set the HTML content for this panel
51423 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51425 Roo.ContentPanel = function(el, config, content){
51429 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51433 if (config && config.parentLayout) {
51434 el = config.parentLayout.el.createChild();
51437 if(el.autoCreate){ // xtype is available if this is called from factory
51441 this.el = Roo.get(el);
51442 if(!this.el && config && config.autoCreate){
51443 if(typeof config.autoCreate == "object"){
51444 if(!config.autoCreate.id){
51445 config.autoCreate.id = config.id||el;
51447 this.el = Roo.DomHelper.append(document.body,
51448 config.autoCreate, true);
51450 this.el = Roo.DomHelper.append(document.body,
51451 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51454 this.closable = false;
51455 this.loaded = false;
51456 this.active = false;
51457 if(typeof config == "string"){
51458 this.title = config;
51460 Roo.apply(this, config);
51463 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51464 this.wrapEl = this.el.wrap();
51465 this.toolbar.container = this.el.insertSibling(false, 'before');
51466 this.toolbar = new Roo.Toolbar(this.toolbar);
51469 // xtype created footer. - not sure if will work as we normally have to render first..
51470 if (this.footer && !this.footer.el && this.footer.xtype) {
51471 if (!this.wrapEl) {
51472 this.wrapEl = this.el.wrap();
51475 this.footer.container = this.wrapEl.createChild();
51477 this.footer = Roo.factory(this.footer, Roo);
51482 this.resizeEl = Roo.get(this.resizeEl, true);
51484 this.resizeEl = this.el;
51486 // handle view.xtype
51494 * Fires when this panel is activated.
51495 * @param {Roo.ContentPanel} this
51499 * @event deactivate
51500 * Fires when this panel is activated.
51501 * @param {Roo.ContentPanel} this
51503 "deactivate" : true,
51507 * Fires when this panel is resized if fitToFrame is true.
51508 * @param {Roo.ContentPanel} this
51509 * @param {Number} width The width after any component adjustments
51510 * @param {Number} height The height after any component adjustments
51516 * Fires when this tab is created
51517 * @param {Roo.ContentPanel} this
51528 if(this.autoScroll){
51529 this.resizeEl.setStyle("overflow", "auto");
51531 // fix randome scrolling
51532 this.el.on('scroll', function() {
51533 Roo.log('fix random scolling');
51534 this.scrollTo('top',0);
51537 content = content || this.content;
51539 this.setContent(content);
51541 if(config && config.url){
51542 this.setUrl(this.url, this.params, this.loadOnce);
51547 Roo.ContentPanel.superclass.constructor.call(this);
51549 if (this.view && typeof(this.view.xtype) != 'undefined') {
51550 this.view.el = this.el.appendChild(document.createElement("div"));
51551 this.view = Roo.factory(this.view);
51552 this.view.render && this.view.render(false, '');
51556 this.fireEvent('render', this);
51559 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51561 setRegion : function(region){
51562 this.region = region;
51564 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51566 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51571 * Returns the toolbar for this Panel if one was configured.
51572 * @return {Roo.Toolbar}
51574 getToolbar : function(){
51575 return this.toolbar;
51578 setActiveState : function(active){
51579 this.active = active;
51581 this.fireEvent("deactivate", this);
51583 this.fireEvent("activate", this);
51587 * Updates this panel's element
51588 * @param {String} content The new content
51589 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51591 setContent : function(content, loadScripts){
51592 this.el.update(content, loadScripts);
51595 ignoreResize : function(w, h){
51596 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51599 this.lastSize = {width: w, height: h};
51604 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51605 * @return {Roo.UpdateManager} The UpdateManager
51607 getUpdateManager : function(){
51608 return this.el.getUpdateManager();
51611 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51612 * @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:
51615 url: "your-url.php",
51616 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51617 callback: yourFunction,
51618 scope: yourObject, //(optional scope)
51621 text: "Loading...",
51626 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51627 * 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.
51628 * @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}
51629 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51630 * @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.
51631 * @return {Roo.ContentPanel} this
51634 var um = this.el.getUpdateManager();
51635 um.update.apply(um, arguments);
51641 * 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.
51642 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51643 * @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)
51644 * @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)
51645 * @return {Roo.UpdateManager} The UpdateManager
51647 setUrl : function(url, params, loadOnce){
51648 if(this.refreshDelegate){
51649 this.removeListener("activate", this.refreshDelegate);
51651 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51652 this.on("activate", this.refreshDelegate);
51653 return this.el.getUpdateManager();
51656 _handleRefresh : function(url, params, loadOnce){
51657 if(!loadOnce || !this.loaded){
51658 var updater = this.el.getUpdateManager();
51659 updater.update(url, params, this._setLoaded.createDelegate(this));
51663 _setLoaded : function(){
51664 this.loaded = true;
51668 * Returns this panel's id
51671 getId : function(){
51676 * Returns this panel's element - used by regiosn to add.
51677 * @return {Roo.Element}
51679 getEl : function(){
51680 return this.wrapEl || this.el;
51683 adjustForComponents : function(width, height)
51685 //Roo.log('adjustForComponents ');
51686 if(this.resizeEl != this.el){
51687 width -= this.el.getFrameWidth('lr');
51688 height -= this.el.getFrameWidth('tb');
51691 var te = this.toolbar.getEl();
51692 height -= te.getHeight();
51693 te.setWidth(width);
51696 var te = this.footer.getEl();
51697 Roo.log("footer:" + te.getHeight());
51699 height -= te.getHeight();
51700 te.setWidth(width);
51704 if(this.adjustments){
51705 width += this.adjustments[0];
51706 height += this.adjustments[1];
51708 return {"width": width, "height": height};
51711 setSize : function(width, height){
51712 if(this.fitToFrame && !this.ignoreResize(width, height)){
51713 if(this.fitContainer && this.resizeEl != this.el){
51714 this.el.setSize(width, height);
51716 var size = this.adjustForComponents(width, height);
51717 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51718 this.fireEvent('resize', this, size.width, size.height);
51723 * Returns this panel's title
51726 getTitle : function(){
51731 * Set this panel's title
51732 * @param {String} title
51734 setTitle : function(title){
51735 this.title = title;
51737 this.region.updatePanelTitle(this, title);
51742 * Returns true is this panel was configured to be closable
51743 * @return {Boolean}
51745 isClosable : function(){
51746 return this.closable;
51749 beforeSlide : function(){
51751 this.resizeEl.clip();
51754 afterSlide : function(){
51756 this.resizeEl.unclip();
51760 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51761 * Will fail silently if the {@link #setUrl} method has not been called.
51762 * This does not activate the panel, just updates its content.
51764 refresh : function(){
51765 if(this.refreshDelegate){
51766 this.loaded = false;
51767 this.refreshDelegate();
51772 * Destroys this panel
51774 destroy : function(){
51775 this.el.removeAllListeners();
51776 var tempEl = document.createElement("span");
51777 tempEl.appendChild(this.el.dom);
51778 tempEl.innerHTML = "";
51784 * form - if the content panel contains a form - this is a reference to it.
51785 * @type {Roo.form.Form}
51789 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51790 * This contains a reference to it.
51796 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51806 * @param {Object} cfg Xtype definition of item to add.
51809 addxtype : function(cfg) {
51811 if (cfg.xtype.match(/^Form$/)) {
51814 //if (this.footer) {
51815 // el = this.footer.container.insertSibling(false, 'before');
51817 el = this.el.createChild();
51820 this.form = new Roo.form.Form(cfg);
51823 if ( this.form.allItems.length) this.form.render(el.dom);
51826 // should only have one of theses..
51827 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51828 // views.. should not be just added - used named prop 'view''
51830 cfg.el = this.el.appendChild(document.createElement("div"));
51833 var ret = new Roo.factory(cfg);
51835 ret.render && ret.render(false, ''); // render blank..
51844 * @class Roo.GridPanel
51845 * @extends Roo.ContentPanel
51847 * Create a new GridPanel.
51848 * @param {Roo.grid.Grid} grid The grid for this panel
51849 * @param {String/Object} config A string to set only the panel's title, or a config object
51851 Roo.GridPanel = function(grid, config){
51854 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51855 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51857 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51859 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51862 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51864 // xtype created footer. - not sure if will work as we normally have to render first..
51865 if (this.footer && !this.footer.el && this.footer.xtype) {
51867 this.footer.container = this.grid.getView().getFooterPanel(true);
51868 this.footer.dataSource = this.grid.dataSource;
51869 this.footer = Roo.factory(this.footer, Roo);
51873 grid.monitorWindowResize = false; // turn off autosizing
51874 grid.autoHeight = false;
51875 grid.autoWidth = false;
51877 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51880 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51881 getId : function(){
51882 return this.grid.id;
51886 * Returns the grid for this panel
51887 * @return {Roo.grid.Grid}
51889 getGrid : function(){
51893 setSize : function(width, height){
51894 if(!this.ignoreResize(width, height)){
51895 var grid = this.grid;
51896 var size = this.adjustForComponents(width, height);
51897 grid.getGridEl().setSize(size.width, size.height);
51902 beforeSlide : function(){
51903 this.grid.getView().scroller.clip();
51906 afterSlide : function(){
51907 this.grid.getView().scroller.unclip();
51910 destroy : function(){
51911 this.grid.destroy();
51913 Roo.GridPanel.superclass.destroy.call(this);
51919 * @class Roo.NestedLayoutPanel
51920 * @extends Roo.ContentPanel
51922 * Create a new NestedLayoutPanel.
51925 * @param {Roo.BorderLayout} layout The layout for this panel
51926 * @param {String/Object} config A string to set only the title or a config object
51928 Roo.NestedLayoutPanel = function(layout, config)
51930 // construct with only one argument..
51931 /* FIXME - implement nicer consturctors
51932 if (layout.layout) {
51934 layout = config.layout;
51935 delete config.layout;
51937 if (layout.xtype && !layout.getEl) {
51938 // then layout needs constructing..
51939 layout = Roo.factory(layout, Roo);
51944 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51946 layout.monitorWindowResize = false; // turn off autosizing
51947 this.layout = layout;
51948 this.layout.getEl().addClass("x-layout-nested-layout");
51955 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51957 setSize : function(width, height){
51958 if(!this.ignoreResize(width, height)){
51959 var size = this.adjustForComponents(width, height);
51960 var el = this.layout.getEl();
51961 el.setSize(size.width, size.height);
51962 var touch = el.dom.offsetWidth;
51963 this.layout.layout();
51964 // ie requires a double layout on the first pass
51965 if(Roo.isIE && !this.initialized){
51966 this.initialized = true;
51967 this.layout.layout();
51972 // activate all subpanels if not currently active..
51974 setActiveState : function(active){
51975 this.active = active;
51977 this.fireEvent("deactivate", this);
51981 this.fireEvent("activate", this);
51982 // not sure if this should happen before or after..
51983 if (!this.layout) {
51984 return; // should not happen..
51987 for (var r in this.layout.regions) {
51988 reg = this.layout.getRegion(r);
51989 if (reg.getActivePanel()) {
51990 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51991 reg.setActivePanel(reg.getActivePanel());
51994 if (!reg.panels.length) {
51997 reg.showPanel(reg.getPanel(0));
52006 * Returns the nested BorderLayout for this panel
52007 * @return {Roo.BorderLayout}
52009 getLayout : function(){
52010 return this.layout;
52014 * Adds a xtype elements to the layout of the nested panel
52018 xtype : 'ContentPanel',
52025 xtype : 'NestedLayoutPanel',
52031 items : [ ... list of content panels or nested layout panels.. ]
52035 * @param {Object} cfg Xtype definition of item to add.
52037 addxtype : function(cfg) {
52038 return this.layout.addxtype(cfg);
52043 Roo.ScrollPanel = function(el, config, content){
52044 config = config || {};
52045 config.fitToFrame = true;
52046 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
52048 this.el.dom.style.overflow = "hidden";
52049 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
52050 this.el.removeClass("x-layout-inactive-content");
52051 this.el.on("mousewheel", this.onWheel, this);
52053 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
52054 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
52055 up.unselectable(); down.unselectable();
52056 up.on("click", this.scrollUp, this);
52057 down.on("click", this.scrollDown, this);
52058 up.addClassOnOver("x-scroller-btn-over");
52059 down.addClassOnOver("x-scroller-btn-over");
52060 up.addClassOnClick("x-scroller-btn-click");
52061 down.addClassOnClick("x-scroller-btn-click");
52062 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
52064 this.resizeEl = this.el;
52065 this.el = wrap; this.up = up; this.down = down;
52068 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
52070 wheelIncrement : 5,
52071 scrollUp : function(){
52072 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
52075 scrollDown : function(){
52076 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
52079 afterScroll : function(){
52080 var el = this.resizeEl;
52081 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52082 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52083 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52086 setSize : function(){
52087 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52088 this.afterScroll();
52091 onWheel : function(e){
52092 var d = e.getWheelDelta();
52093 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52094 this.afterScroll();
52098 setContent : function(content, loadScripts){
52099 this.resizeEl.update(content, loadScripts);
52113 * @class Roo.TreePanel
52114 * @extends Roo.ContentPanel
52116 * Create a new TreePanel. - defaults to fit/scoll contents.
52117 * @param {String/Object} config A string to set only the panel's title, or a config object
52118 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52120 Roo.TreePanel = function(config){
52121 var el = config.el;
52122 var tree = config.tree;
52123 delete config.tree;
52124 delete config.el; // hopefull!
52126 // wrapper for IE7 strict & safari scroll issue
52128 var treeEl = el.createChild();
52129 config.resizeEl = treeEl;
52133 Roo.TreePanel.superclass.constructor.call(this, el, config);
52136 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52137 //console.log(tree);
52138 this.on('activate', function()
52140 if (this.tree.rendered) {
52143 //console.log('render tree');
52144 this.tree.render();
52146 // this should not be needed.. - it's actually the 'el' that resizes?
52147 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52149 //this.on('resize', function (cp, w, h) {
52150 // this.tree.innerCt.setWidth(w);
52151 // this.tree.innerCt.setHeight(h);
52152 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52159 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52176 * Ext JS Library 1.1.1
52177 * Copyright(c) 2006-2007, Ext JS, LLC.
52179 * Originally Released Under LGPL - original licence link has changed is not relivant.
52182 * <script type="text/javascript">
52187 * @class Roo.ReaderLayout
52188 * @extends Roo.BorderLayout
52189 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52190 * center region containing two nested regions (a top one for a list view and one for item preview below),
52191 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52192 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52193 * expedites the setup of the overall layout and regions for this common application style.
52196 var reader = new Roo.ReaderLayout();
52197 var CP = Roo.ContentPanel; // shortcut for adding
52199 reader.beginUpdate();
52200 reader.add("north", new CP("north", "North"));
52201 reader.add("west", new CP("west", {title: "West"}));
52202 reader.add("east", new CP("east", {title: "East"}));
52204 reader.regions.listView.add(new CP("listView", "List"));
52205 reader.regions.preview.add(new CP("preview", "Preview"));
52206 reader.endUpdate();
52209 * Create a new ReaderLayout
52210 * @param {Object} config Configuration options
52211 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52212 * document.body if omitted)
52214 Roo.ReaderLayout = function(config, renderTo){
52215 var c = config || {size:{}};
52216 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52217 north: c.north !== false ? Roo.apply({
52221 }, c.north) : false,
52222 west: c.west !== false ? Roo.apply({
52230 margins:{left:5,right:0,bottom:5,top:5},
52231 cmargins:{left:5,right:5,bottom:5,top:5}
52232 }, c.west) : false,
52233 east: c.east !== false ? Roo.apply({
52241 margins:{left:0,right:5,bottom:5,top:5},
52242 cmargins:{left:5,right:5,bottom:5,top:5}
52243 }, c.east) : false,
52244 center: Roo.apply({
52245 tabPosition: 'top',
52249 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52253 this.el.addClass('x-reader');
52255 this.beginUpdate();
52257 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52258 south: c.preview !== false ? Roo.apply({
52265 cmargins:{top:5,left:0, right:0, bottom:0}
52266 }, c.preview) : false,
52267 center: Roo.apply({
52273 this.add('center', new Roo.NestedLayoutPanel(inner,
52274 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52278 this.regions.preview = inner.getRegion('south');
52279 this.regions.listView = inner.getRegion('center');
52282 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52284 * Ext JS Library 1.1.1
52285 * Copyright(c) 2006-2007, Ext JS, LLC.
52287 * Originally Released Under LGPL - original licence link has changed is not relivant.
52290 * <script type="text/javascript">
52294 * @class Roo.grid.Grid
52295 * @extends Roo.util.Observable
52296 * This class represents the primary interface of a component based grid control.
52297 * <br><br>Usage:<pre><code>
52298 var grid = new Roo.grid.Grid("my-container-id", {
52301 selModel: mySelectionModel,
52302 autoSizeColumns: true,
52303 monitorWindowResize: false,
52304 trackMouseOver: true
52309 * <b>Common Problems:</b><br/>
52310 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52311 * element will correct this<br/>
52312 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52313 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52314 * are unpredictable.<br/>
52315 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52316 * grid to calculate dimensions/offsets.<br/>
52318 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52319 * The container MUST have some type of size defined for the grid to fill. The container will be
52320 * automatically set to position relative if it isn't already.
52321 * @param {Object} config A config object that sets properties on this grid.
52323 Roo.grid.Grid = function(container, config){
52324 // initialize the container
52325 this.container = Roo.get(container);
52326 this.container.update("");
52327 this.container.setStyle("overflow", "hidden");
52328 this.container.addClass('x-grid-container');
52330 this.id = this.container.id;
52332 Roo.apply(this, config);
52333 // check and correct shorthanded configs
52335 this.dataSource = this.ds;
52339 this.colModel = this.cm;
52343 this.selModel = this.sm;
52347 if (this.selModel) {
52348 this.selModel = Roo.factory(this.selModel, Roo.grid);
52349 this.sm = this.selModel;
52350 this.sm.xmodule = this.xmodule || false;
52352 if (typeof(this.colModel.config) == 'undefined') {
52353 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52354 this.cm = this.colModel;
52355 this.cm.xmodule = this.xmodule || false;
52357 if (this.dataSource) {
52358 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52359 this.ds = this.dataSource;
52360 this.ds.xmodule = this.xmodule || false;
52367 this.container.setWidth(this.width);
52371 this.container.setHeight(this.height);
52378 * The raw click event for the entire grid.
52379 * @param {Roo.EventObject} e
52384 * The raw dblclick event for the entire grid.
52385 * @param {Roo.EventObject} e
52389 * @event contextmenu
52390 * The raw contextmenu event for the entire grid.
52391 * @param {Roo.EventObject} e
52393 "contextmenu" : true,
52396 * The raw mousedown event for the entire grid.
52397 * @param {Roo.EventObject} e
52399 "mousedown" : true,
52402 * The raw mouseup event for the entire grid.
52403 * @param {Roo.EventObject} e
52408 * The raw mouseover event for the entire grid.
52409 * @param {Roo.EventObject} e
52411 "mouseover" : true,
52414 * The raw mouseout event for the entire grid.
52415 * @param {Roo.EventObject} e
52420 * The raw keypress event for the entire grid.
52421 * @param {Roo.EventObject} e
52426 * The raw keydown event for the entire grid.
52427 * @param {Roo.EventObject} e
52435 * Fires when a cell is clicked
52436 * @param {Grid} this
52437 * @param {Number} rowIndex
52438 * @param {Number} columnIndex
52439 * @param {Roo.EventObject} e
52441 "cellclick" : true,
52443 * @event celldblclick
52444 * Fires when a cell is double clicked
52445 * @param {Grid} this
52446 * @param {Number} rowIndex
52447 * @param {Number} columnIndex
52448 * @param {Roo.EventObject} e
52450 "celldblclick" : true,
52453 * Fires when a row is clicked
52454 * @param {Grid} this
52455 * @param {Number} rowIndex
52456 * @param {Roo.EventObject} e
52460 * @event rowdblclick
52461 * Fires when a row is double clicked
52462 * @param {Grid} this
52463 * @param {Number} rowIndex
52464 * @param {Roo.EventObject} e
52466 "rowdblclick" : true,
52468 * @event headerclick
52469 * Fires when a header is clicked
52470 * @param {Grid} this
52471 * @param {Number} columnIndex
52472 * @param {Roo.EventObject} e
52474 "headerclick" : true,
52476 * @event headerdblclick
52477 * Fires when a header cell is double clicked
52478 * @param {Grid} this
52479 * @param {Number} columnIndex
52480 * @param {Roo.EventObject} e
52482 "headerdblclick" : true,
52484 * @event rowcontextmenu
52485 * Fires when a row is right clicked
52486 * @param {Grid} this
52487 * @param {Number} rowIndex
52488 * @param {Roo.EventObject} e
52490 "rowcontextmenu" : true,
52492 * @event cellcontextmenu
52493 * Fires when a cell is right clicked
52494 * @param {Grid} this
52495 * @param {Number} rowIndex
52496 * @param {Number} cellIndex
52497 * @param {Roo.EventObject} e
52499 "cellcontextmenu" : true,
52501 * @event headercontextmenu
52502 * Fires when a header is right clicked
52503 * @param {Grid} this
52504 * @param {Number} columnIndex
52505 * @param {Roo.EventObject} e
52507 "headercontextmenu" : true,
52509 * @event bodyscroll
52510 * Fires when the body element is scrolled
52511 * @param {Number} scrollLeft
52512 * @param {Number} scrollTop
52514 "bodyscroll" : true,
52516 * @event columnresize
52517 * Fires when the user resizes a column
52518 * @param {Number} columnIndex
52519 * @param {Number} newSize
52521 "columnresize" : true,
52523 * @event columnmove
52524 * Fires when the user moves a column
52525 * @param {Number} oldIndex
52526 * @param {Number} newIndex
52528 "columnmove" : true,
52531 * Fires when row(s) start being dragged
52532 * @param {Grid} this
52533 * @param {Roo.GridDD} dd The drag drop object
52534 * @param {event} e The raw browser event
52536 "startdrag" : true,
52539 * Fires when a drag operation is complete
52540 * @param {Grid} this
52541 * @param {Roo.GridDD} dd The drag drop object
52542 * @param {event} e The raw browser event
52547 * Fires when dragged row(s) are dropped on a valid DD target
52548 * @param {Grid} this
52549 * @param {Roo.GridDD} dd The drag drop object
52550 * @param {String} targetId The target drag drop object
52551 * @param {event} e The raw browser event
52556 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52557 * @param {Grid} this
52558 * @param {Roo.GridDD} dd The drag drop object
52559 * @param {String} targetId The target drag drop object
52560 * @param {event} e The raw browser event
52565 * Fires when the dragged row(s) first cross another DD target while being dragged
52566 * @param {Grid} this
52567 * @param {Roo.GridDD} dd The drag drop object
52568 * @param {String} targetId The target drag drop object
52569 * @param {event} e The raw browser event
52571 "dragenter" : true,
52574 * Fires when the dragged row(s) leave another DD target while being dragged
52575 * @param {Grid} this
52576 * @param {Roo.GridDD} dd The drag drop object
52577 * @param {String} targetId The target drag drop object
52578 * @param {event} e The raw browser event
52583 * Fires when a row is rendered, so you can change add a style to it.
52584 * @param {GridView} gridview The grid view
52585 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52591 * Fires when the grid is rendered
52592 * @param {Grid} grid
52597 Roo.grid.Grid.superclass.constructor.call(this);
52599 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52602 * @cfg {String} ddGroup - drag drop group.
52606 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52608 minColumnWidth : 25,
52611 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52612 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52613 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52615 autoSizeColumns : false,
52618 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52620 autoSizeHeaders : true,
52623 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52625 monitorWindowResize : true,
52628 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52629 * rows measured to get a columns size. Default is 0 (all rows).
52631 maxRowsToMeasure : 0,
52634 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52636 trackMouseOver : true,
52639 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52643 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52645 enableDragDrop : false,
52648 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52650 enableColumnMove : true,
52653 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52655 enableColumnHide : true,
52658 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52660 enableRowHeightSync : false,
52663 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52668 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52670 autoHeight : false,
52673 * @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.
52675 autoExpandColumn : false,
52678 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52681 autoExpandMin : 50,
52684 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52686 autoExpandMax : 1000,
52689 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52694 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52698 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52708 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52709 * of a fixed width. Default is false.
52712 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52715 * Called once after all setup has been completed and the grid is ready to be rendered.
52716 * @return {Roo.grid.Grid} this
52718 render : function()
52720 var c = this.container;
52721 // try to detect autoHeight/width mode
52722 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52723 this.autoHeight = true;
52725 var view = this.getView();
52728 c.on("click", this.onClick, this);
52729 c.on("dblclick", this.onDblClick, this);
52730 c.on("contextmenu", this.onContextMenu, this);
52731 c.on("keydown", this.onKeyDown, this);
52733 c.on("touchstart", this.onTouchStart, this);
52736 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52738 this.getSelectionModel().init(this);
52743 this.loadMask = new Roo.LoadMask(this.container,
52744 Roo.apply({store:this.dataSource}, this.loadMask));
52748 if (this.toolbar && this.toolbar.xtype) {
52749 this.toolbar.container = this.getView().getHeaderPanel(true);
52750 this.toolbar = new Roo.Toolbar(this.toolbar);
52752 if (this.footer && this.footer.xtype) {
52753 this.footer.dataSource = this.getDataSource();
52754 this.footer.container = this.getView().getFooterPanel(true);
52755 this.footer = Roo.factory(this.footer, Roo);
52757 if (this.dropTarget && this.dropTarget.xtype) {
52758 delete this.dropTarget.xtype;
52759 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52763 this.rendered = true;
52764 this.fireEvent('render', this);
52769 * Reconfigures the grid to use a different Store and Column Model.
52770 * The View will be bound to the new objects and refreshed.
52771 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52772 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52774 reconfigure : function(dataSource, colModel){
52776 this.loadMask.destroy();
52777 this.loadMask = new Roo.LoadMask(this.container,
52778 Roo.apply({store:dataSource}, this.loadMask));
52780 this.view.bind(dataSource, colModel);
52781 this.dataSource = dataSource;
52782 this.colModel = colModel;
52783 this.view.refresh(true);
52787 onKeyDown : function(e){
52788 this.fireEvent("keydown", e);
52792 * Destroy this grid.
52793 * @param {Boolean} removeEl True to remove the element
52795 destroy : function(removeEl, keepListeners){
52797 this.loadMask.destroy();
52799 var c = this.container;
52800 c.removeAllListeners();
52801 this.view.destroy();
52802 this.colModel.purgeListeners();
52803 if(!keepListeners){
52804 this.purgeListeners();
52807 if(removeEl === true){
52813 processEvent : function(name, e){
52814 // does this fire select???
52815 //Roo.log('grid:processEvent ' + name);
52817 if (name != 'touchstart' ) {
52818 this.fireEvent(name, e);
52821 var t = e.getTarget();
52823 var header = v.findHeaderIndex(t);
52824 if(header !== false){
52825 var ename = name == 'touchstart' ? 'click' : name;
52827 this.fireEvent("header" + ename, this, header, e);
52829 var row = v.findRowIndex(t);
52830 var cell = v.findCellIndex(t);
52831 if (name == 'touchstart') {
52832 // first touch is always a click.
52833 // hopefull this happens after selection is updated.?
52836 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52837 var cs = this.selModel.getSelectedCell();
52838 if (row == cs[0] && cell == cs[1]){
52842 if (typeof(this.selModel.getSelections) != 'undefined') {
52843 var cs = this.selModel.getSelections();
52844 var ds = this.dataSource;
52845 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52856 this.fireEvent("row" + name, this, row, e);
52857 if(cell !== false){
52858 this.fireEvent("cell" + name, this, row, cell, e);
52865 onClick : function(e){
52866 this.processEvent("click", e);
52869 onTouchStart : function(e){
52870 this.processEvent("touchstart", e);
52874 onContextMenu : function(e, t){
52875 this.processEvent("contextmenu", e);
52879 onDblClick : function(e){
52880 this.processEvent("dblclick", e);
52884 walkCells : function(row, col, step, fn, scope){
52885 var cm = this.colModel, clen = cm.getColumnCount();
52886 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52898 if(fn.call(scope || this, row, col, cm) === true){
52916 if(fn.call(scope || this, row, col, cm) === true){
52928 getSelections : function(){
52929 return this.selModel.getSelections();
52933 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52934 * but if manual update is required this method will initiate it.
52936 autoSize : function(){
52938 this.view.layout();
52939 if(this.view.adjustForScroll){
52940 this.view.adjustForScroll();
52946 * Returns the grid's underlying element.
52947 * @return {Element} The element
52949 getGridEl : function(){
52950 return this.container;
52953 // private for compatibility, overridden by editor grid
52954 stopEditing : function(){},
52957 * Returns the grid's SelectionModel.
52958 * @return {SelectionModel}
52960 getSelectionModel : function(){
52961 if(!this.selModel){
52962 this.selModel = new Roo.grid.RowSelectionModel();
52964 return this.selModel;
52968 * Returns the grid's DataSource.
52969 * @return {DataSource}
52971 getDataSource : function(){
52972 return this.dataSource;
52976 * Returns the grid's ColumnModel.
52977 * @return {ColumnModel}
52979 getColumnModel : function(){
52980 return this.colModel;
52984 * Returns the grid's GridView object.
52985 * @return {GridView}
52987 getView : function(){
52989 this.view = new Roo.grid.GridView(this.viewConfig);
52994 * Called to get grid's drag proxy text, by default returns this.ddText.
52997 getDragDropText : function(){
52998 var count = this.selModel.getCount();
52999 return String.format(this.ddText, count, count == 1 ? '' : 's');
53003 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
53004 * %0 is replaced with the number of selected rows.
53007 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
53009 * Ext JS Library 1.1.1
53010 * Copyright(c) 2006-2007, Ext JS, LLC.
53012 * Originally Released Under LGPL - original licence link has changed is not relivant.
53015 * <script type="text/javascript">
53018 Roo.grid.AbstractGridView = function(){
53022 "beforerowremoved" : true,
53023 "beforerowsinserted" : true,
53024 "beforerefresh" : true,
53025 "rowremoved" : true,
53026 "rowsinserted" : true,
53027 "rowupdated" : true,
53030 Roo.grid.AbstractGridView.superclass.constructor.call(this);
53033 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
53034 rowClass : "x-grid-row",
53035 cellClass : "x-grid-cell",
53036 tdClass : "x-grid-td",
53037 hdClass : "x-grid-hd",
53038 splitClass : "x-grid-hd-split",
53040 init: function(grid){
53042 var cid = this.grid.getGridEl().id;
53043 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
53044 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
53045 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
53046 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
53049 getColumnRenderers : function(){
53050 var renderers = [];
53051 var cm = this.grid.colModel;
53052 var colCount = cm.getColumnCount();
53053 for(var i = 0; i < colCount; i++){
53054 renderers[i] = cm.getRenderer(i);
53059 getColumnIds : function(){
53061 var cm = this.grid.colModel;
53062 var colCount = cm.getColumnCount();
53063 for(var i = 0; i < colCount; i++){
53064 ids[i] = cm.getColumnId(i);
53069 getDataIndexes : function(){
53070 if(!this.indexMap){
53071 this.indexMap = this.buildIndexMap();
53073 return this.indexMap.colToData;
53076 getColumnIndexByDataIndex : function(dataIndex){
53077 if(!this.indexMap){
53078 this.indexMap = this.buildIndexMap();
53080 return this.indexMap.dataToCol[dataIndex];
53084 * Set a css style for a column dynamically.
53085 * @param {Number} colIndex The index of the column
53086 * @param {String} name The css property name
53087 * @param {String} value The css value
53089 setCSSStyle : function(colIndex, name, value){
53090 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53091 Roo.util.CSS.updateRule(selector, name, value);
53094 generateRules : function(cm){
53095 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53096 Roo.util.CSS.removeStyleSheet(rulesId);
53097 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53098 var cid = cm.getColumnId(i);
53099 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53100 this.tdSelector, cid, " {\n}\n",
53101 this.hdSelector, cid, " {\n}\n",
53102 this.splitSelector, cid, " {\n}\n");
53104 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53108 * Ext JS Library 1.1.1
53109 * Copyright(c) 2006-2007, Ext JS, LLC.
53111 * Originally Released Under LGPL - original licence link has changed is not relivant.
53114 * <script type="text/javascript">
53118 // This is a support class used internally by the Grid components
53119 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53121 this.view = grid.getView();
53122 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53123 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53125 this.setHandleElId(Roo.id(hd));
53126 this.setOuterHandleElId(Roo.id(hd2));
53128 this.scroll = false;
53130 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53132 getDragData : function(e){
53133 var t = Roo.lib.Event.getTarget(e);
53134 var h = this.view.findHeaderCell(t);
53136 return {ddel: h.firstChild, header:h};
53141 onInitDrag : function(e){
53142 this.view.headersDisabled = true;
53143 var clone = this.dragData.ddel.cloneNode(true);
53144 clone.id = Roo.id();
53145 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53146 this.proxy.update(clone);
53150 afterValidDrop : function(){
53152 setTimeout(function(){
53153 v.headersDisabled = false;
53157 afterInvalidDrop : function(){
53159 setTimeout(function(){
53160 v.headersDisabled = false;
53166 * Ext JS Library 1.1.1
53167 * Copyright(c) 2006-2007, Ext JS, LLC.
53169 * Originally Released Under LGPL - original licence link has changed is not relivant.
53172 * <script type="text/javascript">
53175 // This is a support class used internally by the Grid components
53176 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53178 this.view = grid.getView();
53179 // split the proxies so they don't interfere with mouse events
53180 this.proxyTop = Roo.DomHelper.append(document.body, {
53181 cls:"col-move-top", html:" "
53183 this.proxyBottom = Roo.DomHelper.append(document.body, {
53184 cls:"col-move-bottom", html:" "
53186 this.proxyTop.hide = this.proxyBottom.hide = function(){
53187 this.setLeftTop(-100,-100);
53188 this.setStyle("visibility", "hidden");
53190 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53191 // temporarily disabled
53192 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53193 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53195 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53196 proxyOffsets : [-4, -9],
53197 fly: Roo.Element.fly,
53199 getTargetFromEvent : function(e){
53200 var t = Roo.lib.Event.getTarget(e);
53201 var cindex = this.view.findCellIndex(t);
53202 if(cindex !== false){
53203 return this.view.getHeaderCell(cindex);
53208 nextVisible : function(h){
53209 var v = this.view, cm = this.grid.colModel;
53212 if(!cm.isHidden(v.getCellIndex(h))){
53220 prevVisible : function(h){
53221 var v = this.view, cm = this.grid.colModel;
53224 if(!cm.isHidden(v.getCellIndex(h))){
53232 positionIndicator : function(h, n, e){
53233 var x = Roo.lib.Event.getPageX(e);
53234 var r = Roo.lib.Dom.getRegion(n.firstChild);
53235 var px, pt, py = r.top + this.proxyOffsets[1];
53236 if((r.right - x) <= (r.right-r.left)/2){
53237 px = r.right+this.view.borderWidth;
53243 var oldIndex = this.view.getCellIndex(h);
53244 var newIndex = this.view.getCellIndex(n);
53246 if(this.grid.colModel.isFixed(newIndex)){
53250 var locked = this.grid.colModel.isLocked(newIndex);
53255 if(oldIndex < newIndex){
53258 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53261 px += this.proxyOffsets[0];
53262 this.proxyTop.setLeftTop(px, py);
53263 this.proxyTop.show();
53264 if(!this.bottomOffset){
53265 this.bottomOffset = this.view.mainHd.getHeight();
53267 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53268 this.proxyBottom.show();
53272 onNodeEnter : function(n, dd, e, data){
53273 if(data.header != n){
53274 this.positionIndicator(data.header, n, e);
53278 onNodeOver : function(n, dd, e, data){
53279 var result = false;
53280 if(data.header != n){
53281 result = this.positionIndicator(data.header, n, e);
53284 this.proxyTop.hide();
53285 this.proxyBottom.hide();
53287 return result ? this.dropAllowed : this.dropNotAllowed;
53290 onNodeOut : function(n, dd, e, data){
53291 this.proxyTop.hide();
53292 this.proxyBottom.hide();
53295 onNodeDrop : function(n, dd, e, data){
53296 var h = data.header;
53298 var cm = this.grid.colModel;
53299 var x = Roo.lib.Event.getPageX(e);
53300 var r = Roo.lib.Dom.getRegion(n.firstChild);
53301 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53302 var oldIndex = this.view.getCellIndex(h);
53303 var newIndex = this.view.getCellIndex(n);
53304 var locked = cm.isLocked(newIndex);
53308 if(oldIndex < newIndex){
53311 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53314 cm.setLocked(oldIndex, locked, true);
53315 cm.moveColumn(oldIndex, newIndex);
53316 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53324 * Ext JS Library 1.1.1
53325 * Copyright(c) 2006-2007, Ext JS, LLC.
53327 * Originally Released Under LGPL - original licence link has changed is not relivant.
53330 * <script type="text/javascript">
53334 * @class Roo.grid.GridView
53335 * @extends Roo.util.Observable
53338 * @param {Object} config
53340 Roo.grid.GridView = function(config){
53341 Roo.grid.GridView.superclass.constructor.call(this);
53344 Roo.apply(this, config);
53347 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53349 unselectable : 'unselectable="on"',
53350 unselectableCls : 'x-unselectable',
53353 rowClass : "x-grid-row",
53355 cellClass : "x-grid-col",
53357 tdClass : "x-grid-td",
53359 hdClass : "x-grid-hd",
53361 splitClass : "x-grid-split",
53363 sortClasses : ["sort-asc", "sort-desc"],
53365 enableMoveAnim : false,
53369 dh : Roo.DomHelper,
53371 fly : Roo.Element.fly,
53373 css : Roo.util.CSS,
53379 scrollIncrement : 22,
53381 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53383 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53385 bind : function(ds, cm){
53387 this.ds.un("load", this.onLoad, this);
53388 this.ds.un("datachanged", this.onDataChange, this);
53389 this.ds.un("add", this.onAdd, this);
53390 this.ds.un("remove", this.onRemove, this);
53391 this.ds.un("update", this.onUpdate, this);
53392 this.ds.un("clear", this.onClear, this);
53395 ds.on("load", this.onLoad, this);
53396 ds.on("datachanged", this.onDataChange, this);
53397 ds.on("add", this.onAdd, this);
53398 ds.on("remove", this.onRemove, this);
53399 ds.on("update", this.onUpdate, this);
53400 ds.on("clear", this.onClear, this);
53405 this.cm.un("widthchange", this.onColWidthChange, this);
53406 this.cm.un("headerchange", this.onHeaderChange, this);
53407 this.cm.un("hiddenchange", this.onHiddenChange, this);
53408 this.cm.un("columnmoved", this.onColumnMove, this);
53409 this.cm.un("columnlockchange", this.onColumnLock, this);
53412 this.generateRules(cm);
53413 cm.on("widthchange", this.onColWidthChange, this);
53414 cm.on("headerchange", this.onHeaderChange, this);
53415 cm.on("hiddenchange", this.onHiddenChange, this);
53416 cm.on("columnmoved", this.onColumnMove, this);
53417 cm.on("columnlockchange", this.onColumnLock, this);
53422 init: function(grid){
53423 Roo.grid.GridView.superclass.init.call(this, grid);
53425 this.bind(grid.dataSource, grid.colModel);
53427 grid.on("headerclick", this.handleHeaderClick, this);
53429 if(grid.trackMouseOver){
53430 grid.on("mouseover", this.onRowOver, this);
53431 grid.on("mouseout", this.onRowOut, this);
53433 grid.cancelTextSelection = function(){};
53434 this.gridId = grid.id;
53436 var tpls = this.templates || {};
53439 tpls.master = new Roo.Template(
53440 '<div class="x-grid" hidefocus="true">',
53441 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53442 '<div class="x-grid-topbar"></div>',
53443 '<div class="x-grid-scroller"><div></div></div>',
53444 '<div class="x-grid-locked">',
53445 '<div class="x-grid-header">{lockedHeader}</div>',
53446 '<div class="x-grid-body">{lockedBody}</div>',
53448 '<div class="x-grid-viewport">',
53449 '<div class="x-grid-header">{header}</div>',
53450 '<div class="x-grid-body">{body}</div>',
53452 '<div class="x-grid-bottombar"></div>',
53454 '<div class="x-grid-resize-proxy"> </div>',
53457 tpls.master.disableformats = true;
53461 tpls.header = new Roo.Template(
53462 '<table border="0" cellspacing="0" cellpadding="0">',
53463 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53466 tpls.header.disableformats = true;
53468 tpls.header.compile();
53471 tpls.hcell = new Roo.Template(
53472 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53473 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53476 tpls.hcell.disableFormats = true;
53478 tpls.hcell.compile();
53481 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53482 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53483 tpls.hsplit.disableFormats = true;
53485 tpls.hsplit.compile();
53488 tpls.body = new Roo.Template(
53489 '<table border="0" cellspacing="0" cellpadding="0">',
53490 "<tbody>{rows}</tbody>",
53493 tpls.body.disableFormats = true;
53495 tpls.body.compile();
53498 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53499 tpls.row.disableFormats = true;
53501 tpls.row.compile();
53504 tpls.cell = new Roo.Template(
53505 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53506 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53507 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53510 tpls.cell.disableFormats = true;
53512 tpls.cell.compile();
53514 this.templates = tpls;
53517 // remap these for backwards compat
53518 onColWidthChange : function(){
53519 this.updateColumns.apply(this, arguments);
53521 onHeaderChange : function(){
53522 this.updateHeaders.apply(this, arguments);
53524 onHiddenChange : function(){
53525 this.handleHiddenChange.apply(this, arguments);
53527 onColumnMove : function(){
53528 this.handleColumnMove.apply(this, arguments);
53530 onColumnLock : function(){
53531 this.handleLockChange.apply(this, arguments);
53534 onDataChange : function(){
53536 this.updateHeaderSortState();
53539 onClear : function(){
53543 onUpdate : function(ds, record){
53544 this.refreshRow(record);
53547 refreshRow : function(record){
53548 var ds = this.ds, index;
53549 if(typeof record == 'number'){
53551 record = ds.getAt(index);
53553 index = ds.indexOf(record);
53555 this.insertRows(ds, index, index, true);
53556 this.onRemove(ds, record, index+1, true);
53557 this.syncRowHeights(index, index);
53559 this.fireEvent("rowupdated", this, index, record);
53562 onAdd : function(ds, records, index){
53563 this.insertRows(ds, index, index + (records.length-1));
53566 onRemove : function(ds, record, index, isUpdate){
53567 if(isUpdate !== true){
53568 this.fireEvent("beforerowremoved", this, index, record);
53570 var bt = this.getBodyTable(), lt = this.getLockedTable();
53571 if(bt.rows[index]){
53572 bt.firstChild.removeChild(bt.rows[index]);
53574 if(lt.rows[index]){
53575 lt.firstChild.removeChild(lt.rows[index]);
53577 if(isUpdate !== true){
53578 this.stripeRows(index);
53579 this.syncRowHeights(index, index);
53581 this.fireEvent("rowremoved", this, index, record);
53585 onLoad : function(){
53586 this.scrollToTop();
53590 * Scrolls the grid to the top
53592 scrollToTop : function(){
53594 this.scroller.dom.scrollTop = 0;
53600 * Gets a panel in the header of the grid that can be used for toolbars etc.
53601 * After modifying the contents of this panel a call to grid.autoSize() may be
53602 * required to register any changes in size.
53603 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53604 * @return Roo.Element
53606 getHeaderPanel : function(doShow){
53608 this.headerPanel.show();
53610 return this.headerPanel;
53614 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53615 * After modifying the contents of this panel a call to grid.autoSize() may be
53616 * required to register any changes in size.
53617 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53618 * @return Roo.Element
53620 getFooterPanel : function(doShow){
53622 this.footerPanel.show();
53624 return this.footerPanel;
53627 initElements : function(){
53628 var E = Roo.Element;
53629 var el = this.grid.getGridEl().dom.firstChild;
53630 var cs = el.childNodes;
53632 this.el = new E(el);
53634 this.focusEl = new E(el.firstChild);
53635 this.focusEl.swallowEvent("click", true);
53637 this.headerPanel = new E(cs[1]);
53638 this.headerPanel.enableDisplayMode("block");
53640 this.scroller = new E(cs[2]);
53641 this.scrollSizer = new E(this.scroller.dom.firstChild);
53643 this.lockedWrap = new E(cs[3]);
53644 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53645 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53647 this.mainWrap = new E(cs[4]);
53648 this.mainHd = new E(this.mainWrap.dom.firstChild);
53649 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53651 this.footerPanel = new E(cs[5]);
53652 this.footerPanel.enableDisplayMode("block");
53654 this.resizeProxy = new E(cs[6]);
53656 this.headerSelector = String.format(
53657 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53658 this.lockedHd.id, this.mainHd.id
53661 this.splitterSelector = String.format(
53662 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53663 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53666 idToCssName : function(s)
53668 return s.replace(/[^a-z0-9]+/ig, '-');
53671 getHeaderCell : function(index){
53672 return Roo.DomQuery.select(this.headerSelector)[index];
53675 getHeaderCellMeasure : function(index){
53676 return this.getHeaderCell(index).firstChild;
53679 getHeaderCellText : function(index){
53680 return this.getHeaderCell(index).firstChild.firstChild;
53683 getLockedTable : function(){
53684 return this.lockedBody.dom.firstChild;
53687 getBodyTable : function(){
53688 return this.mainBody.dom.firstChild;
53691 getLockedRow : function(index){
53692 return this.getLockedTable().rows[index];
53695 getRow : function(index){
53696 return this.getBodyTable().rows[index];
53699 getRowComposite : function(index){
53701 this.rowEl = new Roo.CompositeElementLite();
53703 var els = [], lrow, mrow;
53704 if(lrow = this.getLockedRow(index)){
53707 if(mrow = this.getRow(index)){
53710 this.rowEl.elements = els;
53714 * Gets the 'td' of the cell
53716 * @param {Integer} rowIndex row to select
53717 * @param {Integer} colIndex column to select
53721 getCell : function(rowIndex, colIndex){
53722 var locked = this.cm.getLockedCount();
53724 if(colIndex < locked){
53725 source = this.lockedBody.dom.firstChild;
53727 source = this.mainBody.dom.firstChild;
53728 colIndex -= locked;
53730 return source.rows[rowIndex].childNodes[colIndex];
53733 getCellText : function(rowIndex, colIndex){
53734 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53737 getCellBox : function(cell){
53738 var b = this.fly(cell).getBox();
53739 if(Roo.isOpera){ // opera fails to report the Y
53740 b.y = cell.offsetTop + this.mainBody.getY();
53745 getCellIndex : function(cell){
53746 var id = String(cell.className).match(this.cellRE);
53748 return parseInt(id[1], 10);
53753 findHeaderIndex : function(n){
53754 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53755 return r ? this.getCellIndex(r) : false;
53758 findHeaderCell : function(n){
53759 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53760 return r ? r : false;
53763 findRowIndex : function(n){
53767 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53768 return r ? r.rowIndex : false;
53771 findCellIndex : function(node){
53772 var stop = this.el.dom;
53773 while(node && node != stop){
53774 if(this.findRE.test(node.className)){
53775 return this.getCellIndex(node);
53777 node = node.parentNode;
53782 getColumnId : function(index){
53783 return this.cm.getColumnId(index);
53786 getSplitters : function()
53788 if(this.splitterSelector){
53789 return Roo.DomQuery.select(this.splitterSelector);
53795 getSplitter : function(index){
53796 return this.getSplitters()[index];
53799 onRowOver : function(e, t){
53801 if((row = this.findRowIndex(t)) !== false){
53802 this.getRowComposite(row).addClass("x-grid-row-over");
53806 onRowOut : function(e, t){
53808 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53809 this.getRowComposite(row).removeClass("x-grid-row-over");
53813 renderHeaders : function(){
53815 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53816 var cb = [], lb = [], sb = [], lsb = [], p = {};
53817 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53818 p.cellId = "x-grid-hd-0-" + i;
53819 p.splitId = "x-grid-csplit-0-" + i;
53820 p.id = cm.getColumnId(i);
53821 p.title = cm.getColumnTooltip(i) || "";
53822 p.value = cm.getColumnHeader(i) || "";
53823 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53824 if(!cm.isLocked(i)){
53825 cb[cb.length] = ct.apply(p);
53826 sb[sb.length] = st.apply(p);
53828 lb[lb.length] = ct.apply(p);
53829 lsb[lsb.length] = st.apply(p);
53832 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53833 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53836 updateHeaders : function(){
53837 var html = this.renderHeaders();
53838 this.lockedHd.update(html[0]);
53839 this.mainHd.update(html[1]);
53843 * Focuses the specified row.
53844 * @param {Number} row The row index
53846 focusRow : function(row)
53848 //Roo.log('GridView.focusRow');
53849 var x = this.scroller.dom.scrollLeft;
53850 this.focusCell(row, 0, false);
53851 this.scroller.dom.scrollLeft = x;
53855 * Focuses the specified cell.
53856 * @param {Number} row The row index
53857 * @param {Number} col The column index
53858 * @param {Boolean} hscroll false to disable horizontal scrolling
53860 focusCell : function(row, col, hscroll)
53862 //Roo.log('GridView.focusCell');
53863 var el = this.ensureVisible(row, col, hscroll);
53864 this.focusEl.alignTo(el, "tl-tl");
53866 this.focusEl.focus();
53868 this.focusEl.focus.defer(1, this.focusEl);
53873 * Scrolls the specified cell into view
53874 * @param {Number} row The row index
53875 * @param {Number} col The column index
53876 * @param {Boolean} hscroll false to disable horizontal scrolling
53878 ensureVisible : function(row, col, hscroll)
53880 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53881 //return null; //disable for testing.
53882 if(typeof row != "number"){
53883 row = row.rowIndex;
53885 if(row < 0 && row >= this.ds.getCount()){
53888 col = (col !== undefined ? col : 0);
53889 var cm = this.grid.colModel;
53890 while(cm.isHidden(col)){
53894 var el = this.getCell(row, col);
53898 var c = this.scroller.dom;
53900 var ctop = parseInt(el.offsetTop, 10);
53901 var cleft = parseInt(el.offsetLeft, 10);
53902 var cbot = ctop + el.offsetHeight;
53903 var cright = cleft + el.offsetWidth;
53905 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53906 var stop = parseInt(c.scrollTop, 10);
53907 var sleft = parseInt(c.scrollLeft, 10);
53908 var sbot = stop + ch;
53909 var sright = sleft + c.clientWidth;
53911 Roo.log('GridView.ensureVisible:' +
53913 ' c.clientHeight:' + c.clientHeight +
53914 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53922 c.scrollTop = ctop;
53923 //Roo.log("set scrolltop to ctop DISABLE?");
53924 }else if(cbot > sbot){
53925 //Roo.log("set scrolltop to cbot-ch");
53926 c.scrollTop = cbot-ch;
53929 if(hscroll !== false){
53931 c.scrollLeft = cleft;
53932 }else if(cright > sright){
53933 c.scrollLeft = cright-c.clientWidth;
53940 updateColumns : function(){
53941 this.grid.stopEditing();
53942 var cm = this.grid.colModel, colIds = this.getColumnIds();
53943 //var totalWidth = cm.getTotalWidth();
53945 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53946 //if(cm.isHidden(i)) continue;
53947 var w = cm.getColumnWidth(i);
53948 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53949 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53951 this.updateSplitters();
53954 generateRules : function(cm){
53955 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53956 Roo.util.CSS.removeStyleSheet(rulesId);
53957 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53958 var cid = cm.getColumnId(i);
53960 if(cm.config[i].align){
53961 align = 'text-align:'+cm.config[i].align+';';
53964 if(cm.isHidden(i)){
53965 hidden = 'display:none;';
53967 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53969 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53970 this.hdSelector, cid, " {\n", align, width, "}\n",
53971 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53972 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53974 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53977 updateSplitters : function(){
53978 var cm = this.cm, s = this.getSplitters();
53979 if(s){ // splitters not created yet
53980 var pos = 0, locked = true;
53981 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53982 if(cm.isHidden(i)) continue;
53983 var w = cm.getColumnWidth(i); // make sure it's a number
53984 if(!cm.isLocked(i) && locked){
53989 s[i].style.left = (pos-this.splitOffset) + "px";
53994 handleHiddenChange : function(colModel, colIndex, hidden){
53996 this.hideColumn(colIndex);
53998 this.unhideColumn(colIndex);
54002 hideColumn : function(colIndex){
54003 var cid = this.getColumnId(colIndex);
54004 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
54005 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
54007 this.updateHeaders();
54009 this.updateSplitters();
54013 unhideColumn : function(colIndex){
54014 var cid = this.getColumnId(colIndex);
54015 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
54016 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
54019 this.updateHeaders();
54021 this.updateSplitters();
54025 insertRows : function(dm, firstRow, lastRow, isUpdate){
54026 if(firstRow == 0 && lastRow == dm.getCount()-1){
54030 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
54032 var s = this.getScrollState();
54033 var markup = this.renderRows(firstRow, lastRow);
54034 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
54035 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
54036 this.restoreScroll(s);
54038 this.fireEvent("rowsinserted", this, firstRow, lastRow);
54039 this.syncRowHeights(firstRow, lastRow);
54040 this.stripeRows(firstRow);
54046 bufferRows : function(markup, target, index){
54047 var before = null, trows = target.rows, tbody = target.tBodies[0];
54048 if(index < trows.length){
54049 before = trows[index];
54051 var b = document.createElement("div");
54052 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
54053 var rows = b.firstChild.rows;
54054 for(var i = 0, len = rows.length; i < len; i++){
54056 tbody.insertBefore(rows[0], before);
54058 tbody.appendChild(rows[0]);
54065 deleteRows : function(dm, firstRow, lastRow){
54066 if(dm.getRowCount()<1){
54067 this.fireEvent("beforerefresh", this);
54068 this.mainBody.update("");
54069 this.lockedBody.update("");
54070 this.fireEvent("refresh", this);
54072 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
54073 var bt = this.getBodyTable();
54074 var tbody = bt.firstChild;
54075 var rows = bt.rows;
54076 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
54077 tbody.removeChild(rows[firstRow]);
54079 this.stripeRows(firstRow);
54080 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54084 updateRows : function(dataSource, firstRow, lastRow){
54085 var s = this.getScrollState();
54087 this.restoreScroll(s);
54090 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54094 this.updateHeaderSortState();
54097 getScrollState : function(){
54099 var sb = this.scroller.dom;
54100 return {left: sb.scrollLeft, top: sb.scrollTop};
54103 stripeRows : function(startRow){
54104 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54107 startRow = startRow || 0;
54108 var rows = this.getBodyTable().rows;
54109 var lrows = this.getLockedTable().rows;
54110 var cls = ' x-grid-row-alt ';
54111 for(var i = startRow, len = rows.length; i < len; i++){
54112 var row = rows[i], lrow = lrows[i];
54113 var isAlt = ((i+1) % 2 == 0);
54114 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54115 if(isAlt == hasAlt){
54119 row.className += " x-grid-row-alt";
54121 row.className = row.className.replace("x-grid-row-alt", "");
54124 lrow.className = row.className;
54129 restoreScroll : function(state){
54130 //Roo.log('GridView.restoreScroll');
54131 var sb = this.scroller.dom;
54132 sb.scrollLeft = state.left;
54133 sb.scrollTop = state.top;
54137 syncScroll : function(){
54138 //Roo.log('GridView.syncScroll');
54139 var sb = this.scroller.dom;
54140 var sh = this.mainHd.dom;
54141 var bs = this.mainBody.dom;
54142 var lv = this.lockedBody.dom;
54143 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54144 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54147 handleScroll : function(e){
54149 var sb = this.scroller.dom;
54150 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54154 handleWheel : function(e){
54155 var d = e.getWheelDelta();
54156 this.scroller.dom.scrollTop -= d*22;
54157 // set this here to prevent jumpy scrolling on large tables
54158 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54162 renderRows : function(startRow, endRow){
54163 // pull in all the crap needed to render rows
54164 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54165 var colCount = cm.getColumnCount();
54167 if(ds.getCount() < 1){
54171 // build a map for all the columns
54173 for(var i = 0; i < colCount; i++){
54174 var name = cm.getDataIndex(i);
54176 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54177 renderer : cm.getRenderer(i),
54178 id : cm.getColumnId(i),
54179 locked : cm.isLocked(i)
54183 startRow = startRow || 0;
54184 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54186 // records to render
54187 var rs = ds.getRange(startRow, endRow);
54189 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54192 // As much as I hate to duplicate code, this was branched because FireFox really hates
54193 // [].join("") on strings. The performance difference was substantial enough to
54194 // branch this function
54195 doRender : Roo.isGecko ?
54196 function(cs, rs, ds, startRow, colCount, stripe){
54197 var ts = this.templates, ct = ts.cell, rt = ts.row;
54199 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54201 var hasListener = this.grid.hasListener('rowclass');
54203 for(var j = 0, len = rs.length; j < len; j++){
54204 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54205 for(var i = 0; i < colCount; i++){
54207 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54209 p.css = p.attr = "";
54210 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54211 if(p.value == undefined || p.value === "") p.value = " ";
54212 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54213 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54215 var markup = ct.apply(p);
54223 if(stripe && ((rowIndex+1) % 2 == 0)){
54224 alt.push("x-grid-row-alt")
54227 alt.push( " x-grid-dirty-row");
54230 if(this.getRowClass){
54231 alt.push(this.getRowClass(r, rowIndex));
54237 rowIndex : rowIndex,
54240 this.grid.fireEvent('rowclass', this, rowcfg);
54241 alt.push(rowcfg.rowClass);
54243 rp.alt = alt.join(" ");
54244 lbuf+= rt.apply(rp);
54246 buf+= rt.apply(rp);
54248 return [lbuf, buf];
54250 function(cs, rs, ds, startRow, colCount, stripe){
54251 var ts = this.templates, ct = ts.cell, rt = ts.row;
54253 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54254 var hasListener = this.grid.hasListener('rowclass');
54257 for(var j = 0, len = rs.length; j < len; j++){
54258 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54259 for(var i = 0; i < colCount; i++){
54261 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54263 p.css = p.attr = "";
54264 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54265 if(p.value == undefined || p.value === "") p.value = " ";
54266 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54267 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54270 var markup = ct.apply(p);
54272 cb[cb.length] = markup;
54274 lcb[lcb.length] = markup;
54278 if(stripe && ((rowIndex+1) % 2 == 0)){
54279 alt.push( "x-grid-row-alt");
54282 alt.push(" x-grid-dirty-row");
54285 if(this.getRowClass){
54286 alt.push( this.getRowClass(r, rowIndex));
54292 rowIndex : rowIndex,
54295 this.grid.fireEvent('rowclass', this, rowcfg);
54296 alt.push(rowcfg.rowClass);
54298 rp.alt = alt.join(" ");
54299 rp.cells = lcb.join("");
54300 lbuf[lbuf.length] = rt.apply(rp);
54301 rp.cells = cb.join("");
54302 buf[buf.length] = rt.apply(rp);
54304 return [lbuf.join(""), buf.join("")];
54307 renderBody : function(){
54308 var markup = this.renderRows();
54309 var bt = this.templates.body;
54310 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54314 * Refreshes the grid
54315 * @param {Boolean} headersToo
54317 refresh : function(headersToo){
54318 this.fireEvent("beforerefresh", this);
54319 this.grid.stopEditing();
54320 var result = this.renderBody();
54321 this.lockedBody.update(result[0]);
54322 this.mainBody.update(result[1]);
54323 if(headersToo === true){
54324 this.updateHeaders();
54325 this.updateColumns();
54326 this.updateSplitters();
54327 this.updateHeaderSortState();
54329 this.syncRowHeights();
54331 this.fireEvent("refresh", this);
54334 handleColumnMove : function(cm, oldIndex, newIndex){
54335 this.indexMap = null;
54336 var s = this.getScrollState();
54337 this.refresh(true);
54338 this.restoreScroll(s);
54339 this.afterMove(newIndex);
54342 afterMove : function(colIndex){
54343 if(this.enableMoveAnim && Roo.enableFx){
54344 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54346 // if multisort - fix sortOrder, and reload..
54347 if (this.grid.dataSource.multiSort) {
54348 // the we can call sort again..
54349 var dm = this.grid.dataSource;
54350 var cm = this.grid.colModel;
54352 for(var i = 0; i < cm.config.length; i++ ) {
54354 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54355 continue; // dont' bother, it's not in sort list or being set.
54358 so.push(cm.config[i].dataIndex);
54361 dm.load(dm.lastOptions);
54368 updateCell : function(dm, rowIndex, dataIndex){
54369 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54370 if(typeof colIndex == "undefined"){ // not present in grid
54373 var cm = this.grid.colModel;
54374 var cell = this.getCell(rowIndex, colIndex);
54375 var cellText = this.getCellText(rowIndex, colIndex);
54378 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54379 id : cm.getColumnId(colIndex),
54380 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54382 var renderer = cm.getRenderer(colIndex);
54383 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54384 if(typeof val == "undefined" || val === "") val = " ";
54385 cellText.innerHTML = val;
54386 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54387 this.syncRowHeights(rowIndex, rowIndex);
54390 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54392 if(this.grid.autoSizeHeaders){
54393 var h = this.getHeaderCellMeasure(colIndex);
54394 maxWidth = Math.max(maxWidth, h.scrollWidth);
54397 if(this.cm.isLocked(colIndex)){
54398 tb = this.getLockedTable();
54401 tb = this.getBodyTable();
54402 index = colIndex - this.cm.getLockedCount();
54405 var rows = tb.rows;
54406 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54407 for(var i = 0; i < stopIndex; i++){
54408 var cell = rows[i].childNodes[index].firstChild;
54409 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54412 return maxWidth + /*margin for error in IE*/ 5;
54415 * Autofit a column to its content.
54416 * @param {Number} colIndex
54417 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54419 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54420 if(this.cm.isHidden(colIndex)){
54421 return; // can't calc a hidden column
54424 var cid = this.cm.getColumnId(colIndex);
54425 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54426 if(this.grid.autoSizeHeaders){
54427 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54430 var newWidth = this.calcColumnWidth(colIndex);
54431 this.cm.setColumnWidth(colIndex,
54432 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54433 if(!suppressEvent){
54434 this.grid.fireEvent("columnresize", colIndex, newWidth);
54439 * Autofits all columns to their content and then expands to fit any extra space in the grid
54441 autoSizeColumns : function(){
54442 var cm = this.grid.colModel;
54443 var colCount = cm.getColumnCount();
54444 for(var i = 0; i < colCount; i++){
54445 this.autoSizeColumn(i, true, true);
54447 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54450 this.updateColumns();
54456 * Autofits all columns to the grid's width proportionate with their current size
54457 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54459 fitColumns : function(reserveScrollSpace){
54460 var cm = this.grid.colModel;
54461 var colCount = cm.getColumnCount();
54465 for (i = 0; i < colCount; i++){
54466 if(!cm.isHidden(i) && !cm.isFixed(i)){
54467 w = cm.getColumnWidth(i);
54473 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54474 if(reserveScrollSpace){
54477 var frac = (avail - cm.getTotalWidth())/width;
54478 while (cols.length){
54481 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54483 this.updateColumns();
54487 onRowSelect : function(rowIndex){
54488 var row = this.getRowComposite(rowIndex);
54489 row.addClass("x-grid-row-selected");
54492 onRowDeselect : function(rowIndex){
54493 var row = this.getRowComposite(rowIndex);
54494 row.removeClass("x-grid-row-selected");
54497 onCellSelect : function(row, col){
54498 var cell = this.getCell(row, col);
54500 Roo.fly(cell).addClass("x-grid-cell-selected");
54504 onCellDeselect : function(row, col){
54505 var cell = this.getCell(row, col);
54507 Roo.fly(cell).removeClass("x-grid-cell-selected");
54511 updateHeaderSortState : function(){
54513 // sort state can be single { field: xxx, direction : yyy}
54514 // or { xxx=>ASC , yyy : DESC ..... }
54517 if (!this.ds.multiSort) {
54518 var state = this.ds.getSortState();
54522 mstate[state.field] = state.direction;
54523 // FIXME... - this is not used here.. but might be elsewhere..
54524 this.sortState = state;
54527 mstate = this.ds.sortToggle;
54529 //remove existing sort classes..
54531 var sc = this.sortClasses;
54532 var hds = this.el.select(this.headerSelector).removeClass(sc);
54534 for(var f in mstate) {
54536 var sortColumn = this.cm.findColumnIndex(f);
54538 if(sortColumn != -1){
54539 var sortDir = mstate[f];
54540 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54549 handleHeaderClick : function(g, index,e){
54551 Roo.log("header click");
54554 // touch events on header are handled by context
54555 this.handleHdCtx(g,index,e);
54560 if(this.headersDisabled){
54563 var dm = g.dataSource, cm = g.colModel;
54564 if(!cm.isSortable(index)){
54569 if (dm.multiSort) {
54570 // update the sortOrder
54572 for(var i = 0; i < cm.config.length; i++ ) {
54574 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54575 continue; // dont' bother, it's not in sort list or being set.
54578 so.push(cm.config[i].dataIndex);
54584 dm.sort(cm.getDataIndex(index));
54588 destroy : function(){
54590 this.colMenu.removeAll();
54591 Roo.menu.MenuMgr.unregister(this.colMenu);
54592 this.colMenu.getEl().remove();
54593 delete this.colMenu;
54596 this.hmenu.removeAll();
54597 Roo.menu.MenuMgr.unregister(this.hmenu);
54598 this.hmenu.getEl().remove();
54601 if(this.grid.enableColumnMove){
54602 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54604 for(var dd in dds){
54605 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54606 var elid = dds[dd].dragElId;
54608 Roo.get(elid).remove();
54609 } else if(dds[dd].config.isTarget){
54610 dds[dd].proxyTop.remove();
54611 dds[dd].proxyBottom.remove();
54614 if(Roo.dd.DDM.locationCache[dd]){
54615 delete Roo.dd.DDM.locationCache[dd];
54618 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54621 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54622 this.bind(null, null);
54623 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54626 handleLockChange : function(){
54627 this.refresh(true);
54630 onDenyColumnLock : function(){
54634 onDenyColumnHide : function(){
54638 handleHdMenuClick : function(item){
54639 var index = this.hdCtxIndex;
54640 var cm = this.cm, ds = this.ds;
54643 ds.sort(cm.getDataIndex(index), "ASC");
54646 ds.sort(cm.getDataIndex(index), "DESC");
54649 var lc = cm.getLockedCount();
54650 if(cm.getColumnCount(true) <= lc+1){
54651 this.onDenyColumnLock();
54655 cm.setLocked(index, true, true);
54656 cm.moveColumn(index, lc);
54657 this.grid.fireEvent("columnmove", index, lc);
54659 cm.setLocked(index, true);
54663 var lc = cm.getLockedCount();
54664 if((lc-1) != index){
54665 cm.setLocked(index, false, true);
54666 cm.moveColumn(index, lc-1);
54667 this.grid.fireEvent("columnmove", index, lc-1);
54669 cm.setLocked(index, false);
54672 case 'wider': // used to expand cols on touch..
54674 var cw = cm.getColumnWidth(index);
54675 cw += (item.id == 'wider' ? 1 : -1) * 50;
54676 cw = Math.max(0, cw);
54677 cw = Math.min(cw,4000);
54678 cm.setColumnWidth(index, cw);
54682 index = cm.getIndexById(item.id.substr(4));
54684 if(item.checked && cm.getColumnCount(true) <= 1){
54685 this.onDenyColumnHide();
54688 cm.setHidden(index, item.checked);
54694 beforeColMenuShow : function(){
54695 var cm = this.cm, colCount = cm.getColumnCount();
54696 this.colMenu.removeAll();
54697 for(var i = 0; i < colCount; i++){
54698 this.colMenu.add(new Roo.menu.CheckItem({
54699 id: "col-"+cm.getColumnId(i),
54700 text: cm.getColumnHeader(i),
54701 checked: !cm.isHidden(i),
54707 handleHdCtx : function(g, index, e){
54709 var hd = this.getHeaderCell(index);
54710 this.hdCtxIndex = index;
54711 var ms = this.hmenu.items, cm = this.cm;
54712 ms.get("asc").setDisabled(!cm.isSortable(index));
54713 ms.get("desc").setDisabled(!cm.isSortable(index));
54714 if(this.grid.enableColLock !== false){
54715 ms.get("lock").setDisabled(cm.isLocked(index));
54716 ms.get("unlock").setDisabled(!cm.isLocked(index));
54718 this.hmenu.show(hd, "tl-bl");
54721 handleHdOver : function(e){
54722 var hd = this.findHeaderCell(e.getTarget());
54723 if(hd && !this.headersDisabled){
54724 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54725 this.fly(hd).addClass("x-grid-hd-over");
54730 handleHdOut : function(e){
54731 var hd = this.findHeaderCell(e.getTarget());
54733 this.fly(hd).removeClass("x-grid-hd-over");
54737 handleSplitDblClick : function(e, t){
54738 var i = this.getCellIndex(t);
54739 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54740 this.autoSizeColumn(i, true);
54745 render : function(){
54748 var colCount = cm.getColumnCount();
54750 if(this.grid.monitorWindowResize === true){
54751 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54753 var header = this.renderHeaders();
54754 var body = this.templates.body.apply({rows:""});
54755 var html = this.templates.master.apply({
54758 lockedHeader: header[0],
54762 //this.updateColumns();
54764 this.grid.getGridEl().dom.innerHTML = html;
54766 this.initElements();
54768 // a kludge to fix the random scolling effect in webkit
54769 this.el.on("scroll", function() {
54770 this.el.dom.scrollTop=0; // hopefully not recursive..
54773 this.scroller.on("scroll", this.handleScroll, this);
54774 this.lockedBody.on("mousewheel", this.handleWheel, this);
54775 this.mainBody.on("mousewheel", this.handleWheel, this);
54777 this.mainHd.on("mouseover", this.handleHdOver, this);
54778 this.mainHd.on("mouseout", this.handleHdOut, this);
54779 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54780 {delegate: "."+this.splitClass});
54782 this.lockedHd.on("mouseover", this.handleHdOver, this);
54783 this.lockedHd.on("mouseout", this.handleHdOut, this);
54784 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54785 {delegate: "."+this.splitClass});
54787 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54788 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54791 this.updateSplitters();
54793 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54794 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54795 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54798 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54799 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54801 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54802 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54804 if(this.grid.enableColLock !== false){
54805 this.hmenu.add('-',
54806 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54807 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54811 this.hmenu.add('-',
54812 {id:"wider", text: this.columnsWiderText},
54813 {id:"narrow", text: this.columnsNarrowText }
54819 if(this.grid.enableColumnHide !== false){
54821 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54822 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54823 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54825 this.hmenu.add('-',
54826 {id:"columns", text: this.columnsText, menu: this.colMenu}
54829 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54831 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54834 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54835 this.dd = new Roo.grid.GridDragZone(this.grid, {
54836 ddGroup : this.grid.ddGroup || 'GridDD'
54842 for(var i = 0; i < colCount; i++){
54843 if(cm.isHidden(i)){
54844 this.hideColumn(i);
54846 if(cm.config[i].align){
54847 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54848 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54852 this.updateHeaderSortState();
54854 this.beforeInitialResize();
54857 // two part rendering gives faster view to the user
54858 this.renderPhase2.defer(1, this);
54861 renderPhase2 : function(){
54862 // render the rows now
54864 if(this.grid.autoSizeColumns){
54865 this.autoSizeColumns();
54869 beforeInitialResize : function(){
54873 onColumnSplitterMoved : function(i, w){
54874 this.userResized = true;
54875 var cm = this.grid.colModel;
54876 cm.setColumnWidth(i, w, true);
54877 var cid = cm.getColumnId(i);
54878 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54879 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54880 this.updateSplitters();
54882 this.grid.fireEvent("columnresize", i, w);
54885 syncRowHeights : function(startIndex, endIndex){
54886 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54887 startIndex = startIndex || 0;
54888 var mrows = this.getBodyTable().rows;
54889 var lrows = this.getLockedTable().rows;
54890 var len = mrows.length-1;
54891 endIndex = Math.min(endIndex || len, len);
54892 for(var i = startIndex; i <= endIndex; i++){
54893 var m = mrows[i], l = lrows[i];
54894 var h = Math.max(m.offsetHeight, l.offsetHeight);
54895 m.style.height = l.style.height = h + "px";
54900 layout : function(initialRender, is2ndPass){
54902 var auto = g.autoHeight;
54903 var scrollOffset = 16;
54904 var c = g.getGridEl(), cm = this.cm,
54905 expandCol = g.autoExpandColumn,
54907 //c.beginMeasure();
54909 if(!c.dom.offsetWidth){ // display:none?
54911 this.lockedWrap.show();
54912 this.mainWrap.show();
54917 var hasLock = this.cm.isLocked(0);
54919 var tbh = this.headerPanel.getHeight();
54920 var bbh = this.footerPanel.getHeight();
54923 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54924 var newHeight = ch + c.getBorderWidth("tb");
54926 newHeight = Math.min(g.maxHeight, newHeight);
54928 c.setHeight(newHeight);
54932 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54935 var s = this.scroller;
54937 var csize = c.getSize(true);
54939 this.el.setSize(csize.width, csize.height);
54941 this.headerPanel.setWidth(csize.width);
54942 this.footerPanel.setWidth(csize.width);
54944 var hdHeight = this.mainHd.getHeight();
54945 var vw = csize.width;
54946 var vh = csize.height - (tbh + bbh);
54950 var bt = this.getBodyTable();
54951 var ltWidth = hasLock ?
54952 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54954 var scrollHeight = bt.offsetHeight;
54955 var scrollWidth = ltWidth + bt.offsetWidth;
54956 var vscroll = false, hscroll = false;
54958 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54960 var lw = this.lockedWrap, mw = this.mainWrap;
54961 var lb = this.lockedBody, mb = this.mainBody;
54963 setTimeout(function(){
54964 var t = s.dom.offsetTop;
54965 var w = s.dom.clientWidth,
54966 h = s.dom.clientHeight;
54969 lw.setSize(ltWidth, h);
54971 mw.setLeftTop(ltWidth, t);
54972 mw.setSize(w-ltWidth, h);
54974 lb.setHeight(h-hdHeight);
54975 mb.setHeight(h-hdHeight);
54977 if(is2ndPass !== true && !gv.userResized && expandCol){
54978 // high speed resize without full column calculation
54980 var ci = cm.getIndexById(expandCol);
54982 ci = cm.findColumnIndex(expandCol);
54984 ci = Math.max(0, ci); // make sure it's got at least the first col.
54985 var expandId = cm.getColumnId(ci);
54986 var tw = cm.getTotalWidth(false);
54987 var currentWidth = cm.getColumnWidth(ci);
54988 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54989 if(currentWidth != cw){
54990 cm.setColumnWidth(ci, cw, true);
54991 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54992 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54993 gv.updateSplitters();
54994 gv.layout(false, true);
55006 onWindowResize : function(){
55007 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
55013 appendFooter : function(parentEl){
55017 sortAscText : "Sort Ascending",
55018 sortDescText : "Sort Descending",
55019 lockText : "Lock Column",
55020 unlockText : "Unlock Column",
55021 columnsText : "Columns",
55023 columnsWiderText : "Wider",
55024 columnsNarrowText : "Thinner"
55028 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
55029 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
55030 this.proxy.el.addClass('x-grid3-col-dd');
55033 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
55034 handleMouseDown : function(e){
55038 callHandleMouseDown : function(e){
55039 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
55044 * Ext JS Library 1.1.1
55045 * Copyright(c) 2006-2007, Ext JS, LLC.
55047 * Originally Released Under LGPL - original licence link has changed is not relivant.
55050 * <script type="text/javascript">
55054 // This is a support class used internally by the Grid components
55055 Roo.grid.SplitDragZone = function(grid, hd, hd2){
55057 this.view = grid.getView();
55058 this.proxy = this.view.resizeProxy;
55059 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
55060 "gridSplitters" + this.grid.getGridEl().id, {
55061 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
55063 this.setHandleElId(Roo.id(hd));
55064 this.setOuterHandleElId(Roo.id(hd2));
55065 this.scroll = false;
55067 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
55068 fly: Roo.Element.fly,
55070 b4StartDrag : function(x, y){
55071 this.view.headersDisabled = true;
55072 this.proxy.setHeight(this.view.mainWrap.getHeight());
55073 var w = this.cm.getColumnWidth(this.cellIndex);
55074 var minw = Math.max(w-this.grid.minColumnWidth, 0);
55075 this.resetConstraints();
55076 this.setXConstraint(minw, 1000);
55077 this.setYConstraint(0, 0);
55078 this.minX = x - minw;
55079 this.maxX = x + 1000;
55081 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55085 handleMouseDown : function(e){
55086 ev = Roo.EventObject.setEvent(e);
55087 var t = this.fly(ev.getTarget());
55088 if(t.hasClass("x-grid-split")){
55089 this.cellIndex = this.view.getCellIndex(t.dom);
55090 this.split = t.dom;
55091 this.cm = this.grid.colModel;
55092 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55093 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55098 endDrag : function(e){
55099 this.view.headersDisabled = false;
55100 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55101 var diff = endX - this.startPos;
55102 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55105 autoOffset : function(){
55106 this.setDelta(0,0);
55110 * Ext JS Library 1.1.1
55111 * Copyright(c) 2006-2007, Ext JS, LLC.
55113 * Originally Released Under LGPL - original licence link has changed is not relivant.
55116 * <script type="text/javascript">
55120 // This is a support class used internally by the Grid components
55121 Roo.grid.GridDragZone = function(grid, config){
55122 this.view = grid.getView();
55123 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55124 if(this.view.lockedBody){
55125 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55126 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55128 this.scroll = false;
55130 this.ddel = document.createElement('div');
55131 this.ddel.className = 'x-grid-dd-wrap';
55134 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55135 ddGroup : "GridDD",
55137 getDragData : function(e){
55138 var t = Roo.lib.Event.getTarget(e);
55139 var rowIndex = this.view.findRowIndex(t);
55140 var sm = this.grid.selModel;
55142 //Roo.log(rowIndex);
55144 if (sm.getSelectedCell) {
55145 // cell selection..
55146 if (!sm.getSelectedCell()) {
55149 if (rowIndex != sm.getSelectedCell()[0]) {
55155 if(rowIndex !== false){
55160 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55162 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55165 if (e.hasModifier()){
55166 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55169 Roo.log("getDragData");
55174 rowIndex: rowIndex,
55175 selections:sm.getSelections ? sm.getSelections() : (
55176 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55183 onInitDrag : function(e){
55184 var data = this.dragData;
55185 this.ddel.innerHTML = this.grid.getDragDropText();
55186 this.proxy.update(this.ddel);
55187 // fire start drag?
55190 afterRepair : function(){
55191 this.dragging = false;
55194 getRepairXY : function(e, data){
55198 onEndDrag : function(data, e){
55202 onValidDrop : function(dd, e, id){
55207 beforeInvalidDrop : function(e, id){
55212 * Ext JS Library 1.1.1
55213 * Copyright(c) 2006-2007, Ext JS, LLC.
55215 * Originally Released Under LGPL - original licence link has changed is not relivant.
55218 * <script type="text/javascript">
55223 * @class Roo.grid.ColumnModel
55224 * @extends Roo.util.Observable
55225 * This is the default implementation of a ColumnModel used by the Grid. It defines
55226 * the columns in the grid.
55229 var colModel = new Roo.grid.ColumnModel([
55230 {header: "Ticker", width: 60, sortable: true, locked: true},
55231 {header: "Company Name", width: 150, sortable: true},
55232 {header: "Market Cap.", width: 100, sortable: true},
55233 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55234 {header: "Employees", width: 100, sortable: true, resizable: false}
55239 * The config options listed for this class are options which may appear in each
55240 * individual column definition.
55241 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55243 * @param {Object} config An Array of column config objects. See this class's
55244 * config objects for details.
55246 Roo.grid.ColumnModel = function(config){
55248 * The config passed into the constructor
55250 this.config = config;
55253 // if no id, create one
55254 // if the column does not have a dataIndex mapping,
55255 // map it to the order it is in the config
55256 for(var i = 0, len = config.length; i < len; i++){
55258 if(typeof c.dataIndex == "undefined"){
55261 if(typeof c.renderer == "string"){
55262 c.renderer = Roo.util.Format[c.renderer];
55264 if(typeof c.id == "undefined"){
55267 if(c.editor && c.editor.xtype){
55268 c.editor = Roo.factory(c.editor, Roo.grid);
55270 if(c.editor && c.editor.isFormField){
55271 c.editor = new Roo.grid.GridEditor(c.editor);
55273 this.lookup[c.id] = c;
55277 * The width of columns which have no width specified (defaults to 100)
55280 this.defaultWidth = 100;
55283 * Default sortable of columns which have no sortable specified (defaults to false)
55286 this.defaultSortable = false;
55290 * @event widthchange
55291 * Fires when the width of a column changes.
55292 * @param {ColumnModel} this
55293 * @param {Number} columnIndex The column index
55294 * @param {Number} newWidth The new width
55296 "widthchange": true,
55298 * @event headerchange
55299 * Fires when the text of a header changes.
55300 * @param {ColumnModel} this
55301 * @param {Number} columnIndex The column index
55302 * @param {Number} newText The new header text
55304 "headerchange": true,
55306 * @event hiddenchange
55307 * Fires when a column is hidden or "unhidden".
55308 * @param {ColumnModel} this
55309 * @param {Number} columnIndex The column index
55310 * @param {Boolean} hidden true if hidden, false otherwise
55312 "hiddenchange": true,
55314 * @event columnmoved
55315 * Fires when a column is moved.
55316 * @param {ColumnModel} this
55317 * @param {Number} oldIndex
55318 * @param {Number} newIndex
55320 "columnmoved" : true,
55322 * @event columlockchange
55323 * Fires when a column's locked state is changed
55324 * @param {ColumnModel} this
55325 * @param {Number} colIndex
55326 * @param {Boolean} locked true if locked
55328 "columnlockchange" : true
55330 Roo.grid.ColumnModel.superclass.constructor.call(this);
55332 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55334 * @cfg {String} header The header text to display in the Grid view.
55337 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55338 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55339 * specified, the column's index is used as an index into the Record's data Array.
55342 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55343 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55346 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55347 * Defaults to the value of the {@link #defaultSortable} property.
55348 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55351 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55354 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55357 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55360 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55363 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55364 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55365 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55366 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55369 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55372 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55375 * @cfg {String} cursor (Optional)
55378 * @cfg {String} tooltip (Optional)
55381 * Returns the id of the column at the specified index.
55382 * @param {Number} index The column index
55383 * @return {String} the id
55385 getColumnId : function(index){
55386 return this.config[index].id;
55390 * Returns the column for a specified id.
55391 * @param {String} id The column id
55392 * @return {Object} the column
55394 getColumnById : function(id){
55395 return this.lookup[id];
55400 * Returns the column for a specified dataIndex.
55401 * @param {String} dataIndex The column dataIndex
55402 * @return {Object|Boolean} the column or false if not found
55404 getColumnByDataIndex: function(dataIndex){
55405 var index = this.findColumnIndex(dataIndex);
55406 return index > -1 ? this.config[index] : false;
55410 * Returns the index for a specified column id.
55411 * @param {String} id The column id
55412 * @return {Number} the index, or -1 if not found
55414 getIndexById : function(id){
55415 for(var i = 0, len = this.config.length; i < len; i++){
55416 if(this.config[i].id == id){
55424 * Returns the index for a specified column dataIndex.
55425 * @param {String} dataIndex The column dataIndex
55426 * @return {Number} the index, or -1 if not found
55429 findColumnIndex : function(dataIndex){
55430 for(var i = 0, len = this.config.length; i < len; i++){
55431 if(this.config[i].dataIndex == dataIndex){
55439 moveColumn : function(oldIndex, newIndex){
55440 var c = this.config[oldIndex];
55441 this.config.splice(oldIndex, 1);
55442 this.config.splice(newIndex, 0, c);
55443 this.dataMap = null;
55444 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55447 isLocked : function(colIndex){
55448 return this.config[colIndex].locked === true;
55451 setLocked : function(colIndex, value, suppressEvent){
55452 if(this.isLocked(colIndex) == value){
55455 this.config[colIndex].locked = value;
55456 if(!suppressEvent){
55457 this.fireEvent("columnlockchange", this, colIndex, value);
55461 getTotalLockedWidth : function(){
55462 var totalWidth = 0;
55463 for(var i = 0; i < this.config.length; i++){
55464 if(this.isLocked(i) && !this.isHidden(i)){
55465 this.totalWidth += this.getColumnWidth(i);
55471 getLockedCount : function(){
55472 for(var i = 0, len = this.config.length; i < len; i++){
55473 if(!this.isLocked(i)){
55480 * Returns the number of columns.
55483 getColumnCount : function(visibleOnly){
55484 if(visibleOnly === true){
55486 for(var i = 0, len = this.config.length; i < len; i++){
55487 if(!this.isHidden(i)){
55493 return this.config.length;
55497 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55498 * @param {Function} fn
55499 * @param {Object} scope (optional)
55500 * @return {Array} result
55502 getColumnsBy : function(fn, scope){
55504 for(var i = 0, len = this.config.length; i < len; i++){
55505 var c = this.config[i];
55506 if(fn.call(scope||this, c, i) === true){
55514 * Returns true if the specified column is sortable.
55515 * @param {Number} col The column index
55516 * @return {Boolean}
55518 isSortable : function(col){
55519 if(typeof this.config[col].sortable == "undefined"){
55520 return this.defaultSortable;
55522 return this.config[col].sortable;
55526 * Returns the rendering (formatting) function defined for the column.
55527 * @param {Number} col The column index.
55528 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55530 getRenderer : function(col){
55531 if(!this.config[col].renderer){
55532 return Roo.grid.ColumnModel.defaultRenderer;
55534 return this.config[col].renderer;
55538 * Sets the rendering (formatting) function for a column.
55539 * @param {Number} col The column index
55540 * @param {Function} fn The function to use to process the cell's raw data
55541 * to return HTML markup for the grid view. The render function is called with
55542 * the following parameters:<ul>
55543 * <li>Data value.</li>
55544 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55545 * <li>css A CSS style string to apply to the table cell.</li>
55546 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55547 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55548 * <li>Row index</li>
55549 * <li>Column index</li>
55550 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55552 setRenderer : function(col, fn){
55553 this.config[col].renderer = fn;
55557 * Returns the width for the specified column.
55558 * @param {Number} col The column index
55561 getColumnWidth : function(col){
55562 return this.config[col].width * 1 || this.defaultWidth;
55566 * Sets the width for a column.
55567 * @param {Number} col The column index
55568 * @param {Number} width The new width
55570 setColumnWidth : function(col, width, suppressEvent){
55571 this.config[col].width = width;
55572 this.totalWidth = null;
55573 if(!suppressEvent){
55574 this.fireEvent("widthchange", this, col, width);
55579 * Returns the total width of all columns.
55580 * @param {Boolean} includeHidden True to include hidden column widths
55583 getTotalWidth : function(includeHidden){
55584 if(!this.totalWidth){
55585 this.totalWidth = 0;
55586 for(var i = 0, len = this.config.length; i < len; i++){
55587 if(includeHidden || !this.isHidden(i)){
55588 this.totalWidth += this.getColumnWidth(i);
55592 return this.totalWidth;
55596 * Returns the header for the specified column.
55597 * @param {Number} col The column index
55600 getColumnHeader : function(col){
55601 return this.config[col].header;
55605 * Sets the header for a column.
55606 * @param {Number} col The column index
55607 * @param {String} header The new header
55609 setColumnHeader : function(col, header){
55610 this.config[col].header = header;
55611 this.fireEvent("headerchange", this, col, header);
55615 * Returns the tooltip for the specified column.
55616 * @param {Number} col The column index
55619 getColumnTooltip : function(col){
55620 return this.config[col].tooltip;
55623 * Sets the tooltip for a column.
55624 * @param {Number} col The column index
55625 * @param {String} tooltip The new tooltip
55627 setColumnTooltip : function(col, tooltip){
55628 this.config[col].tooltip = tooltip;
55632 * Returns the dataIndex for the specified column.
55633 * @param {Number} col The column index
55636 getDataIndex : function(col){
55637 return this.config[col].dataIndex;
55641 * Sets the dataIndex for a column.
55642 * @param {Number} col The column index
55643 * @param {Number} dataIndex The new dataIndex
55645 setDataIndex : function(col, dataIndex){
55646 this.config[col].dataIndex = dataIndex;
55652 * Returns true if the cell is editable.
55653 * @param {Number} colIndex The column index
55654 * @param {Number} rowIndex The row index
55655 * @return {Boolean}
55657 isCellEditable : function(colIndex, rowIndex){
55658 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55662 * Returns the editor defined for the cell/column.
55663 * return false or null to disable editing.
55664 * @param {Number} colIndex The column index
55665 * @param {Number} rowIndex The row index
55668 getCellEditor : function(colIndex, rowIndex){
55669 return this.config[colIndex].editor;
55673 * Sets if a column is editable.
55674 * @param {Number} col The column index
55675 * @param {Boolean} editable True if the column is editable
55677 setEditable : function(col, editable){
55678 this.config[col].editable = editable;
55683 * Returns true if the column is hidden.
55684 * @param {Number} colIndex The column index
55685 * @return {Boolean}
55687 isHidden : function(colIndex){
55688 return this.config[colIndex].hidden;
55693 * Returns true if the column width cannot be changed
55695 isFixed : function(colIndex){
55696 return this.config[colIndex].fixed;
55700 * Returns true if the column can be resized
55701 * @return {Boolean}
55703 isResizable : function(colIndex){
55704 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55707 * Sets if a column is hidden.
55708 * @param {Number} colIndex The column index
55709 * @param {Boolean} hidden True if the column is hidden
55711 setHidden : function(colIndex, hidden){
55712 this.config[colIndex].hidden = hidden;
55713 this.totalWidth = null;
55714 this.fireEvent("hiddenchange", this, colIndex, hidden);
55718 * Sets the editor for a column.
55719 * @param {Number} col The column index
55720 * @param {Object} editor The editor object
55722 setEditor : function(col, editor){
55723 this.config[col].editor = editor;
55727 Roo.grid.ColumnModel.defaultRenderer = function(value){
55728 if(typeof value == "string" && value.length < 1){
55734 // Alias for backwards compatibility
55735 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55738 * Ext JS Library 1.1.1
55739 * Copyright(c) 2006-2007, Ext JS, LLC.
55741 * Originally Released Under LGPL - original licence link has changed is not relivant.
55744 * <script type="text/javascript">
55748 * @class Roo.grid.AbstractSelectionModel
55749 * @extends Roo.util.Observable
55750 * Abstract base class for grid SelectionModels. It provides the interface that should be
55751 * implemented by descendant classes. This class should not be directly instantiated.
55754 Roo.grid.AbstractSelectionModel = function(){
55755 this.locked = false;
55756 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55759 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55760 /** @ignore Called by the grid automatically. Do not call directly. */
55761 init : function(grid){
55767 * Locks the selections.
55770 this.locked = true;
55774 * Unlocks the selections.
55776 unlock : function(){
55777 this.locked = false;
55781 * Returns true if the selections are locked.
55782 * @return {Boolean}
55784 isLocked : function(){
55785 return this.locked;
55789 * Ext JS Library 1.1.1
55790 * Copyright(c) 2006-2007, Ext JS, LLC.
55792 * Originally Released Under LGPL - original licence link has changed is not relivant.
55795 * <script type="text/javascript">
55798 * @extends Roo.grid.AbstractSelectionModel
55799 * @class Roo.grid.RowSelectionModel
55800 * The default SelectionModel used by {@link Roo.grid.Grid}.
55801 * It supports multiple selections and keyboard selection/navigation.
55803 * @param {Object} config
55805 Roo.grid.RowSelectionModel = function(config){
55806 Roo.apply(this, config);
55807 this.selections = new Roo.util.MixedCollection(false, function(o){
55812 this.lastActive = false;
55816 * @event selectionchange
55817 * Fires when the selection changes
55818 * @param {SelectionModel} this
55820 "selectionchange" : true,
55822 * @event afterselectionchange
55823 * Fires after the selection changes (eg. by key press or clicking)
55824 * @param {SelectionModel} this
55826 "afterselectionchange" : true,
55828 * @event beforerowselect
55829 * Fires when a row is selected being selected, return false to cancel.
55830 * @param {SelectionModel} this
55831 * @param {Number} rowIndex The selected index
55832 * @param {Boolean} keepExisting False if other selections will be cleared
55834 "beforerowselect" : true,
55837 * Fires when a row is selected.
55838 * @param {SelectionModel} this
55839 * @param {Number} rowIndex The selected index
55840 * @param {Roo.data.Record} r The record
55842 "rowselect" : true,
55844 * @event rowdeselect
55845 * Fires when a row is deselected.
55846 * @param {SelectionModel} this
55847 * @param {Number} rowIndex The selected index
55849 "rowdeselect" : true
55851 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55852 this.locked = false;
55855 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55857 * @cfg {Boolean} singleSelect
55858 * True to allow selection of only one row at a time (defaults to false)
55860 singleSelect : false,
55863 initEvents : function(){
55865 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55866 this.grid.on("mousedown", this.handleMouseDown, this);
55867 }else{ // allow click to work like normal
55868 this.grid.on("rowclick", this.handleDragableRowClick, this);
55871 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55872 "up" : function(e){
55874 this.selectPrevious(e.shiftKey);
55875 }else if(this.last !== false && this.lastActive !== false){
55876 var last = this.last;
55877 this.selectRange(this.last, this.lastActive-1);
55878 this.grid.getView().focusRow(this.lastActive);
55879 if(last !== false){
55883 this.selectFirstRow();
55885 this.fireEvent("afterselectionchange", this);
55887 "down" : function(e){
55889 this.selectNext(e.shiftKey);
55890 }else if(this.last !== false && this.lastActive !== false){
55891 var last = this.last;
55892 this.selectRange(this.last, this.lastActive+1);
55893 this.grid.getView().focusRow(this.lastActive);
55894 if(last !== false){
55898 this.selectFirstRow();
55900 this.fireEvent("afterselectionchange", this);
55905 var view = this.grid.view;
55906 view.on("refresh", this.onRefresh, this);
55907 view.on("rowupdated", this.onRowUpdated, this);
55908 view.on("rowremoved", this.onRemove, this);
55912 onRefresh : function(){
55913 var ds = this.grid.dataSource, i, v = this.grid.view;
55914 var s = this.selections;
55915 s.each(function(r){
55916 if((i = ds.indexOfId(r.id)) != -1){
55925 onRemove : function(v, index, r){
55926 this.selections.remove(r);
55930 onRowUpdated : function(v, index, r){
55931 if(this.isSelected(r)){
55932 v.onRowSelect(index);
55938 * @param {Array} records The records to select
55939 * @param {Boolean} keepExisting (optional) True to keep existing selections
55941 selectRecords : function(records, keepExisting){
55943 this.clearSelections();
55945 var ds = this.grid.dataSource;
55946 for(var i = 0, len = records.length; i < len; i++){
55947 this.selectRow(ds.indexOf(records[i]), true);
55952 * Gets the number of selected rows.
55955 getCount : function(){
55956 return this.selections.length;
55960 * Selects the first row in the grid.
55962 selectFirstRow : function(){
55967 * Select the last row.
55968 * @param {Boolean} keepExisting (optional) True to keep existing selections
55970 selectLastRow : function(keepExisting){
55971 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55975 * Selects the row immediately following the last selected row.
55976 * @param {Boolean} keepExisting (optional) True to keep existing selections
55978 selectNext : function(keepExisting){
55979 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55980 this.selectRow(this.last+1, keepExisting);
55981 this.grid.getView().focusRow(this.last);
55986 * Selects the row that precedes the last selected row.
55987 * @param {Boolean} keepExisting (optional) True to keep existing selections
55989 selectPrevious : function(keepExisting){
55991 this.selectRow(this.last-1, keepExisting);
55992 this.grid.getView().focusRow(this.last);
55997 * Returns the selected records
55998 * @return {Array} Array of selected records
56000 getSelections : function(){
56001 return [].concat(this.selections.items);
56005 * Returns the first selected record.
56008 getSelected : function(){
56009 return this.selections.itemAt(0);
56014 * Clears all selections.
56016 clearSelections : function(fast){
56017 if(this.locked) return;
56019 var ds = this.grid.dataSource;
56020 var s = this.selections;
56021 s.each(function(r){
56022 this.deselectRow(ds.indexOfId(r.id));
56026 this.selections.clear();
56033 * Selects all rows.
56035 selectAll : function(){
56036 if(this.locked) return;
56037 this.selections.clear();
56038 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
56039 this.selectRow(i, true);
56044 * Returns True if there is a selection.
56045 * @return {Boolean}
56047 hasSelection : function(){
56048 return this.selections.length > 0;
56052 * Returns True if the specified row is selected.
56053 * @param {Number/Record} record The record or index of the record to check
56054 * @return {Boolean}
56056 isSelected : function(index){
56057 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
56058 return (r && this.selections.key(r.id) ? true : false);
56062 * Returns True if the specified record id is selected.
56063 * @param {String} id The id of record to check
56064 * @return {Boolean}
56066 isIdSelected : function(id){
56067 return (this.selections.key(id) ? true : false);
56071 handleMouseDown : function(e, t){
56072 var view = this.grid.getView(), rowIndex;
56073 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
56076 if(e.shiftKey && this.last !== false){
56077 var last = this.last;
56078 this.selectRange(last, rowIndex, e.ctrlKey);
56079 this.last = last; // reset the last
56080 view.focusRow(rowIndex);
56082 var isSelected = this.isSelected(rowIndex);
56083 if(e.button !== 0 && isSelected){
56084 view.focusRow(rowIndex);
56085 }else if(e.ctrlKey && isSelected){
56086 this.deselectRow(rowIndex);
56087 }else if(!isSelected){
56088 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56089 view.focusRow(rowIndex);
56092 this.fireEvent("afterselectionchange", this);
56095 handleDragableRowClick : function(grid, rowIndex, e)
56097 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56098 this.selectRow(rowIndex, false);
56099 grid.view.focusRow(rowIndex);
56100 this.fireEvent("afterselectionchange", this);
56105 * Selects multiple rows.
56106 * @param {Array} rows Array of the indexes of the row to select
56107 * @param {Boolean} keepExisting (optional) True to keep existing selections
56109 selectRows : function(rows, keepExisting){
56111 this.clearSelections();
56113 for(var i = 0, len = rows.length; i < len; i++){
56114 this.selectRow(rows[i], true);
56119 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56120 * @param {Number} startRow The index of the first row in the range
56121 * @param {Number} endRow The index of the last row in the range
56122 * @param {Boolean} keepExisting (optional) True to retain existing selections
56124 selectRange : function(startRow, endRow, keepExisting){
56125 if(this.locked) return;
56127 this.clearSelections();
56129 if(startRow <= endRow){
56130 for(var i = startRow; i <= endRow; i++){
56131 this.selectRow(i, true);
56134 for(var i = startRow; i >= endRow; i--){
56135 this.selectRow(i, true);
56141 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56142 * @param {Number} startRow The index of the first row in the range
56143 * @param {Number} endRow The index of the last row in the range
56145 deselectRange : function(startRow, endRow, preventViewNotify){
56146 if(this.locked) return;
56147 for(var i = startRow; i <= endRow; i++){
56148 this.deselectRow(i, preventViewNotify);
56154 * @param {Number} row The index of the row to select
56155 * @param {Boolean} keepExisting (optional) True to keep existing selections
56157 selectRow : function(index, keepExisting, preventViewNotify){
56158 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56159 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56160 if(!keepExisting || this.singleSelect){
56161 this.clearSelections();
56163 var r = this.grid.dataSource.getAt(index);
56164 this.selections.add(r);
56165 this.last = this.lastActive = index;
56166 if(!preventViewNotify){
56167 this.grid.getView().onRowSelect(index);
56169 this.fireEvent("rowselect", this, index, r);
56170 this.fireEvent("selectionchange", this);
56176 * @param {Number} row The index of the row to deselect
56178 deselectRow : function(index, preventViewNotify){
56179 if(this.locked) return;
56180 if(this.last == index){
56183 if(this.lastActive == index){
56184 this.lastActive = false;
56186 var r = this.grid.dataSource.getAt(index);
56187 this.selections.remove(r);
56188 if(!preventViewNotify){
56189 this.grid.getView().onRowDeselect(index);
56191 this.fireEvent("rowdeselect", this, index);
56192 this.fireEvent("selectionchange", this);
56196 restoreLast : function(){
56198 this.last = this._last;
56203 acceptsNav : function(row, col, cm){
56204 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56208 onEditorKey : function(field, e){
56209 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56214 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56216 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56218 }else if(k == e.ENTER && !e.ctrlKey){
56222 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56224 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56226 }else if(k == e.ESC){
56230 g.startEditing(newCell[0], newCell[1]);
56235 * Ext JS Library 1.1.1
56236 * Copyright(c) 2006-2007, Ext JS, LLC.
56238 * Originally Released Under LGPL - original licence link has changed is not relivant.
56241 * <script type="text/javascript">
56244 * @class Roo.grid.CellSelectionModel
56245 * @extends Roo.grid.AbstractSelectionModel
56246 * This class provides the basic implementation for cell selection in a grid.
56248 * @param {Object} config The object containing the configuration of this model.
56249 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56251 Roo.grid.CellSelectionModel = function(config){
56252 Roo.apply(this, config);
56254 this.selection = null;
56258 * @event beforerowselect
56259 * Fires before a cell is selected.
56260 * @param {SelectionModel} this
56261 * @param {Number} rowIndex The selected row index
56262 * @param {Number} colIndex The selected cell index
56264 "beforecellselect" : true,
56266 * @event cellselect
56267 * Fires when a cell is selected.
56268 * @param {SelectionModel} this
56269 * @param {Number} rowIndex The selected row index
56270 * @param {Number} colIndex The selected cell index
56272 "cellselect" : true,
56274 * @event selectionchange
56275 * Fires when the active selection changes.
56276 * @param {SelectionModel} this
56277 * @param {Object} selection null for no selection or an object (o) with two properties
56279 <li>o.record: the record object for the row the selection is in</li>
56280 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56283 "selectionchange" : true,
56286 * Fires when the tab (or enter) was pressed on the last editable cell
56287 * You can use this to trigger add new row.
56288 * @param {SelectionModel} this
56292 * @event beforeeditnext
56293 * Fires before the next editable sell is made active
56294 * You can use this to skip to another cell or fire the tabend
56295 * if you set cell to false
56296 * @param {Object} eventdata object : { cell : [ row, col ] }
56298 "beforeeditnext" : true
56300 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56303 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56305 enter_is_tab: false,
56308 initEvents : function(){
56309 this.grid.on("mousedown", this.handleMouseDown, this);
56310 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56311 var view = this.grid.view;
56312 view.on("refresh", this.onViewChange, this);
56313 view.on("rowupdated", this.onRowUpdated, this);
56314 view.on("beforerowremoved", this.clearSelections, this);
56315 view.on("beforerowsinserted", this.clearSelections, this);
56316 if(this.grid.isEditor){
56317 this.grid.on("beforeedit", this.beforeEdit, this);
56322 beforeEdit : function(e){
56323 this.select(e.row, e.column, false, true, e.record);
56327 onRowUpdated : function(v, index, r){
56328 if(this.selection && this.selection.record == r){
56329 v.onCellSelect(index, this.selection.cell[1]);
56334 onViewChange : function(){
56335 this.clearSelections(true);
56339 * Returns the currently selected cell,.
56340 * @return {Array} The selected cell (row, column) or null if none selected.
56342 getSelectedCell : function(){
56343 return this.selection ? this.selection.cell : null;
56347 * Clears all selections.
56348 * @param {Boolean} true to prevent the gridview from being notified about the change.
56350 clearSelections : function(preventNotify){
56351 var s = this.selection;
56353 if(preventNotify !== true){
56354 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56356 this.selection = null;
56357 this.fireEvent("selectionchange", this, null);
56362 * Returns true if there is a selection.
56363 * @return {Boolean}
56365 hasSelection : function(){
56366 return this.selection ? true : false;
56370 handleMouseDown : function(e, t){
56371 var v = this.grid.getView();
56372 if(this.isLocked()){
56375 var row = v.findRowIndex(t);
56376 var cell = v.findCellIndex(t);
56377 if(row !== false && cell !== false){
56378 this.select(row, cell);
56384 * @param {Number} rowIndex
56385 * @param {Number} collIndex
56387 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56388 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56389 this.clearSelections();
56390 r = r || this.grid.dataSource.getAt(rowIndex);
56393 cell : [rowIndex, colIndex]
56395 if(!preventViewNotify){
56396 var v = this.grid.getView();
56397 v.onCellSelect(rowIndex, colIndex);
56398 if(preventFocus !== true){
56399 v.focusCell(rowIndex, colIndex);
56402 this.fireEvent("cellselect", this, rowIndex, colIndex);
56403 this.fireEvent("selectionchange", this, this.selection);
56408 isSelectable : function(rowIndex, colIndex, cm){
56409 return !cm.isHidden(colIndex);
56413 handleKeyDown : function(e){
56414 //Roo.log('Cell Sel Model handleKeyDown');
56415 if(!e.isNavKeyPress()){
56418 var g = this.grid, s = this.selection;
56421 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56423 this.select(cell[0], cell[1]);
56428 var walk = function(row, col, step){
56429 return g.walkCells(row, col, step, sm.isSelectable, sm);
56431 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56438 // handled by onEditorKey
56439 if (g.isEditor && g.editing) {
56443 newCell = walk(r, c-1, -1);
56445 newCell = walk(r, c+1, 1);
56450 newCell = walk(r+1, c, 1);
56454 newCell = walk(r-1, c, -1);
56458 newCell = walk(r, c+1, 1);
56462 newCell = walk(r, c-1, -1);
56467 if(g.isEditor && !g.editing){
56468 g.startEditing(r, c);
56477 this.select(newCell[0], newCell[1]);
56483 acceptsNav : function(row, col, cm){
56484 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56488 * @param {Number} field (not used) - as it's normally used as a listener
56489 * @param {Number} e - event - fake it by using
56491 * var e = Roo.EventObjectImpl.prototype;
56492 * e.keyCode = e.TAB
56496 onEditorKey : function(field, e){
56498 var k = e.getKey(),
56501 ed = g.activeEditor,
56503 ///Roo.log('onEditorKey' + k);
56506 if (this.enter_is_tab && k == e.ENTER) {
56512 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56514 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56520 } else if(k == e.ENTER && !e.ctrlKey){
56523 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56525 } else if(k == e.ESC){
56530 var ecall = { cell : newCell, forward : forward };
56531 this.fireEvent('beforeeditnext', ecall );
56532 newCell = ecall.cell;
56533 forward = ecall.forward;
56537 //Roo.log('next cell after edit');
56538 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56539 } else if (forward) {
56540 // tabbed past last
56541 this.fireEvent.defer(100, this, ['tabend',this]);
56546 * Ext JS Library 1.1.1
56547 * Copyright(c) 2006-2007, Ext JS, LLC.
56549 * Originally Released Under LGPL - original licence link has changed is not relivant.
56552 * <script type="text/javascript">
56556 * @class Roo.grid.EditorGrid
56557 * @extends Roo.grid.Grid
56558 * Class for creating and editable grid.
56559 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56560 * The container MUST have some type of size defined for the grid to fill. The container will be
56561 * automatically set to position relative if it isn't already.
56562 * @param {Object} dataSource The data model to bind to
56563 * @param {Object} colModel The column model with info about this grid's columns
56565 Roo.grid.EditorGrid = function(container, config){
56566 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56567 this.getGridEl().addClass("xedit-grid");
56569 if(!this.selModel){
56570 this.selModel = new Roo.grid.CellSelectionModel();
56573 this.activeEditor = null;
56577 * @event beforeedit
56578 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56579 * <ul style="padding:5px;padding-left:16px;">
56580 * <li>grid - This grid</li>
56581 * <li>record - The record being edited</li>
56582 * <li>field - The field name being edited</li>
56583 * <li>value - The value for the field being edited.</li>
56584 * <li>row - The grid row index</li>
56585 * <li>column - The grid column index</li>
56586 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56588 * @param {Object} e An edit event (see above for description)
56590 "beforeedit" : true,
56593 * Fires after a cell is edited. <br />
56594 * <ul style="padding:5px;padding-left:16px;">
56595 * <li>grid - This grid</li>
56596 * <li>record - The record being edited</li>
56597 * <li>field - The field name being edited</li>
56598 * <li>value - The value being set</li>
56599 * <li>originalValue - The original value for the field, before the edit.</li>
56600 * <li>row - The grid row index</li>
56601 * <li>column - The grid column index</li>
56603 * @param {Object} e An edit event (see above for description)
56605 "afteredit" : true,
56607 * @event validateedit
56608 * Fires after a cell is edited, but before the value is set in the record.
56609 * You can use this to modify the value being set in the field, Return false
56610 * to cancel the change. The edit event object has the following properties <br />
56611 * <ul style="padding:5px;padding-left:16px;">
56612 * <li>editor - This editor</li>
56613 * <li>grid - This grid</li>
56614 * <li>record - The record being edited</li>
56615 * <li>field - The field name being edited</li>
56616 * <li>value - The value being set</li>
56617 * <li>originalValue - The original value for the field, before the edit.</li>
56618 * <li>row - The grid row index</li>
56619 * <li>column - The grid column index</li>
56620 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56622 * @param {Object} e An edit event (see above for description)
56624 "validateedit" : true
56626 this.on("bodyscroll", this.stopEditing, this);
56627 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56630 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56632 * @cfg {Number} clicksToEdit
56633 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56640 trackMouseOver: false, // causes very odd FF errors
56642 onCellDblClick : function(g, row, col){
56643 this.startEditing(row, col);
56646 onEditComplete : function(ed, value, startValue){
56647 this.editing = false;
56648 this.activeEditor = null;
56649 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56651 var field = this.colModel.getDataIndex(ed.col);
56656 originalValue: startValue,
56663 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56666 if(String(value) !== String(startValue)){
56668 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56669 r.set(field, e.value);
56670 // if we are dealing with a combo box..
56671 // then we also set the 'name' colum to be the displayField
56672 if (ed.field.displayField && ed.field.name) {
56673 r.set(ed.field.name, ed.field.el.dom.value);
56676 delete e.cancel; //?? why!!!
56677 this.fireEvent("afteredit", e);
56680 this.fireEvent("afteredit", e); // always fire it!
56682 this.view.focusCell(ed.row, ed.col);
56686 * Starts editing the specified for the specified row/column
56687 * @param {Number} rowIndex
56688 * @param {Number} colIndex
56690 startEditing : function(row, col){
56691 this.stopEditing();
56692 if(this.colModel.isCellEditable(col, row)){
56693 this.view.ensureVisible(row, col, true);
56695 var r = this.dataSource.getAt(row);
56696 var field = this.colModel.getDataIndex(col);
56697 var cell = Roo.get(this.view.getCell(row,col));
56702 value: r.data[field],
56707 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56708 this.editing = true;
56709 var ed = this.colModel.getCellEditor(col, row);
56715 ed.render(ed.parentEl || document.body);
56721 (function(){ // complex but required for focus issues in safari, ie and opera
56725 ed.on("complete", this.onEditComplete, this, {single: true});
56726 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56727 this.activeEditor = ed;
56728 var v = r.data[field];
56729 ed.startEdit(this.view.getCell(row, col), v);
56730 // combo's with 'displayField and name set
56731 if (ed.field.displayField && ed.field.name) {
56732 ed.field.el.dom.value = r.data[ed.field.name];
56736 }).defer(50, this);
56742 * Stops any active editing
56744 stopEditing : function(){
56745 if(this.activeEditor){
56746 this.activeEditor.completeEdit();
56748 this.activeEditor = null;
56752 * Called to get grid's drag proxy text, by default returns this.ddText.
56755 getDragDropText : function(){
56756 var count = this.selModel.getSelectedCell() ? 1 : 0;
56757 return String.format(this.ddText, count, count == 1 ? '' : 's');
56762 * Ext JS Library 1.1.1
56763 * Copyright(c) 2006-2007, Ext JS, LLC.
56765 * Originally Released Under LGPL - original licence link has changed is not relivant.
56768 * <script type="text/javascript">
56771 // private - not really -- you end up using it !
56772 // This is a support class used internally by the Grid components
56775 * @class Roo.grid.GridEditor
56776 * @extends Roo.Editor
56777 * Class for creating and editable grid elements.
56778 * @param {Object} config any settings (must include field)
56780 Roo.grid.GridEditor = function(field, config){
56781 if (!config && field.field) {
56783 field = Roo.factory(config.field, Roo.form);
56785 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56786 field.monitorTab = false;
56789 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56792 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56795 alignment: "tl-tl",
56798 cls: "x-small-editor x-grid-editor",
56803 * Ext JS Library 1.1.1
56804 * Copyright(c) 2006-2007, Ext JS, LLC.
56806 * Originally Released Under LGPL - original licence link has changed is not relivant.
56809 * <script type="text/javascript">
56814 Roo.grid.PropertyRecord = Roo.data.Record.create([
56815 {name:'name',type:'string'}, 'value'
56819 Roo.grid.PropertyStore = function(grid, source){
56821 this.store = new Roo.data.Store({
56822 recordType : Roo.grid.PropertyRecord
56824 this.store.on('update', this.onUpdate, this);
56826 this.setSource(source);
56828 Roo.grid.PropertyStore.superclass.constructor.call(this);
56833 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56834 setSource : function(o){
56836 this.store.removeAll();
56839 if(this.isEditableValue(o[k])){
56840 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56843 this.store.loadRecords({records: data}, {}, true);
56846 onUpdate : function(ds, record, type){
56847 if(type == Roo.data.Record.EDIT){
56848 var v = record.data['value'];
56849 var oldValue = record.modified['value'];
56850 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56851 this.source[record.id] = v;
56853 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56860 getProperty : function(row){
56861 return this.store.getAt(row);
56864 isEditableValue: function(val){
56865 if(val && val instanceof Date){
56867 }else if(typeof val == 'object' || typeof val == 'function'){
56873 setValue : function(prop, value){
56874 this.source[prop] = value;
56875 this.store.getById(prop).set('value', value);
56878 getSource : function(){
56879 return this.source;
56883 Roo.grid.PropertyColumnModel = function(grid, store){
56886 g.PropertyColumnModel.superclass.constructor.call(this, [
56887 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56888 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56890 this.store = store;
56891 this.bselect = Roo.DomHelper.append(document.body, {
56892 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56893 {tag: 'option', value: 'true', html: 'true'},
56894 {tag: 'option', value: 'false', html: 'false'}
56897 Roo.id(this.bselect);
56900 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56901 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56902 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56903 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56904 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56906 this.renderCellDelegate = this.renderCell.createDelegate(this);
56907 this.renderPropDelegate = this.renderProp.createDelegate(this);
56910 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56914 valueText : 'Value',
56916 dateFormat : 'm/j/Y',
56919 renderDate : function(dateVal){
56920 return dateVal.dateFormat(this.dateFormat);
56923 renderBool : function(bVal){
56924 return bVal ? 'true' : 'false';
56927 isCellEditable : function(colIndex, rowIndex){
56928 return colIndex == 1;
56931 getRenderer : function(col){
56933 this.renderCellDelegate : this.renderPropDelegate;
56936 renderProp : function(v){
56937 return this.getPropertyName(v);
56940 renderCell : function(val){
56942 if(val instanceof Date){
56943 rv = this.renderDate(val);
56944 }else if(typeof val == 'boolean'){
56945 rv = this.renderBool(val);
56947 return Roo.util.Format.htmlEncode(rv);
56950 getPropertyName : function(name){
56951 var pn = this.grid.propertyNames;
56952 return pn && pn[name] ? pn[name] : name;
56955 getCellEditor : function(colIndex, rowIndex){
56956 var p = this.store.getProperty(rowIndex);
56957 var n = p.data['name'], val = p.data['value'];
56959 if(typeof(this.grid.customEditors[n]) == 'string'){
56960 return this.editors[this.grid.customEditors[n]];
56962 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56963 return this.grid.customEditors[n];
56965 if(val instanceof Date){
56966 return this.editors['date'];
56967 }else if(typeof val == 'number'){
56968 return this.editors['number'];
56969 }else if(typeof val == 'boolean'){
56970 return this.editors['boolean'];
56972 return this.editors['string'];
56978 * @class Roo.grid.PropertyGrid
56979 * @extends Roo.grid.EditorGrid
56980 * This class represents the interface of a component based property grid control.
56981 * <br><br>Usage:<pre><code>
56982 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56990 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56991 * The container MUST have some type of size defined for the grid to fill. The container will be
56992 * automatically set to position relative if it isn't already.
56993 * @param {Object} config A config object that sets properties on this grid.
56995 Roo.grid.PropertyGrid = function(container, config){
56996 config = config || {};
56997 var store = new Roo.grid.PropertyStore(this);
56998 this.store = store;
56999 var cm = new Roo.grid.PropertyColumnModel(this, store);
57000 store.store.sort('name', 'ASC');
57001 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
57004 enableColLock:false,
57005 enableColumnMove:false,
57007 trackMouseOver: false,
57010 this.getGridEl().addClass('x-props-grid');
57011 this.lastEditRow = null;
57012 this.on('columnresize', this.onColumnResize, this);
57015 * @event beforepropertychange
57016 * Fires before a property changes (return false to stop?)
57017 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57018 * @param {String} id Record Id
57019 * @param {String} newval New Value
57020 * @param {String} oldval Old Value
57022 "beforepropertychange": true,
57024 * @event propertychange
57025 * Fires after a property changes
57026 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
57027 * @param {String} id Record Id
57028 * @param {String} newval New Value
57029 * @param {String} oldval Old Value
57031 "propertychange": true
57033 this.customEditors = this.customEditors || {};
57035 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
57038 * @cfg {Object} customEditors map of colnames=> custom editors.
57039 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
57040 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
57041 * false disables editing of the field.
57045 * @cfg {Object} propertyNames map of property Names to their displayed value
57048 render : function(){
57049 Roo.grid.PropertyGrid.superclass.render.call(this);
57050 this.autoSize.defer(100, this);
57053 autoSize : function(){
57054 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
57056 this.view.fitColumns();
57060 onColumnResize : function(){
57061 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
57065 * Sets the data for the Grid
57066 * accepts a Key => Value object of all the elements avaiable.
57067 * @param {Object} data to appear in grid.
57069 setSource : function(source){
57070 this.store.setSource(source);
57074 * Gets all the data from the grid.
57075 * @return {Object} data data stored in grid
57077 getSource : function(){
57078 return this.store.getSource();
57087 * @class Roo.grid.Calendar
57088 * @extends Roo.util.Grid
57089 * This class extends the Grid to provide a calendar widget
57090 * <br><br>Usage:<pre><code>
57091 var grid = new Roo.grid.Calendar("my-container-id", {
57094 selModel: mySelectionModel,
57095 autoSizeColumns: true,
57096 monitorWindowResize: false,
57097 trackMouseOver: true
57098 eventstore : real data store..
57104 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57105 * The container MUST have some type of size defined for the grid to fill. The container will be
57106 * automatically set to position relative if it isn't already.
57107 * @param {Object} config A config object that sets properties on this grid.
57109 Roo.grid.Calendar = function(container, config){
57110 // initialize the container
57111 this.container = Roo.get(container);
57112 this.container.update("");
57113 this.container.setStyle("overflow", "hidden");
57114 this.container.addClass('x-grid-container');
57116 this.id = this.container.id;
57118 Roo.apply(this, config);
57119 // check and correct shorthanded configs
57123 for (var r = 0;r < 6;r++) {
57126 for (var c =0;c < 7;c++) {
57130 if (this.eventStore) {
57131 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57132 this.eventStore.on('load',this.onLoad, this);
57133 this.eventStore.on('beforeload',this.clearEvents, this);
57137 this.dataSource = new Roo.data.Store({
57138 proxy: new Roo.data.MemoryProxy(rows),
57139 reader: new Roo.data.ArrayReader({}, [
57140 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57143 this.dataSource.load();
57144 this.ds = this.dataSource;
57145 this.ds.xmodule = this.xmodule || false;
57148 var cellRender = function(v,x,r)
57150 return String.format(
57151 '<div class="fc-day fc-widget-content"><div>' +
57152 '<div class="fc-event-container"></div>' +
57153 '<div class="fc-day-number">{0}</div>'+
57155 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57156 '</div></div>', v);
57161 this.colModel = new Roo.grid.ColumnModel( [
57163 xtype: 'ColumnModel',
57165 dataIndex : 'weekday0',
57167 renderer : cellRender
57170 xtype: 'ColumnModel',
57172 dataIndex : 'weekday1',
57174 renderer : cellRender
57177 xtype: 'ColumnModel',
57179 dataIndex : 'weekday2',
57180 header : 'Tuesday',
57181 renderer : cellRender
57184 xtype: 'ColumnModel',
57186 dataIndex : 'weekday3',
57187 header : 'Wednesday',
57188 renderer : cellRender
57191 xtype: 'ColumnModel',
57193 dataIndex : 'weekday4',
57194 header : 'Thursday',
57195 renderer : cellRender
57198 xtype: 'ColumnModel',
57200 dataIndex : 'weekday5',
57202 renderer : cellRender
57205 xtype: 'ColumnModel',
57207 dataIndex : 'weekday6',
57208 header : 'Saturday',
57209 renderer : cellRender
57212 this.cm = this.colModel;
57213 this.cm.xmodule = this.xmodule || false;
57217 //this.selModel = new Roo.grid.CellSelectionModel();
57218 //this.sm = this.selModel;
57219 //this.selModel.init(this);
57223 this.container.setWidth(this.width);
57227 this.container.setHeight(this.height);
57234 * The raw click event for the entire grid.
57235 * @param {Roo.EventObject} e
57240 * The raw dblclick event for the entire grid.
57241 * @param {Roo.EventObject} e
57245 * @event contextmenu
57246 * The raw contextmenu event for the entire grid.
57247 * @param {Roo.EventObject} e
57249 "contextmenu" : true,
57252 * The raw mousedown event for the entire grid.
57253 * @param {Roo.EventObject} e
57255 "mousedown" : true,
57258 * The raw mouseup event for the entire grid.
57259 * @param {Roo.EventObject} e
57264 * The raw mouseover event for the entire grid.
57265 * @param {Roo.EventObject} e
57267 "mouseover" : true,
57270 * The raw mouseout event for the entire grid.
57271 * @param {Roo.EventObject} e
57276 * The raw keypress event for the entire grid.
57277 * @param {Roo.EventObject} e
57282 * The raw keydown event for the entire grid.
57283 * @param {Roo.EventObject} e
57291 * Fires when a cell is clicked
57292 * @param {Grid} this
57293 * @param {Number} rowIndex
57294 * @param {Number} columnIndex
57295 * @param {Roo.EventObject} e
57297 "cellclick" : true,
57299 * @event celldblclick
57300 * Fires when a cell is double clicked
57301 * @param {Grid} this
57302 * @param {Number} rowIndex
57303 * @param {Number} columnIndex
57304 * @param {Roo.EventObject} e
57306 "celldblclick" : true,
57309 * Fires when a row is clicked
57310 * @param {Grid} this
57311 * @param {Number} rowIndex
57312 * @param {Roo.EventObject} e
57316 * @event rowdblclick
57317 * Fires when a row is double clicked
57318 * @param {Grid} this
57319 * @param {Number} rowIndex
57320 * @param {Roo.EventObject} e
57322 "rowdblclick" : true,
57324 * @event headerclick
57325 * Fires when a header is clicked
57326 * @param {Grid} this
57327 * @param {Number} columnIndex
57328 * @param {Roo.EventObject} e
57330 "headerclick" : true,
57332 * @event headerdblclick
57333 * Fires when a header cell is double clicked
57334 * @param {Grid} this
57335 * @param {Number} columnIndex
57336 * @param {Roo.EventObject} e
57338 "headerdblclick" : true,
57340 * @event rowcontextmenu
57341 * Fires when a row is right clicked
57342 * @param {Grid} this
57343 * @param {Number} rowIndex
57344 * @param {Roo.EventObject} e
57346 "rowcontextmenu" : true,
57348 * @event cellcontextmenu
57349 * Fires when a cell is right clicked
57350 * @param {Grid} this
57351 * @param {Number} rowIndex
57352 * @param {Number} cellIndex
57353 * @param {Roo.EventObject} e
57355 "cellcontextmenu" : true,
57357 * @event headercontextmenu
57358 * Fires when a header is right clicked
57359 * @param {Grid} this
57360 * @param {Number} columnIndex
57361 * @param {Roo.EventObject} e
57363 "headercontextmenu" : true,
57365 * @event bodyscroll
57366 * Fires when the body element is scrolled
57367 * @param {Number} scrollLeft
57368 * @param {Number} scrollTop
57370 "bodyscroll" : true,
57372 * @event columnresize
57373 * Fires when the user resizes a column
57374 * @param {Number} columnIndex
57375 * @param {Number} newSize
57377 "columnresize" : true,
57379 * @event columnmove
57380 * Fires when the user moves a column
57381 * @param {Number} oldIndex
57382 * @param {Number} newIndex
57384 "columnmove" : true,
57387 * Fires when row(s) start being dragged
57388 * @param {Grid} this
57389 * @param {Roo.GridDD} dd The drag drop object
57390 * @param {event} e The raw browser event
57392 "startdrag" : true,
57395 * Fires when a drag operation is complete
57396 * @param {Grid} this
57397 * @param {Roo.GridDD} dd The drag drop object
57398 * @param {event} e The raw browser event
57403 * Fires when dragged row(s) are dropped on a valid DD target
57404 * @param {Grid} this
57405 * @param {Roo.GridDD} dd The drag drop object
57406 * @param {String} targetId The target drag drop object
57407 * @param {event} e The raw browser event
57412 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57413 * @param {Grid} this
57414 * @param {Roo.GridDD} dd The drag drop object
57415 * @param {String} targetId The target drag drop object
57416 * @param {event} e The raw browser event
57421 * Fires when the dragged row(s) first cross another DD target while being dragged
57422 * @param {Grid} this
57423 * @param {Roo.GridDD} dd The drag drop object
57424 * @param {String} targetId The target drag drop object
57425 * @param {event} e The raw browser event
57427 "dragenter" : true,
57430 * Fires when the dragged row(s) leave another DD target while being dragged
57431 * @param {Grid} this
57432 * @param {Roo.GridDD} dd The drag drop object
57433 * @param {String} targetId The target drag drop object
57434 * @param {event} e The raw browser event
57439 * Fires when a row is rendered, so you can change add a style to it.
57440 * @param {GridView} gridview The grid view
57441 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57447 * Fires when the grid is rendered
57448 * @param {Grid} grid
57453 * Fires when a date is selected
57454 * @param {DatePicker} this
57455 * @param {Date} date The selected date
57459 * @event monthchange
57460 * Fires when the displayed month changes
57461 * @param {DatePicker} this
57462 * @param {Date} date The selected month
57464 'monthchange': true,
57466 * @event evententer
57467 * Fires when mouse over an event
57468 * @param {Calendar} this
57469 * @param {event} Event
57471 'evententer': true,
57473 * @event eventleave
57474 * Fires when the mouse leaves an
57475 * @param {Calendar} this
57478 'eventleave': true,
57480 * @event eventclick
57481 * Fires when the mouse click an
57482 * @param {Calendar} this
57485 'eventclick': true,
57487 * @event eventrender
57488 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57489 * @param {Calendar} this
57490 * @param {data} data to be modified
57492 'eventrender': true
57496 Roo.grid.Grid.superclass.constructor.call(this);
57497 this.on('render', function() {
57498 this.view.el.addClass('x-grid-cal');
57500 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57504 if (!Roo.grid.Calendar.style) {
57505 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57508 '.x-grid-cal .x-grid-col' : {
57509 height: 'auto !important',
57510 'vertical-align': 'top'
57512 '.x-grid-cal .fc-event-hori' : {
57523 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57525 * @cfg {Store} eventStore The store that loads events.
57530 activeDate : false,
57533 monitorWindowResize : false,
57536 resizeColumns : function() {
57537 var col = (this.view.el.getWidth() / 7) - 3;
57538 // loop through cols, and setWidth
57539 for(var i =0 ; i < 7 ; i++){
57540 this.cm.setColumnWidth(i, col);
57543 setDate :function(date) {
57545 Roo.log('setDate?');
57547 this.resizeColumns();
57548 var vd = this.activeDate;
57549 this.activeDate = date;
57550 // if(vd && this.el){
57551 // var t = date.getTime();
57552 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57553 // Roo.log('using add remove');
57555 // this.fireEvent('monthchange', this, date);
57557 // this.cells.removeClass("fc-state-highlight");
57558 // this.cells.each(function(c){
57559 // if(c.dateValue == t){
57560 // c.addClass("fc-state-highlight");
57561 // setTimeout(function(){
57562 // try{c.dom.firstChild.focus();}catch(e){}
57572 var days = date.getDaysInMonth();
57574 var firstOfMonth = date.getFirstDateOfMonth();
57575 var startingPos = firstOfMonth.getDay()-this.startDay;
57577 if(startingPos < this.startDay){
57581 var pm = date.add(Date.MONTH, -1);
57582 var prevStart = pm.getDaysInMonth()-startingPos;
57586 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57588 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57589 //this.cells.addClassOnOver('fc-state-hover');
57591 var cells = this.cells.elements;
57592 var textEls = this.textNodes;
57594 //Roo.each(cells, function(cell){
57595 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57598 days += startingPos;
57600 // convert everything to numbers so it's fast
57601 var day = 86400000;
57602 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57605 //Roo.log(prevStart);
57607 var today = new Date().clearTime().getTime();
57608 var sel = date.clearTime().getTime();
57609 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57610 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57611 var ddMatch = this.disabledDatesRE;
57612 var ddText = this.disabledDatesText;
57613 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57614 var ddaysText = this.disabledDaysText;
57615 var format = this.format;
57617 var setCellClass = function(cal, cell){
57619 //Roo.log('set Cell Class');
57621 var t = d.getTime();
57626 cell.dateValue = t;
57628 cell.className += " fc-today";
57629 cell.className += " fc-state-highlight";
57630 cell.title = cal.todayText;
57633 // disable highlight in other month..
57634 cell.className += " fc-state-highlight";
57639 //cell.className = " fc-state-disabled";
57640 cell.title = cal.minText;
57644 //cell.className = " fc-state-disabled";
57645 cell.title = cal.maxText;
57649 if(ddays.indexOf(d.getDay()) != -1){
57650 // cell.title = ddaysText;
57651 // cell.className = " fc-state-disabled";
57654 if(ddMatch && format){
57655 var fvalue = d.dateFormat(format);
57656 if(ddMatch.test(fvalue)){
57657 cell.title = ddText.replace("%0", fvalue);
57658 cell.className = " fc-state-disabled";
57662 if (!cell.initialClassName) {
57663 cell.initialClassName = cell.dom.className;
57666 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57671 for(; i < startingPos; i++) {
57672 cells[i].dayName = (++prevStart);
57673 Roo.log(textEls[i]);
57674 d.setDate(d.getDate()+1);
57676 //cells[i].className = "fc-past fc-other-month";
57677 setCellClass(this, cells[i]);
57682 for(; i < days; i++){
57683 intDay = i - startingPos + 1;
57684 cells[i].dayName = (intDay);
57685 d.setDate(d.getDate()+1);
57687 cells[i].className = ''; // "x-date-active";
57688 setCellClass(this, cells[i]);
57692 for(; i < 42; i++) {
57693 //textEls[i].innerHTML = (++extraDays);
57695 d.setDate(d.getDate()+1);
57696 cells[i].dayName = (++extraDays);
57697 cells[i].className = "fc-future fc-other-month";
57698 setCellClass(this, cells[i]);
57701 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57703 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57705 // this will cause all the cells to mis
57708 for (var r = 0;r < 6;r++) {
57709 for (var c =0;c < 7;c++) {
57710 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57714 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57715 for(i=0;i<cells.length;i++) {
57717 this.cells.elements[i].dayName = cells[i].dayName ;
57718 this.cells.elements[i].className = cells[i].className;
57719 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57720 this.cells.elements[i].title = cells[i].title ;
57721 this.cells.elements[i].dateValue = cells[i].dateValue ;
57727 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57728 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57730 ////if(totalRows != 6){
57731 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57732 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57735 this.fireEvent('monthchange', this, date);
57740 * Returns the grid's SelectionModel.
57741 * @return {SelectionModel}
57743 getSelectionModel : function(){
57744 if(!this.selModel){
57745 this.selModel = new Roo.grid.CellSelectionModel();
57747 return this.selModel;
57751 this.eventStore.load()
57757 findCell : function(dt) {
57758 dt = dt.clearTime().getTime();
57760 this.cells.each(function(c){
57761 //Roo.log("check " +c.dateValue + '?=' + dt);
57762 if(c.dateValue == dt){
57772 findCells : function(rec) {
57773 var s = rec.data.start_dt.clone().clearTime().getTime();
57775 var e= rec.data.end_dt.clone().clearTime().getTime();
57778 this.cells.each(function(c){
57779 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57781 if(c.dateValue > e){
57784 if(c.dateValue < s){
57793 findBestRow: function(cells)
57797 for (var i =0 ; i < cells.length;i++) {
57798 ret = Math.max(cells[i].rows || 0,ret);
57805 addItem : function(rec)
57807 // look for vertical location slot in
57808 var cells = this.findCells(rec);
57810 rec.row = this.findBestRow(cells);
57812 // work out the location.
57816 for(var i =0; i < cells.length; i++) {
57824 if (crow.start.getY() == cells[i].getY()) {
57826 crow.end = cells[i];
57842 for (var i = 0; i < cells.length;i++) {
57843 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57850 clearEvents: function() {
57852 if (!this.eventStore.getCount()) {
57855 // reset number of rows in cells.
57856 Roo.each(this.cells.elements, function(c){
57860 this.eventStore.each(function(e) {
57861 this.clearEvent(e);
57866 clearEvent : function(ev)
57869 Roo.each(ev.els, function(el) {
57870 el.un('mouseenter' ,this.onEventEnter, this);
57871 el.un('mouseleave' ,this.onEventLeave, this);
57879 renderEvent : function(ev,ctr) {
57881 ctr = this.view.el.select('.fc-event-container',true).first();
57885 this.clearEvent(ev);
57891 var cells = ev.cells;
57892 var rows = ev.rows;
57893 this.fireEvent('eventrender', this, ev);
57895 for(var i =0; i < rows.length; i++) {
57899 cls += ' fc-event-start';
57901 if ((i+1) == rows.length) {
57902 cls += ' fc-event-end';
57905 //Roo.log(ev.data);
57906 // how many rows should it span..
57907 var cg = this.eventTmpl.append(ctr,Roo.apply({
57910 }, ev.data) , true);
57913 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57914 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57915 cg.on('click', this.onEventClick, this, ev);
57919 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57920 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57923 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57924 cg.setWidth(ebox.right - sbox.x -2);
57928 renderEvents: function()
57930 // first make sure there is enough space..
57932 if (!this.eventTmpl) {
57933 this.eventTmpl = new Roo.Template(
57934 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57935 '<div class="fc-event-inner">' +
57936 '<span class="fc-event-time">{time}</span>' +
57937 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57939 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57947 this.cells.each(function(c) {
57948 //Roo.log(c.select('.fc-day-content div',true).first());
57949 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57952 var ctr = this.view.el.select('.fc-event-container',true).first();
57955 this.eventStore.each(function(ev){
57957 this.renderEvent(ev);
57961 this.view.layout();
57965 onEventEnter: function (e, el,event,d) {
57966 this.fireEvent('evententer', this, el, event);
57969 onEventLeave: function (e, el,event,d) {
57970 this.fireEvent('eventleave', this, el, event);
57973 onEventClick: function (e, el,event,d) {
57974 this.fireEvent('eventclick', this, el, event);
57977 onMonthChange: function () {
57981 onLoad: function () {
57983 //Roo.log('calendar onload');
57985 if(this.eventStore.getCount() > 0){
57989 this.eventStore.each(function(d){
57994 if (typeof(add.end_dt) == 'undefined') {
57995 Roo.log("Missing End time in calendar data: ");
57999 if (typeof(add.start_dt) == 'undefined') {
58000 Roo.log("Missing Start time in calendar data: ");
58004 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
58005 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
58006 add.id = add.id || d.id;
58007 add.title = add.title || '??';
58015 this.renderEvents();
58025 render : function ()
58029 if (!this.view.el.hasClass('course-timesheet')) {
58030 this.view.el.addClass('course-timesheet');
58032 if (this.tsStyle) {
58037 Roo.log(_this.grid.view.el.getWidth());
58040 this.tsStyle = Roo.util.CSS.createStyleSheet({
58041 '.course-timesheet .x-grid-row' : {
58044 '.x-grid-row td' : {
58045 'vertical-align' : 0
58047 '.course-edit-link' : {
58049 'text-overflow' : 'ellipsis',
58050 'overflow' : 'hidden',
58051 'white-space' : 'nowrap',
58052 'cursor' : 'pointer'
58057 '.de-act-sup-link' : {
58058 'color' : 'purple',
58059 'text-decoration' : 'line-through'
58063 'text-decoration' : 'line-through'
58065 '.course-timesheet .course-highlight' : {
58066 'border-top-style': 'dashed !important',
58067 'border-bottom-bottom': 'dashed !important'
58069 '.course-timesheet .course-item' : {
58070 'font-family' : 'tahoma, arial, helvetica',
58071 'font-size' : '11px',
58072 'overflow' : 'hidden',
58073 'padding-left' : '10px',
58074 'padding-right' : '10px',
58075 'padding-top' : '10px'
58083 monitorWindowResize : false,
58084 cellrenderer : function(v,x,r)
58089 xtype: 'CellSelectionModel',
58096 beforeload : function (_self, options)
58098 options.params = options.params || {};
58099 options.params._month = _this.monthField.getValue();
58100 options.params.limit = 9999;
58101 options.params['sort'] = 'when_dt';
58102 options.params['dir'] = 'ASC';
58103 this.proxy.loadResponse = this.loadResponse;
58105 //this.addColumns();
58107 load : function (_self, records, options)
58109 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58110 // if you click on the translation.. you can edit it...
58111 var el = Roo.get(this);
58112 var id = el.dom.getAttribute('data-id');
58113 var d = el.dom.getAttribute('data-date');
58114 var t = el.dom.getAttribute('data-time');
58115 //var id = this.child('span').dom.textContent;
58118 Pman.Dialog.CourseCalendar.show({
58122 productitem_active : id ? 1 : 0
58124 _this.grid.ds.load({});
58129 _this.panel.fireEvent('resize', [ '', '' ]);
58132 loadResponse : function(o, success, response){
58133 // this is overridden on before load..
58135 Roo.log("our code?");
58136 //Roo.log(success);
58137 //Roo.log(response)
58138 delete this.activeRequest;
58140 this.fireEvent("loadexception", this, o, response);
58141 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58146 result = o.reader.read(response);
58148 Roo.log("load exception?");
58149 this.fireEvent("loadexception", this, o, response, e);
58150 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58153 Roo.log("ready...");
58154 // loop through result.records;
58155 // and set this.tdate[date] = [] << array of records..
58157 Roo.each(result.records, function(r){
58159 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58160 _this.tdata[r.data.when_dt.format('j')] = [];
58162 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58165 //Roo.log(_this.tdata);
58167 result.records = [];
58168 result.totalRecords = 6;
58170 // let's generate some duumy records for the rows.
58171 //var st = _this.dateField.getValue();
58173 // work out monday..
58174 //st = st.add(Date.DAY, -1 * st.format('w'));
58176 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58178 var firstOfMonth = date.getFirstDayOfMonth();
58179 var days = date.getDaysInMonth();
58181 var firstAdded = false;
58182 for (var i = 0; i < result.totalRecords ; i++) {
58183 //var d= st.add(Date.DAY, i);
58186 for(var w = 0 ; w < 7 ; w++){
58187 if(!firstAdded && firstOfMonth != w){
58194 var dd = (d > 0 && d < 10) ? "0"+d : d;
58195 row['weekday'+w] = String.format(
58196 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58197 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58199 date.format('Y-m-')+dd
58202 if(typeof(_this.tdata[d]) != 'undefined'){
58203 Roo.each(_this.tdata[d], function(r){
58207 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58208 if(r.parent_id*1>0){
58209 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58212 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58213 deactive = 'de-act-link';
58216 row['weekday'+w] += String.format(
58217 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58219 r.product_id_name, //1
58220 r.when_dt.format('h:ia'), //2
58230 // only do this if something added..
58232 result.records.push(_this.grid.dataSource.reader.newRow(row));
58236 // push it twice. (second one with an hour..
58240 this.fireEvent("load", this, o, o.request.arg);
58241 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58243 sortInfo : {field: 'when_dt', direction : 'ASC' },
58245 xtype: 'HttpProxy',
58248 url : baseURL + '/Roo/Shop_course.php'
58251 xtype: 'JsonReader',
58268 'name': 'parent_id',
58272 'name': 'product_id',
58276 'name': 'productitem_id',
58294 click : function (_self, e)
58296 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58297 sd.setMonth(sd.getMonth()-1);
58298 _this.monthField.setValue(sd.format('Y-m-d'));
58299 _this.grid.ds.load({});
58305 xtype: 'Separator',
58309 xtype: 'MonthField',
58312 render : function (_self)
58314 _this.monthField = _self;
58315 // _this.monthField.set today
58317 select : function (combo, date)
58319 _this.grid.ds.load({});
58322 value : (function() { return new Date(); })()
58325 xtype: 'Separator',
58331 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58341 click : function (_self, e)
58343 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58344 sd.setMonth(sd.getMonth()+1);
58345 _this.monthField.setValue(sd.format('Y-m-d'));
58346 _this.grid.ds.load({});
58359 * Ext JS Library 1.1.1
58360 * Copyright(c) 2006-2007, Ext JS, LLC.
58362 * Originally Released Under LGPL - original licence link has changed is not relivant.
58365 * <script type="text/javascript">
58369 * @class Roo.LoadMask
58370 * A simple utility class for generically masking elements while loading data. If the element being masked has
58371 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58372 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58373 * element's UpdateManager load indicator and will be destroyed after the initial load.
58375 * Create a new LoadMask
58376 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58377 * @param {Object} config The config object
58379 Roo.LoadMask = function(el, config){
58380 this.el = Roo.get(el);
58381 Roo.apply(this, config);
58383 this.store.on('beforeload', this.onBeforeLoad, this);
58384 this.store.on('load', this.onLoad, this);
58385 this.store.on('loadexception', this.onLoadException, this);
58386 this.removeMask = false;
58388 var um = this.el.getUpdateManager();
58389 um.showLoadIndicator = false; // disable the default indicator
58390 um.on('beforeupdate', this.onBeforeLoad, this);
58391 um.on('update', this.onLoad, this);
58392 um.on('failure', this.onLoad, this);
58393 this.removeMask = true;
58397 Roo.LoadMask.prototype = {
58399 * @cfg {Boolean} removeMask
58400 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58401 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58404 * @cfg {String} msg
58405 * The text to display in a centered loading message box (defaults to 'Loading...')
58407 msg : 'Loading...',
58409 * @cfg {String} msgCls
58410 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58412 msgCls : 'x-mask-loading',
58415 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58421 * Disables the mask to prevent it from being displayed
58423 disable : function(){
58424 this.disabled = true;
58428 * Enables the mask so that it can be displayed
58430 enable : function(){
58431 this.disabled = false;
58434 onLoadException : function()
58436 Roo.log(arguments);
58438 if (typeof(arguments[3]) != 'undefined') {
58439 Roo.MessageBox.alert("Error loading",arguments[3]);
58443 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58444 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58453 this.el.unmask(this.removeMask);
58456 onLoad : function()
58458 this.el.unmask(this.removeMask);
58462 onBeforeLoad : function(){
58463 if(!this.disabled){
58464 this.el.mask(this.msg, this.msgCls);
58469 destroy : function(){
58471 this.store.un('beforeload', this.onBeforeLoad, this);
58472 this.store.un('load', this.onLoad, this);
58473 this.store.un('loadexception', this.onLoadException, this);
58475 var um = this.el.getUpdateManager();
58476 um.un('beforeupdate', this.onBeforeLoad, this);
58477 um.un('update', this.onLoad, this);
58478 um.un('failure', this.onLoad, this);
58483 * Ext JS Library 1.1.1
58484 * Copyright(c) 2006-2007, Ext JS, LLC.
58486 * Originally Released Under LGPL - original licence link has changed is not relivant.
58489 * <script type="text/javascript">
58494 * @class Roo.XTemplate
58495 * @extends Roo.Template
58496 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58498 var t = new Roo.XTemplate(
58499 '<select name="{name}">',
58500 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58504 // then append, applying the master template values
58507 * Supported features:
58512 {a_variable} - output encoded.
58513 {a_variable.format:("Y-m-d")} - call a method on the variable
58514 {a_variable:raw} - unencoded output
58515 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58516 {a_variable:this.method_on_template(...)} - call a method on the template object.
58521 <tpl for="a_variable or condition.."></tpl>
58522 <tpl if="a_variable or condition"></tpl>
58523 <tpl exec="some javascript"></tpl>
58524 <tpl name="named_template"></tpl> (experimental)
58526 <tpl for="."></tpl> - just iterate the property..
58527 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58531 Roo.XTemplate = function()
58533 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58540 Roo.extend(Roo.XTemplate, Roo.Template, {
58543 * The various sub templates
58548 * basic tag replacing syntax
58551 * // you can fake an object call by doing this
58555 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58558 * compile the template
58560 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58563 compile: function()
58567 s = ['<tpl>', s, '</tpl>'].join('');
58569 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58570 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58571 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58572 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58573 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58578 while(true == !!(m = s.match(re))){
58579 var forMatch = m[0].match(nameRe),
58580 ifMatch = m[0].match(ifRe),
58581 execMatch = m[0].match(execRe),
58582 namedMatch = m[0].match(namedRe),
58587 name = forMatch && forMatch[1] ? forMatch[1] : '';
58590 // if - puts fn into test..
58591 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58593 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58598 // exec - calls a function... returns empty if true is returned.
58599 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58601 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58609 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58610 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58611 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58614 var uid = namedMatch ? namedMatch[1] : id;
58618 id: namedMatch ? namedMatch[1] : id,
58625 s = s.replace(m[0], '');
58627 s = s.replace(m[0], '{xtpl'+ id + '}');
58632 for(var i = tpls.length-1; i >= 0; --i){
58633 this.compileTpl(tpls[i]);
58634 this.tpls[tpls[i].id] = tpls[i];
58636 this.master = tpls[tpls.length-1];
58640 * same as applyTemplate, except it's done to one of the subTemplates
58641 * when using named templates, you can do:
58643 * var str = pl.applySubTemplate('your-name', values);
58646 * @param {Number} id of the template
58647 * @param {Object} values to apply to template
58648 * @param {Object} parent (normaly the instance of this object)
58650 applySubTemplate : function(id, values, parent)
58654 var t = this.tpls[id];
58658 if(t.test && !t.test.call(this, values, parent)){
58662 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58663 Roo.log(e.toString());
58669 if(t.exec && t.exec.call(this, values, parent)){
58673 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58674 Roo.log(e.toString());
58679 var vs = t.target ? t.target.call(this, values, parent) : values;
58680 parent = t.target ? values : parent;
58681 if(t.target && vs instanceof Array){
58683 for(var i = 0, len = vs.length; i < len; i++){
58684 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58686 return buf.join('');
58688 return t.compiled.call(this, vs, parent);
58690 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58691 Roo.log(e.toString());
58692 Roo.log(t.compiled);
58697 compileTpl : function(tpl)
58699 var fm = Roo.util.Format;
58700 var useF = this.disableFormats !== true;
58701 var sep = Roo.isGecko ? "+" : ",";
58702 var undef = function(str) {
58703 Roo.log("Property not found :" + str);
58707 var fn = function(m, name, format, args)
58709 //Roo.log(arguments);
58710 args = args ? args.replace(/\\'/g,"'") : args;
58711 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58712 if (typeof(format) == 'undefined') {
58713 format= 'htmlEncode';
58715 if (format == 'raw' ) {
58719 if(name.substr(0, 4) == 'xtpl'){
58720 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58723 // build an array of options to determine if value is undefined..
58725 // basically get 'xxxx.yyyy' then do
58726 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58727 // (function () { Roo.log("Property not found"); return ''; })() :
58732 Roo.each(name.split('.'), function(st) {
58733 lookfor += (lookfor.length ? '.': '') + st;
58734 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58737 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58740 if(format && useF){
58742 args = args ? ',' + args : "";
58744 if(format.substr(0, 5) != "this."){
58745 format = "fm." + format + '(';
58747 format = 'this.call("'+ format.substr(5) + '", ';
58751 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58755 // called with xxyx.yuu:(test,test)
58757 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58759 // raw.. - :raw modifier..
58760 return "'"+ sep + udef_st + name + ")"+sep+"'";
58764 // branched to use + in gecko and [].join() in others
58766 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58767 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58770 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58771 body.push(tpl.body.replace(/(\r\n|\n)/g,
58772 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58773 body.push("'].join('');};};");
58774 body = body.join('');
58777 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58779 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58785 applyTemplate : function(values){
58786 return this.master.compiled.call(this, values, {});
58787 //var s = this.subs;
58790 apply : function(){
58791 return this.applyTemplate.apply(this, arguments);
58796 Roo.XTemplate.from = function(el){
58797 el = Roo.getDom(el);
58798 return new Roo.XTemplate(el.value || el.innerHTML);