4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isIE = ua.indexOf("msie") > -1,
57 isIE7 = ua.indexOf("msie 7") > -1,
58 isGecko = !isSafari && ua.indexOf("gecko") > -1,
59 isBorderBox = isIE && !isStrict,
60 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62 isLinux = (ua.indexOf("linux") != -1),
63 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64 isTouch = 'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65 // remove css image flicker
68 document.execCommand("BackgroundImageCache", false, true);
74 * True if the browser is in strict mode
79 * True if the page is running over SSL
84 * True when the document is fully initialized and ready for action
89 * Turn on debugging output (currently only the factory uses this)
96 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
99 enableGarbageCollector : true,
102 * True to automatically purge event listeners after uncaching an element (defaults to false).
103 * Note: this only happens if enableGarbageCollector is true.
106 enableListenerCollection:false,
109 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110 * the IE insecure content warning (defaults to javascript:false).
113 SSL_SECURE_URL : "javascript:false",
116 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
120 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
122 emptyFn : function(){},
125 * Copies all the properties of config to obj if they don't already exist.
126 * @param {Object} obj The receiver of the properties
127 * @param {Object} config The source of the properties
128 * @return {Object} returns obj
130 applyIf : function(o, c){
133 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
140 * Applies event listeners to elements by selectors when the document is ready.
141 * The event name is specified with an @ suffix.
144 // add a listener for click on all anchors in element with id foo
145 '#foo a@click' : function(e, t){
149 // add the same listener to multiple selectors (separated by comma BEFORE the @)
150 '#foo a, #bar span.some-class@mouseover' : function(){
155 * @param {Object} obj The list of behaviors to apply
157 addBehaviors : function(o){
159 Roo.onReady(function(){
164 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
166 var parts = b.split('@');
167 if(parts[1]){ // for Object prototype breakers
170 cache[s] = Roo.select(s);
172 cache[s].on(parts[1], o[b]);
179 * Generates unique ids. If the element already has an id, it is unchanged
180 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182 * @return {String} The generated Id.
184 id : function(el, prefix){
185 prefix = prefix || "roo-gen";
187 var id = prefix + (++idSeed);
188 return el ? (el.id ? el.id : (el.id = id)) : id;
193 * Extends one class with another class and optionally overrides members with the passed literal. This class
194 * also adds the function "override()" to the class that can be used to override
195 * members on an instance.
196 * @param {Object} subclass The class inheriting the functionality
197 * @param {Object} superclass The class being extended
198 * @param {Object} overrides (optional) A literal with members
203 var io = function(o){
208 return function(sb, sp, overrides){
209 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
212 sb = function(){sp.apply(this, arguments);};
214 var F = function(){}, sbp, spp = sp.prototype;
216 sbp = sb.prototype = new F();
220 if(spp.constructor == Object.prototype.constructor){
225 sb.override = function(o){
229 Roo.override(sb, overrides);
235 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
237 Roo.override(MyClass, {
238 newMethod1: function(){
241 newMethod2: function(foo){
246 * @param {Object} origclass The class to override
247 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
248 * containing one or more methods.
251 override : function(origclass, overrides){
253 var p = origclass.prototype;
254 for(var method in overrides){
255 p[method] = overrides[method];
260 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
266 * @param {String} namespace1
267 * @param {String} namespace2
268 * @param {String} etc
271 namespace : function(){
272 var a=arguments, o=null, i, j, d, rt;
273 for (i=0; i<a.length; ++i) {
277 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278 for (j=1; j<d.length; ++j) {
279 o[d[j]]=o[d[j]] || {};
285 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
290 * @param {String} classname
291 * @param {String} namespace (optional)
295 factory : function(c, ns)
297 // no xtype, no ns or c.xns - or forced off by c.xns
298 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
301 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302 if (c.constructor == ns[c.xtype]) {// already created...
306 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307 var ret = new ns[c.xtype](c);
311 c.xns = false; // prevent recursion..
315 * Logs to console if it can.
317 * @param {String|Object} string
322 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
329 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
333 urlEncode : function(o){
339 var ov = o[key], k = Roo.encodeURIComponent(key);
340 var type = typeof ov;
341 if(type == 'undefined'){
343 }else if(type != "function" && type != "object"){
344 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345 }else if(ov instanceof Array){
347 for(var i = 0, len = ov.length; i < len; i++) {
348 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359 * Safe version of encodeURIComponent
360 * @param {String} data
364 encodeURIComponent : function (data)
367 return encodeURIComponent(data);
368 } catch(e) {} // should be an uri encode error.
370 if (data == '' || data == null){
373 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374 function nibble_to_hex(nibble){
375 var chars = '0123456789ABCDEF';
376 return chars.charAt(nibble);
378 data = data.toString();
380 for(var i=0; i<data.length; i++){
381 var c = data.charCodeAt(i);
382 var bs = new Array();
385 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388 bs[3] = 0x80 | (c & 0x3F);
389 }else if (c > 0x800){
391 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393 bs[2] = 0x80 | (c & 0x3F);
396 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397 bs[1] = 0x80 | (c & 0x3F);
402 for(var j=0; j<bs.length; j++){
404 var hex = nibble_to_hex((b & 0xF0) >>> 4)
405 + nibble_to_hex(b &0x0F);
414 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415 * @param {String} string
416 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417 * @return {Object} A literal with members
419 urlDecode : function(string, overwrite){
420 if(!string || !string.length){
424 var pairs = string.split('&');
425 var pair, name, value;
426 for(var i = 0, len = pairs.length; i < len; i++){
427 pair = pairs[i].split('=');
428 name = decodeURIComponent(pair[0]);
429 value = decodeURIComponent(pair[1]);
430 if(overwrite !== true){
431 if(typeof obj[name] == "undefined"){
433 }else if(typeof obj[name] == "string"){
434 obj[name] = [obj[name]];
435 obj[name].push(value);
437 obj[name].push(value);
447 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448 * passed array is not really an array, your function is called once with it.
449 * The supplied function is called with (Object item, Number index, Array allItems).
450 * @param {Array/NodeList/Mixed} array
451 * @param {Function} fn
452 * @param {Object} scope
454 each : function(array, fn, scope){
455 if(typeof array.length == "undefined" || typeof array == "string"){
458 for(var i = 0, len = array.length; i < len; i++){
459 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
464 combine : function(){
465 var as = arguments, l = as.length, r = [];
466 for(var i = 0; i < l; i++){
468 if(a instanceof Array){
470 }else if(a.length !== undefined && !a.substr){
471 r = r.concat(Array.prototype.slice.call(a, 0));
480 * Escapes the passed string for use in a regular expression
481 * @param {String} str
484 escapeRe : function(s) {
485 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
489 callback : function(cb, scope, args, delay){
490 if(typeof cb == "function"){
492 cb.defer(delay, scope, args || []);
494 cb.apply(scope, args || []);
500 * Return the dom node for the passed string (id), dom node, or Roo.Element
501 * @param {String/HTMLElement/Roo.Element} el
502 * @return HTMLElement
504 getDom : function(el){
508 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
512 * Shorthand for {@link Roo.ComponentMgr#get}
514 * @return Roo.Component
516 getCmp : function(id){
517 return Roo.ComponentMgr.get(id);
520 num : function(v, defaultValue){
521 if(typeof v != 'number'){
527 destroy : function(){
528 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
532 as.removeAllListeners();
536 if(typeof as.purgeListeners == 'function'){
539 if(typeof as.destroy == 'function'){
546 // inpired by a similar function in mootools library
548 * Returns the type of object that is passed in. If the object passed in is null or undefined it
549 * return false otherwise it returns one of the following values:<ul>
550 * <li><b>string</b>: If the object passed is a string</li>
551 * <li><b>number</b>: If the object passed is a number</li>
552 * <li><b>boolean</b>: If the object passed is a boolean value</li>
553 * <li><b>function</b>: If the object passed is a function reference</li>
554 * <li><b>object</b>: If the object passed is an object</li>
555 * <li><b>array</b>: If the object passed is an array</li>
556 * <li><b>regexp</b>: If the object passed is a regular expression</li>
557 * <li><b>element</b>: If the object passed is a DOM Element</li>
558 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561 * @param {Mixed} object
565 if(o === undefined || o === null){
572 if(t == 'object' && o.nodeName) {
574 case 1: return 'element';
575 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
578 if(t == 'object' || t == 'function') {
579 switch(o.constructor) {
580 case Array: return 'array';
581 case RegExp: return 'regexp';
583 if(typeof o.length == 'number' && typeof o.item == 'function') {
591 * Returns true if the passed value is null, undefined or an empty string (optional).
592 * @param {Mixed} value The value to test
593 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
596 isEmpty : function(v, allowBlank){
597 return v === null || v === undefined || (!allowBlank ? v === '' : false);
611 isBorderBox : isBorderBox,
613 isWindows : isWindows,
622 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623 * you may want to set this to true.
626 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
631 * Selects a single element as a Roo Element
632 * This is about as close as you can get to jQuery's $('do crazy stuff')
633 * @param {String} selector The selector/xpath query
634 * @param {Node} root (optional) The start of the query (defaults to document).
635 * @return {Roo.Element}
637 selectNode : function(selector, root)
639 var node = Roo.DomQuery.selectNode(selector,root);
640 return node ? Roo.get(node) : new Roo.Element(false);
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
652 * Ext JS Library 1.1.1
653 * Copyright(c) 2006-2007, Ext JS, LLC.
655 * Originally Released Under LGPL - original licence link has changed is not relivant.
658 * <script type="text/javascript">
662 // wrappedn so fnCleanup is not in global scope...
664 function fnCleanUp() {
665 var p = Function.prototype;
666 delete p.createSequence;
668 delete p.createDelegate;
669 delete p.createCallback;
670 delete p.createInterceptor;
672 window.detachEvent("onunload", fnCleanUp);
674 window.attachEvent("onunload", fnCleanUp);
681 * These functions are available on every Function object (any JavaScript function).
683 Roo.apply(Function.prototype, {
685 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687 * Will create a function that is bound to those 2 args.
688 * @return {Function} The new function
690 createCallback : function(/*args...*/){
691 // make args available, in function below
692 var args = arguments;
695 return method.apply(window, args);
700 * Creates a delegate (callback) that sets the scope to obj.
701 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702 * Will create a function that is automatically scoped to this.
703 * @param {Object} obj (optional) The object for which the scope is set
704 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706 * if a number the args are inserted at the specified position
707 * @return {Function} The new function
709 createDelegate : function(obj, args, appendArgs){
712 var callArgs = args || arguments;
713 if(appendArgs === true){
714 callArgs = Array.prototype.slice.call(arguments, 0);
715 callArgs = callArgs.concat(args);
716 }else if(typeof appendArgs == "number"){
717 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
721 return method.apply(obj || window, callArgs);
726 * Calls this function after the number of millseconds specified.
727 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728 * @param {Object} obj (optional) The object for which the scope is set
729 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731 * if a number the args are inserted at the specified position
732 * @return {Number} The timeout id that can be used with clearTimeout
734 defer : function(millis, obj, args, appendArgs){
735 var fn = this.createDelegate(obj, args, appendArgs);
737 return setTimeout(fn, millis);
743 * Create a combined function call sequence of the original function + the passed function.
744 * The resulting function returns the results of the original function.
745 * The passed fcn is called with the parameters of the original function
746 * @param {Function} fcn The function to sequence
747 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748 * @return {Function} The new function
750 createSequence : function(fcn, scope){
751 if(typeof fcn != "function"){
756 var retval = method.apply(this || window, arguments);
757 fcn.apply(scope || this || window, arguments);
763 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764 * The resulting function returns the results of the original function.
765 * The passed fcn is called with the parameters of the original function.
767 * @param {Function} fcn The function to call before the original
768 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769 * @return {Function} The new function
771 createInterceptor : function(fcn, scope){
772 if(typeof fcn != "function"){
779 if(fcn.apply(scope || this || window, arguments) === false){
782 return method.apply(this || window, arguments);
788 * Ext JS Library 1.1.1
789 * Copyright(c) 2006-2007, Ext JS, LLC.
791 * Originally Released Under LGPL - original licence link has changed is not relivant.
794 * <script type="text/javascript">
797 Roo.applyIf(String, {
802 * Escapes the passed string for ' and \
803 * @param {String} string The string to escape
804 * @return {String} The escaped string
807 escape : function(string) {
808 return string.replace(/('|\\)/g, "\\$1");
812 * Pads the left side of a string with a specified character. This is especially useful
813 * for normalizing number and date strings. Example usage:
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
818 * @param {String} string The original string
819 * @param {Number} size The total length of the output string
820 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821 * @return {String} The padded string
824 leftPad : function (val, size, ch) {
825 var result = new String(val);
826 if(ch === null || ch === undefined || ch === '') {
829 while (result.length < size) {
830 result = ch + result;
836 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
837 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
843 * @param {String} string The tokenized string to be formatted
844 * @param {String} value1 The value to replace token {0}
845 * @param {String} value2 Etc...
846 * @return {String} The formatted string
849 format : function(format){
850 var args = Array.prototype.slice.call(arguments, 1);
851 return format.replace(/\{(\d+)\}/g, function(m, i){
852 return Roo.util.Format.htmlEncode(args[i]);
858 * Utility function that allows you to easily switch a string between two alternating values. The passed value
859 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
860 * they are already different, the first value passed in is returned. Note that this method returns the new value
861 * but does not change the current string.
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
869 * @param {String} value The value to compare to the current string
870 * @param {String} other The new value to use if the string already equals the first value passed in
871 * @return {String} The new value
874 String.prototype.toggle = function(value, other){
875 return this == value ? other : value;
878 * Ext JS Library 1.1.1
879 * Copyright(c) 2006-2007, Ext JS, LLC.
881 * Originally Released Under LGPL - original licence link has changed is not relivant.
884 * <script type="text/javascript">
890 Roo.applyIf(Number.prototype, {
892 * Checks whether or not the current number is within a desired range. If the number is already within the
893 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894 * exceeded. Note that this method returns the constrained value but does not change the current number.
895 * @param {Number} min The minimum number in the range
896 * @param {Number} max The maximum number in the range
897 * @return {Number} The constrained value if outside the range, otherwise the current value
899 constrain : function(min, max){
900 return Math.min(Math.max(this, min), max);
904 * Ext JS Library 1.1.1
905 * Copyright(c) 2006-2007, Ext JS, LLC.
907 * Originally Released Under LGPL - original licence link has changed is not relivant.
910 * <script type="text/javascript">
915 Roo.applyIf(Array.prototype, {
917 * Checks whether or not the specified object exists in the array.
918 * @param {Object} o The object to check for
919 * @return {Number} The index of o in the array (or -1 if it is not found)
921 indexOf : function(o){
922 for (var i = 0, len = this.length; i < len; i++){
923 if(this[i] == o) return i;
929 * Removes the specified object from the array. If the object is not found nothing happens.
930 * @param {Object} o The object to remove
932 remove : function(o){
933 var index = this.indexOf(o);
935 this.splice(index, 1);
939 * Map (JS 1.6 compatibility)
940 * @param {Function} function to call
944 var len = this.length >>> 0;
945 if (typeof fun != "function")
946 throw new TypeError();
948 var res = new Array(len);
949 var thisp = arguments[1];
950 for (var i = 0; i < len; i++)
953 res[i] = fun.call(thisp, this[i], i, this);
964 * Ext JS Library 1.1.1
965 * Copyright(c) 2006-2007, Ext JS, LLC.
967 * Originally Released Under LGPL - original licence link has changed is not relivant.
970 * <script type="text/javascript">
976 * The date parsing and format syntax is a subset of
977 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978 * supported will provide results equivalent to their PHP versions.
980 * Following is the list of all currently supported formats:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
985 Format Output Description
986 ------ ---------- --------------------------------------------------------------
987 d 10 Day of the month, 2 digits with leading zeros
988 D Wed A textual representation of a day, three letters
989 j 10 Day of the month without leading zeros
990 l Wednesday A full textual representation of the day of the week
991 S th English ordinal day of month suffix, 2 chars (use with j)
992 w 3 Numeric representation of the day of the week
993 z 9 The julian date, or day of the year (0-365)
994 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995 F January A full textual representation of the month
996 m 01 Numeric representation of a month, with leading zeros
997 M Jan Month name abbreviation, three letters
998 n 1 Numeric representation of a month, without leading zeros
999 t 31 Number of days in the given month
1000 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1001 Y 2007 A full numeric representation of a year, 4 digits
1002 y 07 A two digit representation of a year
1003 a pm Lowercase Ante meridiem and Post meridiem
1004 A PM Uppercase Ante meridiem and Post meridiem
1005 g 3 12-hour format of an hour without leading zeros
1006 G 15 24-hour format of an hour without leading zeros
1007 h 03 12-hour format of an hour with leading zeros
1008 H 15 24-hour format of an hour with leading zeros
1009 i 05 Minutes with leading zeros
1010 s 01 Seconds, with leading zeros
1011 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1013 T CST Timezone setting of the machine running the code
1014 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1017 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d')); //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1025 * Here are some standard date/time patterns that you might find helpful. They
1026 * are not part of the source of Date.js, but to use them you can simply copy this
1027 * block of code into any script that is included after Date.js and they will also become
1028 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1031 ISO8601Long:"Y-m-d H:i:s",
1032 ISO8601Short:"Y-m-d",
1034 LongDate: "l, F d, Y",
1035 FullDateTime: "l, F d, Y g:i:s A",
1038 LongTime: "g:i:s A",
1039 SortableDateTime: "Y-m-d\\TH:i:s",
1040 UniversalSortableDateTime: "Y-m-d H:i:sO",
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1053 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054 * They generate precompiled functions from date formats instead of parsing and
1055 * processing the pattern every time you format a date. These functions are available
1056 * on every Date object (any javascript function).
1058 * The original article and download are here:
1059 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1066 Returns the number of milliseconds between this date and date
1067 @param {Date} date (optional) Defaults to now
1068 @return {Number} The diff in milliseconds
1069 @member Date getElapsed
1071 Date.prototype.getElapsed = function(date) {
1072 return Math.abs((date || new Date()).getTime()-this.getTime());
1074 // was in date file..
1078 Date.parseFunctions = {count:0};
1080 Date.parseRegexes = [];
1082 Date.formatFunctions = {count:0};
1085 Date.prototype.dateFormat = function(format) {
1086 if (Date.formatFunctions[format] == null) {
1087 Date.createNewFormat(format);
1089 var func = Date.formatFunctions[format];
1090 return this[func]();
1095 * Formats a date given the supplied format string
1096 * @param {String} format The format string
1097 * @return {String} The formatted date
1100 Date.prototype.format = Date.prototype.dateFormat;
1103 Date.createNewFormat = function(format) {
1104 var funcName = "format" + Date.formatFunctions.count++;
1105 Date.formatFunctions[format] = funcName;
1106 var code = "Date.prototype." + funcName + " = function(){return ";
1107 var special = false;
1109 for (var i = 0; i < format.length; ++i) {
1110 ch = format.charAt(i);
1111 if (!special && ch == "\\") {
1116 code += "'" + String.escape(ch) + "' + ";
1119 code += Date.getFormatCode(ch);
1122 /** eval:var:zzzzzzzzzzzzz */
1123 eval(code.substring(0, code.length - 3) + ";}");
1127 Date.getFormatCode = function(character) {
1128 switch (character) {
1130 return "String.leftPad(this.getDate(), 2, '0') + ";
1132 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1134 return "this.getDate() + ";
1136 return "Date.dayNames[this.getDay()] + ";
1138 return "this.getSuffix() + ";
1140 return "this.getDay() + ";
1142 return "this.getDayOfYear() + ";
1144 return "this.getWeekOfYear() + ";
1146 return "Date.monthNames[this.getMonth()] + ";
1148 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1150 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1152 return "(this.getMonth() + 1) + ";
1154 return "this.getDaysInMonth() + ";
1156 return "(this.isLeapYear() ? 1 : 0) + ";
1158 return "this.getFullYear() + ";
1160 return "('' + this.getFullYear()).substring(2, 4) + ";
1162 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1164 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1166 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1168 return "this.getHours() + ";
1170 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1172 return "String.leftPad(this.getHours(), 2, '0') + ";
1174 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1176 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1178 return "this.getGMTOffset() + ";
1180 return "this.getGMTColonOffset() + ";
1182 return "this.getTimezone() + ";
1184 return "(this.getTimezoneOffset() * -60) + ";
1186 return "'" + String.escape(character) + "' + ";
1191 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1193 * the date format that is not specified will default to the current date value for that part. Time parts can also
1194 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1195 * string or the parse operation will fail.
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1210 * @param {String} input The unparsed date as a string
1211 * @param {String} format The format the date is in
1212 * @return {Date} The parsed date
1215 Date.parseDate = function(input, format) {
1216 if (Date.parseFunctions[format] == null) {
1217 Date.createParser(format);
1219 var func = Date.parseFunctions[format];
1220 return Date[func](input);
1225 Date.createParser = function(format) {
1226 var funcName = "parse" + Date.parseFunctions.count++;
1227 var regexNum = Date.parseRegexes.length;
1228 var currentGroup = 1;
1229 Date.parseFunctions[format] = funcName;
1231 var code = "Date." + funcName + " = function(input){\n"
1232 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233 + "var d = new Date();\n"
1234 + "y = d.getFullYear();\n"
1235 + "m = d.getMonth();\n"
1236 + "d = d.getDate();\n"
1237 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238 + "if (results && results.length > 0) {";
1241 var special = false;
1243 for (var i = 0; i < format.length; ++i) {
1244 ch = format.charAt(i);
1245 if (!special && ch == "\\") {
1250 regex += String.escape(ch);
1253 var obj = Date.formatCodeToRegex(ch, currentGroup);
1254 currentGroup += obj.g;
1256 if (obj.g && obj.c) {
1262 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263 + "{v = new Date(y, m, d, h, i, s);}\n"
1264 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265 + "{v = new Date(y, m, d, h, i);}\n"
1266 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267 + "{v = new Date(y, m, d, h);}\n"
1268 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269 + "{v = new Date(y, m, d);}\n"
1270 + "else if (y >= 0 && m >= 0)\n"
1271 + "{v = new Date(y, m);}\n"
1272 + "else if (y >= 0)\n"
1273 + "{v = new Date(y);}\n"
1274 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1279 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280 /** eval:var:zzzzzzzzzzzzz */
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286 switch (character) {
1290 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1293 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294 s:"(\\d{1,2})"}; // day of month without leading zeroes
1297 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298 s:"(\\d{2})"}; // day of month with leading zeroes
1302 s:"(?:" + Date.dayNames.join("|") + ")"};
1306 s:"(?:st|nd|rd|th)"};
1321 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322 s:"(" + Date.monthNames.join("|") + ")"};
1325 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1329 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1333 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1345 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354 c:"if (results[" + currentGroup + "] == 'am') {\n"
1355 + "if (h == 12) { h = 0; }\n"
1356 + "} else { if (h < 12) { h += 12; }}",
1360 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361 + "if (h == 12) { h = 0; }\n"
1362 + "} else { if (h < 12) { h += 12; }}",
1367 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1372 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1376 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1385 "o = results[", currentGroup, "];\n",
1386 "var sn = o.substring(0,1);\n", // get + / - sign
1387 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1392 s:"([+\-]\\d{2,4})"};
1398 "o = results[", currentGroup, "];\n",
1399 "var sn = o.substring(0,1);\n",
1400 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401 "var mn = o.substring(4,6) % 60;\n",
1402 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1409 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1412 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418 s:String.escape(character)};
1423 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424 * @return {String} The abbreviated timezone name (e.g. 'CST')
1426 Date.prototype.getTimezone = function() {
1427 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1434 Date.prototype.getGMTOffset = function() {
1435 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442 * @return {String} 2-characters representing hours and 2-characters representing minutes
1443 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1445 Date.prototype.getGMTColonOffset = function() {
1446 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 * Get the numeric day number of the year, adjusted for leap year.
1454 * @return {Number} 0 through 364 (365 in leap years)
1456 Date.prototype.getDayOfYear = function() {
1458 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459 for (var i = 0; i < this.getMonth(); ++i) {
1460 num += Date.daysInMonth[i];
1462 return num + this.getDate() - 1;
1466 * Get the string representation of the numeric week number of the year
1467 * (equivalent to the format specifier 'W').
1468 * @return {String} '00' through '52'
1470 Date.prototype.getWeekOfYear = function() {
1471 // Skip to Thursday of this week
1472 var now = this.getDayOfYear() + (4 - this.getDay());
1473 // Find the first Thursday of the year
1474 var jan1 = new Date(this.getFullYear(), 0, 1);
1475 var then = (7 - jan1.getDay() + 4);
1476 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 * Whether or not the current date is in a leap year.
1481 * @return {Boolean} True if the current date is in a leap year, else false
1483 Date.prototype.isLeapYear = function() {
1484 var year = this.getFullYear();
1485 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 * Get the first day of the current month, adjusted for leap year. The returned value
1490 * is the numeric day index within the week (0-6) which can be used in conjunction with
1491 * the {@link #monthNames} array to retrieve the textual day name.
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1497 * @return {Number} The day number (0-6)
1499 Date.prototype.getFirstDayOfMonth = function() {
1500 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501 return (day < 0) ? (day + 7) : day;
1505 * Get the last day of the current month, adjusted for leap year. The returned value
1506 * is the numeric day index within the week (0-6) which can be used in conjunction with
1507 * the {@link #monthNames} array to retrieve the textual day name.
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1513 * @return {Number} The day number (0-6)
1515 Date.prototype.getLastDayOfMonth = function() {
1516 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517 return (day < 0) ? (day + 7) : day;
1522 * Get the first date of this date's month
1525 Date.prototype.getFirstDateOfMonth = function() {
1526 return new Date(this.getFullYear(), this.getMonth(), 1);
1530 * Get the last date of this date's month
1533 Date.prototype.getLastDateOfMonth = function() {
1534 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1537 * Get the number of days in the current month, adjusted for leap year.
1538 * @return {Number} The number of days in the month
1540 Date.prototype.getDaysInMonth = function() {
1541 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542 return Date.daysInMonth[this.getMonth()];
1546 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547 * @return {String} 'st, 'nd', 'rd' or 'th'
1549 Date.prototype.getSuffix = function() {
1550 switch (this.getDate()) {
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1570 * An array of textual month names.
1571 * Override these values for international dates, for example...
1572 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1591 * An array of textual day names.
1592 * Override these values for international dates, for example...
1593 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1609 Date.monthNumbers = {
1624 * Creates and returns a new Date instance with the exact same date value as the called instance.
1625 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626 * variable will also be changed. When the intention is to create a new variable that will not
1627 * modify the original instance, you should create a clone.
1629 * Example of correctly cloning a date:
1632 var orig = new Date('10/1/2006');
1635 document.write(orig); //returns 'Thu Oct 05 2006'!
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1641 document.write(orig); //returns 'Thu Oct 01 2006'
1643 * @return {Date} The new Date instance
1645 Date.prototype.clone = function() {
1646 return new Date(this.getTime());
1650 * Clears any time information from this date
1651 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652 @return {Date} this or the clone
1654 Date.prototype.clearTime = function(clone){
1656 return this.clone().clearTime();
1661 this.setMilliseconds(0);
1666 // safari setMonth is broken
1668 Date.brokenSetMonth = Date.prototype.setMonth;
1669 Date.prototype.setMonth = function(num){
1671 var n = Math.ceil(-num);
1672 var back_year = Math.ceil(n/12);
1673 var month = (n % 12) ? 12 - n % 12 : 0 ;
1674 this.setFullYear(this.getFullYear() - back_year);
1675 return Date.brokenSetMonth.call(this, month);
1677 return Date.brokenSetMonth.apply(this, arguments);
1682 /** Date interval constant
1686 /** Date interval constant
1690 /** Date interval constant
1694 /** Date interval constant
1698 /** Date interval constant
1702 /** Date interval constant
1706 /** Date interval constant
1712 * Provides a convenient method of performing basic date arithmetic. This method
1713 * does not modify the Date instance being called - it creates and returns
1714 * a new Date instance containing the resulting date value.
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1731 * @param {String} interval A valid date interval enum value
1732 * @param {Number} value The amount to add to the current date
1733 * @return {Date} The new Date instance
1735 Date.prototype.add = function(interval, value){
1736 var d = this.clone();
1737 if (!interval || value === 0) return d;
1738 switch(interval.toLowerCase()){
1740 d.setMilliseconds(this.getMilliseconds() + value);
1743 d.setSeconds(this.getSeconds() + value);
1746 d.setMinutes(this.getMinutes() + value);
1749 d.setHours(this.getHours() + value);
1752 d.setDate(this.getDate() + value);
1755 var day = this.getDate();
1757 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1760 d.setMonth(this.getMonth() + value);
1763 d.setFullYear(this.getFullYear() + value);
1770 * Ext JS Library 1.1.1
1771 * Copyright(c) 2006-2007, Ext JS, LLC.
1773 * Originally Released Under LGPL - original licence link has changed is not relivant.
1776 * <script type="text/javascript">
1780 * @class Roo.lib.Dom
1783 * Dom utils (from YIU afaik)
1788 * Get the view width
1789 * @param {Boolean} full True will get the full document, otherwise it's the view width
1790 * @return {Number} The width
1793 getViewWidth : function(full) {
1794 return full ? this.getDocumentWidth() : this.getViewportWidth();
1797 * Get the view height
1798 * @param {Boolean} full True will get the full document, otherwise it's the view height
1799 * @return {Number} The height
1801 getViewHeight : function(full) {
1802 return full ? this.getDocumentHeight() : this.getViewportHeight();
1805 getDocumentHeight: function() {
1806 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807 return Math.max(scrollHeight, this.getViewportHeight());
1810 getDocumentWidth: function() {
1811 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812 return Math.max(scrollWidth, this.getViewportWidth());
1815 getViewportHeight: function() {
1816 var height = self.innerHeight;
1817 var mode = document.compatMode;
1819 if ((mode || Roo.isIE) && !Roo.isOpera) {
1820 height = (mode == "CSS1Compat") ?
1821 document.documentElement.clientHeight :
1822 document.body.clientHeight;
1828 getViewportWidth: function() {
1829 var width = self.innerWidth;
1830 var mode = document.compatMode;
1832 if (mode || Roo.isIE) {
1833 width = (mode == "CSS1Compat") ?
1834 document.documentElement.clientWidth :
1835 document.body.clientWidth;
1840 isAncestor : function(p, c) {
1847 if (p.contains && !Roo.isSafari) {
1848 return p.contains(c);
1849 } else if (p.compareDocumentPosition) {
1850 return !!(p.compareDocumentPosition(c) & 16);
1852 var parent = c.parentNode;
1857 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1860 parent = parent.parentNode;
1866 getRegion : function(el) {
1867 return Roo.lib.Region.getRegion(el);
1870 getY : function(el) {
1871 return this.getXY(el)[1];
1874 getX : function(el) {
1875 return this.getXY(el)[0];
1878 getXY : function(el) {
1879 var p, pe, b, scroll, bd = document.body;
1880 el = Roo.getDom(el);
1881 var fly = Roo.lib.AnimBase.fly;
1882 if (el.getBoundingClientRect) {
1883 b = el.getBoundingClientRect();
1884 scroll = fly(document).getScroll();
1885 return [b.left + scroll.left, b.top + scroll.top];
1891 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1898 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1905 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1913 if (p != el && pe.getStyle('overflow') != 'visible') {
1921 if (Roo.isSafari && hasAbsolute) {
1926 if (Roo.isGecko && !hasAbsolute) {
1928 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933 while (p && p != bd) {
1934 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1946 setXY : function(el, xy) {
1947 el = Roo.fly(el, '_setXY');
1949 var pts = el.translatePoints(xy);
1950 if (xy[0] !== false) {
1951 el.dom.style.left = pts.left + "px";
1953 if (xy[1] !== false) {
1954 el.dom.style.top = pts.top + "px";
1958 setX : function(el, x) {
1959 this.setXY(el, [x, false]);
1962 setY : function(el, y) {
1963 this.setXY(el, [false, y]);
1967 * Portions of this file are based on pieces of Yahoo User Interface Library
1968 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969 * YUI licensed under the BSD License:
1970 * http://developer.yahoo.net/yui/license.txt
1971 * <script type="text/javascript">
1975 Roo.lib.Event = function() {
1976 var loadComplete = false;
1978 var unloadListeners = [];
1980 var onAvailStack = [];
1982 var lastError = null;
1995 startInterval: function() {
1996 if (!this._interval) {
1998 var callback = function() {
1999 self._tryPreloadAttach();
2001 this._interval = setInterval(callback, this.POLL_INTERVAL);
2006 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007 onAvailStack.push({ id: p_id,
2010 override: p_override,
2011 checkReady: false });
2013 retryCount = this.POLL_RETRYS;
2014 this.startInterval();
2018 addListener: function(el, eventName, fn) {
2019 el = Roo.getDom(el);
2024 if ("unload" == eventName) {
2025 unloadListeners[unloadListeners.length] =
2026 [el, eventName, fn];
2030 var wrappedFn = function(e) {
2031 return fn(Roo.lib.Event.getEvent(e));
2034 var li = [el, eventName, fn, wrappedFn];
2036 var index = listeners.length;
2037 listeners[index] = li;
2039 this.doAdd(el, eventName, wrappedFn, false);
2045 removeListener: function(el, eventName, fn) {
2048 el = Roo.getDom(el);
2051 return this.purgeElement(el, false, eventName);
2055 if ("unload" == eventName) {
2057 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058 var li = unloadListeners[i];
2061 li[1] == eventName &&
2063 unloadListeners.splice(i, 1);
2071 var cacheItem = null;
2074 var index = arguments[3];
2076 if ("undefined" == typeof index) {
2077 index = this._getCacheIndex(el, eventName, fn);
2081 cacheItem = listeners[index];
2084 if (!el || !cacheItem) {
2088 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2090 delete listeners[index][this.WFN];
2091 delete listeners[index][this.FN];
2092 listeners.splice(index, 1);
2099 getTarget: function(ev, resolveTextNode) {
2100 ev = ev.browserEvent || ev;
2101 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2102 var t = ev.target || ev.srcElement;
2103 return this.resolveTextNode(t);
2107 resolveTextNode: function(node) {
2108 if (Roo.isSafari && node && 3 == node.nodeType) {
2109 return node.parentNode;
2116 getPageX: function(ev) {
2117 ev = ev.browserEvent || ev;
2118 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2120 if (!x && 0 !== x) {
2121 x = ev.clientX || 0;
2124 x += this.getScroll()[1];
2132 getPageY: function(ev) {
2133 ev = ev.browserEvent || ev;
2134 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2136 if (!y && 0 !== y) {
2137 y = ev.clientY || 0;
2140 y += this.getScroll()[0];
2149 getXY: function(ev) {
2150 ev = ev.browserEvent || ev;
2151 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2152 return [this.getPageX(ev), this.getPageY(ev)];
2156 getRelatedTarget: function(ev) {
2157 ev = ev.browserEvent || ev;
2158 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2159 var t = ev.relatedTarget;
2161 if (ev.type == "mouseout") {
2163 } else if (ev.type == "mouseover") {
2168 return this.resolveTextNode(t);
2172 getTime: function(ev) {
2173 ev = ev.browserEvent || ev;
2174 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2176 var t = new Date().getTime();
2180 this.lastError = ex;
2189 stopEvent: function(ev) {
2190 this.stopPropagation(ev);
2191 this.preventDefault(ev);
2195 stopPropagation: function(ev) {
2196 ev = ev.browserEvent || ev;
2197 if (ev.stopPropagation) {
2198 ev.stopPropagation();
2200 ev.cancelBubble = true;
2205 preventDefault: function(ev) {
2206 ev = ev.browserEvent || ev;
2207 if(ev.preventDefault) {
2208 ev.preventDefault();
2210 ev.returnValue = false;
2215 getEvent: function(e) {
2216 var ev = e || window.event;
2218 var c = this.getEvent.caller;
2220 ev = c.arguments[0];
2221 if (ev && Event == ev.constructor) {
2231 getCharCode: function(ev) {
2232 ev = ev.browserEvent || ev;
2233 return ev.charCode || ev.keyCode || 0;
2237 _getCacheIndex: function(el, eventName, fn) {
2238 for (var i = 0,len = listeners.length; i < len; ++i) {
2239 var li = listeners[i];
2241 li[this.FN] == fn &&
2242 li[this.EL] == el &&
2243 li[this.TYPE] == eventName) {
2255 getEl: function(id) {
2256 return document.getElementById(id);
2260 clearCache: function() {
2264 _load: function(e) {
2265 loadComplete = true;
2266 var EU = Roo.lib.Event;
2270 EU.doRemove(window, "load", EU._load);
2275 _tryPreloadAttach: function() {
2284 var tryAgain = !loadComplete;
2286 tryAgain = (retryCount > 0);
2291 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292 var item = onAvailStack[i];
2294 var el = this.getEl(item.id);
2297 if (!item.checkReady ||
2300 (document && document.body)) {
2303 if (item.override) {
2304 if (item.override === true) {
2307 scope = item.override;
2310 item.fn.call(scope, item.obj);
2311 onAvailStack[i] = null;
2314 notAvail.push(item);
2319 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323 this.startInterval();
2325 clearInterval(this._interval);
2326 this._interval = null;
2329 this.locked = false;
2336 purgeElement: function(el, recurse, eventName) {
2337 var elListeners = this.getListeners(el, eventName);
2339 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340 var l = elListeners[i];
2341 this.removeListener(el, l.type, l.fn);
2345 if (recurse && el && el.childNodes) {
2346 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347 this.purgeElement(el.childNodes[i], recurse, eventName);
2353 getListeners: function(el, eventName) {
2354 var results = [], searchLists;
2356 searchLists = [listeners, unloadListeners];
2357 } else if (eventName == "unload") {
2358 searchLists = [unloadListeners];
2360 searchLists = [listeners];
2363 for (var j = 0; j < searchLists.length; ++j) {
2364 var searchList = searchLists[j];
2365 if (searchList && searchList.length > 0) {
2366 for (var i = 0,len = searchList.length; i < len; ++i) {
2367 var l = searchList[i];
2368 if (l && l[this.EL] === el &&
2369 (!eventName || eventName === l[this.TYPE])) {
2374 adjust: l[this.ADJ_SCOPE],
2382 return (results.length) ? results : null;
2386 _unload: function(e) {
2388 var EU = Roo.lib.Event, i, j, l, len, index;
2390 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391 l = unloadListeners[i];
2394 if (l[EU.ADJ_SCOPE]) {
2395 if (l[EU.ADJ_SCOPE] === true) {
2398 scope = l[EU.ADJ_SCOPE];
2401 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402 unloadListeners[i] = null;
2408 unloadListeners = null;
2410 if (listeners && listeners.length > 0) {
2411 j = listeners.length;
2414 l = listeners[index];
2416 EU.removeListener(l[EU.EL], l[EU.TYPE],
2426 EU.doRemove(window, "unload", EU._unload);
2431 getScroll: function() {
2432 var dd = document.documentElement, db = document.body;
2433 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434 return [dd.scrollTop, dd.scrollLeft];
2436 return [db.scrollTop, db.scrollLeft];
2443 doAdd: function () {
2444 if (window.addEventListener) {
2445 return function(el, eventName, fn, capture) {
2446 el.addEventListener(eventName, fn, (capture));
2448 } else if (window.attachEvent) {
2449 return function(el, eventName, fn, capture) {
2450 el.attachEvent("on" + eventName, fn);
2459 doRemove: function() {
2460 if (window.removeEventListener) {
2461 return function (el, eventName, fn, capture) {
2462 el.removeEventListener(eventName, fn, (capture));
2464 } else if (window.detachEvent) {
2465 return function (el, eventName, fn) {
2466 el.detachEvent("on" + eventName, fn);
2478 var E = Roo.lib.Event;
2479 E.on = E.addListener;
2480 E.un = E.removeListener;
2482 if (document && document.body) {
2485 E.doAdd(window, "load", E._load);
2487 E.doAdd(window, "unload", E._unload);
2488 E._tryPreloadAttach();
2492 * Portions of this file are based on pieces of Yahoo User Interface Library
2493 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494 * YUI licensed under the BSD License:
2495 * http://developer.yahoo.net/yui/license.txt
2496 * <script type="text/javascript">
2502 * @class Roo.lib.Ajax
2509 request : function(method, uri, cb, data, options) {
2511 var hs = options.headers;
2514 if(hs.hasOwnProperty(h)){
2515 this.initHeader(h, hs[h], false);
2519 if(options.xmlData){
2520 this.initHeader('Content-Type', 'text/xml', false);
2522 data = options.xmlData;
2526 return this.asyncRequest(method, uri, cb, data);
2529 serializeForm : function(form) {
2530 if(typeof form == 'string') {
2531 form = (document.getElementById(form) || document.forms[form]);
2534 var el, name, val, disabled, data = '', hasSubmit = false;
2535 for (var i = 0; i < form.elements.length; i++) {
2536 el = form.elements[i];
2537 disabled = form.elements[i].disabled;
2538 name = form.elements[i].name;
2539 val = form.elements[i].value;
2541 if (!disabled && name){
2545 case 'select-multiple':
2546 for (var j = 0; j < el.options.length; j++) {
2547 if (el.options[j].selected) {
2549 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2552 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2560 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573 if(hasSubmit == false) {
2574 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2579 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584 data = data.substr(0, data.length - 1);
2592 useDefaultHeader:true,
2594 defaultPostHeader:'application/x-www-form-urlencoded',
2596 useDefaultXhrHeader:true,
2598 defaultXhrHeader:'XMLHttpRequest',
2600 hasDefaultHeaders:true,
2612 setProgId:function(id)
2614 this.activeX.unshift(id);
2617 setDefaultPostHeader:function(b)
2619 this.useDefaultHeader = b;
2622 setDefaultXhrHeader:function(b)
2624 this.useDefaultXhrHeader = b;
2627 setPollingInterval:function(i)
2629 if (typeof i == 'number' && isFinite(i)) {
2630 this.pollInterval = i;
2634 createXhrObject:function(transactionId)
2640 http = new XMLHttpRequest();
2642 obj = { conn:http, tId:transactionId };
2646 for (var i = 0; i < this.activeX.length; ++i) {
2650 http = new ActiveXObject(this.activeX[i]);
2652 obj = { conn:http, tId:transactionId };
2665 getConnectionObject:function()
2668 var tId = this.transactionId;
2672 o = this.createXhrObject(tId);
2674 this.transactionId++;
2685 asyncRequest:function(method, uri, callback, postData)
2687 var o = this.getConnectionObject();
2693 o.conn.open(method, uri, true);
2695 if (this.useDefaultXhrHeader) {
2696 if (!this.defaultHeaders['X-Requested-With']) {
2697 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701 if(postData && this.useDefaultHeader){
2702 this.initHeader('Content-Type', this.defaultPostHeader);
2705 if (this.hasDefaultHeaders || this.hasHeaders) {
2709 this.handleReadyState(o, callback);
2710 o.conn.send(postData || null);
2716 handleReadyState:function(o, callback)
2720 if (callback && callback.timeout) {
2722 this.timeout[o.tId] = window.setTimeout(function() {
2723 oConn.abort(o, callback, true);
2724 }, callback.timeout);
2727 this.poll[o.tId] = window.setInterval(
2729 if (o.conn && o.conn.readyState == 4) {
2730 window.clearInterval(oConn.poll[o.tId]);
2731 delete oConn.poll[o.tId];
2733 if(callback && callback.timeout) {
2734 window.clearTimeout(oConn.timeout[o.tId]);
2735 delete oConn.timeout[o.tId];
2738 oConn.handleTransactionResponse(o, callback);
2741 , this.pollInterval);
2744 handleTransactionResponse:function(o, callback, isAbort)
2748 this.releaseObject(o);
2752 var httpStatus, responseObject;
2756 if (o.conn.status !== undefined && o.conn.status != 0) {
2757 httpStatus = o.conn.status;
2769 if (httpStatus >= 200 && httpStatus < 300) {
2770 responseObject = this.createResponseObject(o, callback.argument);
2771 if (callback.success) {
2772 if (!callback.scope) {
2773 callback.success(responseObject);
2778 callback.success.apply(callback.scope, [responseObject]);
2783 switch (httpStatus) {
2791 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792 if (callback.failure) {
2793 if (!callback.scope) {
2794 callback.failure(responseObject);
2797 callback.failure.apply(callback.scope, [responseObject]);
2802 responseObject = this.createResponseObject(o, callback.argument);
2803 if (callback.failure) {
2804 if (!callback.scope) {
2805 callback.failure(responseObject);
2808 callback.failure.apply(callback.scope, [responseObject]);
2814 this.releaseObject(o);
2815 responseObject = null;
2818 createResponseObject:function(o, callbackArg)
2825 var headerStr = o.conn.getAllResponseHeaders();
2826 var header = headerStr.split('\n');
2827 for (var i = 0; i < header.length; i++) {
2828 var delimitPos = header[i].indexOf(':');
2829 if (delimitPos != -1) {
2830 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2838 obj.status = o.conn.status;
2839 obj.statusText = o.conn.statusText;
2840 obj.getResponseHeader = headerObj;
2841 obj.getAllResponseHeaders = headerStr;
2842 obj.responseText = o.conn.responseText;
2843 obj.responseXML = o.conn.responseXML;
2845 if (typeof callbackArg !== undefined) {
2846 obj.argument = callbackArg;
2852 createExceptionObject:function(tId, callbackArg, isAbort)
2855 var COMM_ERROR = 'communication failure';
2856 var ABORT_CODE = -1;
2857 var ABORT_ERROR = 'transaction aborted';
2863 obj.status = ABORT_CODE;
2864 obj.statusText = ABORT_ERROR;
2867 obj.status = COMM_CODE;
2868 obj.statusText = COMM_ERROR;
2872 obj.argument = callbackArg;
2878 initHeader:function(label, value, isDefault)
2880 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2882 if (headerObj[label] === undefined) {
2883 headerObj[label] = value;
2888 headerObj[label] = value + "," + headerObj[label];
2892 this.hasDefaultHeaders = true;
2895 this.hasHeaders = true;
2900 setHeader:function(o)
2902 if (this.hasDefaultHeaders) {
2903 for (var prop in this.defaultHeaders) {
2904 if (this.defaultHeaders.hasOwnProperty(prop)) {
2905 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2910 if (this.hasHeaders) {
2911 for (var prop in this.headers) {
2912 if (this.headers.hasOwnProperty(prop)) {
2913 o.conn.setRequestHeader(prop, this.headers[prop]);
2917 this.hasHeaders = false;
2921 resetDefaultHeaders:function() {
2922 delete this.defaultHeaders;
2923 this.defaultHeaders = {};
2924 this.hasDefaultHeaders = false;
2927 abort:function(o, callback, isTimeout)
2929 if(this.isCallInProgress(o)) {
2931 window.clearInterval(this.poll[o.tId]);
2932 delete this.poll[o.tId];
2934 delete this.timeout[o.tId];
2937 this.handleTransactionResponse(o, callback, true);
2947 isCallInProgress:function(o)
2950 return o.conn.readyState != 4 && o.conn.readyState != 0;
2959 releaseObject:function(o)
2968 'MSXML2.XMLHTTP.3.0',
2976 * Portions of this file are based on pieces of Yahoo User Interface Library
2977 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978 * YUI licensed under the BSD License:
2979 * http://developer.yahoo.net/yui/license.txt
2980 * <script type="text/javascript">
2984 Roo.lib.Region = function(t, r, b, l) {
2994 Roo.lib.Region.prototype = {
2995 contains : function(region) {
2996 return ( region.left >= this.left &&
2997 region.right <= this.right &&
2998 region.top >= this.top &&
2999 region.bottom <= this.bottom );
3003 getArea : function() {
3004 return ( (this.bottom - this.top) * (this.right - this.left) );
3007 intersect : function(region) {
3008 var t = Math.max(this.top, region.top);
3009 var r = Math.min(this.right, region.right);
3010 var b = Math.min(this.bottom, region.bottom);
3011 var l = Math.max(this.left, region.left);
3013 if (b >= t && r >= l) {
3014 return new Roo.lib.Region(t, r, b, l);
3019 union : function(region) {
3020 var t = Math.min(this.top, region.top);
3021 var r = Math.max(this.right, region.right);
3022 var b = Math.max(this.bottom, region.bottom);
3023 var l = Math.min(this.left, region.left);
3025 return new Roo.lib.Region(t, r, b, l);
3028 adjust : function(t, l, b, r) {
3037 Roo.lib.Region.getRegion = function(el) {
3038 var p = Roo.lib.Dom.getXY(el);
3041 var r = p[0] + el.offsetWidth;
3042 var b = p[1] + el.offsetHeight;
3045 return new Roo.lib.Region(t, r, b, l);
3048 * Portions of this file are based on pieces of Yahoo User Interface Library
3049 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050 * YUI licensed under the BSD License:
3051 * http://developer.yahoo.net/yui/license.txt
3052 * <script type="text/javascript">
3055 //@@dep Roo.lib.Region
3058 Roo.lib.Point = function(x, y) {
3059 if (x instanceof Array) {
3063 this.x = this.right = this.left = this[0] = x;
3064 this.y = this.top = this.bottom = this[1] = y;
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3069 * Portions of this file are based on pieces of Yahoo User Interface Library
3070 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071 * YUI licensed under the BSD License:
3072 * http://developer.yahoo.net/yui/license.txt
3073 * <script type="text/javascript">
3080 scroll : function(el, args, duration, easing, cb, scope) {
3081 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3084 motion : function(el, args, duration, easing, cb, scope) {
3085 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3088 color : function(el, args, duration, easing, cb, scope) {
3089 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3092 run : function(el, args, duration, easing, cb, scope, type) {
3093 type = type || Roo.lib.AnimBase;
3094 if (typeof easing == "string") {
3095 easing = Roo.lib.Easing[easing];
3097 var anim = new type(el, args, duration, easing);
3098 anim.animateX(function() {
3099 Roo.callback(cb, scope);
3105 * Portions of this file are based on pieces of Yahoo User Interface Library
3106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107 * YUI licensed under the BSD License:
3108 * http://developer.yahoo.net/yui/license.txt
3109 * <script type="text/javascript">
3117 if (!libFlyweight) {
3118 libFlyweight = new Roo.Element.Flyweight();
3120 libFlyweight.dom = el;
3121 return libFlyweight;
3124 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3130 this.init(el, attributes, duration, method);
3134 Roo.lib.AnimBase.fly = fly;
3138 Roo.lib.AnimBase.prototype = {
3140 toString: function() {
3141 var el = this.getEl();
3142 var id = el.id || el.tagName;
3143 return ("Anim " + id);
3147 noNegatives: /width|height|opacity|padding/i,
3148 offsetAttribute: /^((width|height)|(top|left))$/,
3149 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3150 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154 doMethod: function(attr, start, end) {
3155 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159 setAttribute: function(attr, val, unit) {
3160 if (this.patterns.noNegatives.test(attr)) {
3161 val = (val > 0) ? val : 0;
3164 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168 getAttribute: function(attr) {
3169 var el = this.getEl();
3170 var val = fly(el).getStyle(attr);
3172 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173 return parseFloat(val);
3176 var a = this.patterns.offsetAttribute.exec(attr) || [];
3177 var pos = !!( a[3] );
3178 var box = !!( a[2] );
3181 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3191 getDefaultUnit: function(attr) {
3192 if (this.patterns.defaultUnit.test(attr)) {
3199 animateX : function(callback, scope) {
3200 var f = function() {
3201 this.onComplete.removeListener(f);
3202 if (typeof callback == "function") {
3203 callback.call(scope || this, this);
3206 this.onComplete.addListener(f, this);
3211 setRuntimeAttribute: function(attr) {
3214 var attributes = this.attributes;
3216 this.runtimeAttributes[attr] = {};
3218 var isset = function(prop) {
3219 return (typeof prop !== 'undefined');
3222 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3229 if (isset(attributes[attr]['to'])) {
3230 end = attributes[attr]['to'];
3231 } else if (isset(attributes[attr]['by'])) {
3232 if (start.constructor == Array) {
3234 for (var i = 0, len = start.length; i < len; ++i) {
3235 end[i] = start[i] + attributes[attr]['by'][i];
3238 end = start + attributes[attr]['by'];
3242 this.runtimeAttributes[attr].start = start;
3243 this.runtimeAttributes[attr].end = end;
3246 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250 init: function(el, attributes, duration, method) {
3252 var isAnimated = false;
3255 var startTime = null;
3258 var actualFrames = 0;
3261 el = Roo.getDom(el);
3264 this.attributes = attributes || {};
3267 this.duration = duration || 1;
3270 this.method = method || Roo.lib.Easing.easeNone;
3273 this.useSeconds = true;
3276 this.currentFrame = 0;
3279 this.totalFrames = Roo.lib.AnimMgr.fps;
3282 this.getEl = function() {
3287 this.isAnimated = function() {
3292 this.getStartTime = function() {
3296 this.runtimeAttributes = {};
3299 this.animate = function() {
3300 if (this.isAnimated()) {
3304 this.currentFrame = 0;
3306 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3308 Roo.lib.AnimMgr.registerElement(this);
3312 this.stop = function(finish) {
3314 this.currentFrame = this.totalFrames;
3315 this._onTween.fire();
3317 Roo.lib.AnimMgr.stop(this);
3320 var onStart = function() {
3321 this.onStart.fire();
3323 this.runtimeAttributes = {};
3324 for (var attr in this.attributes) {
3325 this.setRuntimeAttribute(attr);
3330 startTime = new Date();
3334 var onTween = function() {
3336 duration: new Date() - this.getStartTime(),
3337 currentFrame: this.currentFrame
3340 data.toString = function() {
3342 'duration: ' + data.duration +
3343 ', currentFrame: ' + data.currentFrame
3347 this.onTween.fire(data);
3349 var runtimeAttributes = this.runtimeAttributes;
3351 for (var attr in runtimeAttributes) {
3352 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3358 var onComplete = function() {
3359 var actual_duration = (new Date() - startTime) / 1000 ;
3362 duration: actual_duration,
3363 frames: actualFrames,
3364 fps: actualFrames / actual_duration
3367 data.toString = function() {
3369 'duration: ' + data.duration +
3370 ', frames: ' + data.frames +
3371 ', fps: ' + data.fps
3377 this.onComplete.fire(data);
3381 this._onStart = new Roo.util.Event(this);
3382 this.onStart = new Roo.util.Event(this);
3383 this.onTween = new Roo.util.Event(this);
3384 this._onTween = new Roo.util.Event(this);
3385 this.onComplete = new Roo.util.Event(this);
3386 this._onComplete = new Roo.util.Event(this);
3387 this._onStart.addListener(onStart);
3388 this._onTween.addListener(onTween);
3389 this._onComplete.addListener(onComplete);
3394 * Portions of this file are based on pieces of Yahoo User Interface Library
3395 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396 * YUI licensed under the BSD License:
3397 * http://developer.yahoo.net/yui/license.txt
3398 * <script type="text/javascript">
3402 Roo.lib.AnimMgr = new function() {
3419 this.registerElement = function(tween) {
3420 queue[queue.length] = tween;
3422 tween._onStart.fire();
3427 this.unRegister = function(tween, index) {
3428 tween._onComplete.fire();
3429 index = index || getIndex(tween);
3431 queue.splice(index, 1);
3435 if (tweenCount <= 0) {
3441 this.start = function() {
3442 if (thread === null) {
3443 thread = setInterval(this.run, this.delay);
3448 this.stop = function(tween) {
3450 clearInterval(thread);
3452 for (var i = 0, len = queue.length; i < len; ++i) {
3453 if (queue[0].isAnimated()) {
3454 this.unRegister(queue[0], 0);
3463 this.unRegister(tween);
3468 this.run = function() {
3469 for (var i = 0, len = queue.length; i < len; ++i) {
3470 var tween = queue[i];
3471 if (!tween || !tween.isAnimated()) {
3475 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3477 tween.currentFrame += 1;
3479 if (tween.useSeconds) {
3480 correctFrame(tween);
3482 tween._onTween.fire();
3485 Roo.lib.AnimMgr.stop(tween, i);
3490 var getIndex = function(anim) {
3491 for (var i = 0, len = queue.length; i < len; ++i) {
3492 if (queue[i] == anim) {
3500 var correctFrame = function(tween) {
3501 var frames = tween.totalFrames;
3502 var frame = tween.currentFrame;
3503 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504 var elapsed = (new Date() - tween.getStartTime());
3507 if (elapsed < tween.duration * 1000) {
3508 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3510 tweak = frames - (frame + 1);
3512 if (tweak > 0 && isFinite(tweak)) {
3513 if (tween.currentFrame + tweak >= frames) {
3514 tweak = frames - (frame + 1);
3517 tween.currentFrame += tweak;
3523 * Portions of this file are based on pieces of Yahoo User Interface Library
3524 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525 * YUI licensed under the BSD License:
3526 * http://developer.yahoo.net/yui/license.txt
3527 * <script type="text/javascript">
3530 Roo.lib.Bezier = new function() {
3532 this.getPosition = function(points, t) {
3533 var n = points.length;
3536 for (var i = 0; i < n; ++i) {
3537 tmp[i] = [points[i][0], points[i][1]];
3540 for (var j = 1; j < n; ++j) {
3541 for (i = 0; i < n - j; ++i) {
3542 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547 return [ tmp[0][0], tmp[0][1] ];
3551 * Portions of this file are based on pieces of Yahoo User Interface Library
3552 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553 * YUI licensed under the BSD License:
3554 * http://developer.yahoo.net/yui/license.txt
3555 * <script type="text/javascript">
3560 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3564 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3566 var fly = Roo.lib.AnimBase.fly;
3568 var superclass = Y.ColorAnim.superclass;
3569 var proto = Y.ColorAnim.prototype;
3571 proto.toString = function() {
3572 var el = this.getEl();
3573 var id = el.id || el.tagName;
3574 return ("ColorAnim " + id);
3577 proto.patterns.color = /color$/i;
3578 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3584 proto.parseColor = function(s) {
3585 if (s.length == 3) {
3589 var c = this.patterns.hex.exec(s);
3590 if (c && c.length == 4) {
3591 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3594 c = this.patterns.rgb.exec(s);
3595 if (c && c.length == 4) {
3596 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3599 c = this.patterns.hex3.exec(s);
3600 if (c && c.length == 4) {
3601 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3606 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607 proto.getAttribute = function(attr) {
3608 var el = this.getEl();
3609 if (this.patterns.color.test(attr)) {
3610 var val = fly(el).getStyle(attr);
3612 if (this.patterns.transparent.test(val)) {
3613 var parent = el.parentNode;
3614 val = fly(parent).getStyle(attr);
3616 while (parent && this.patterns.transparent.test(val)) {
3617 parent = parent.parentNode;
3618 val = fly(parent).getStyle(attr);
3619 if (parent.tagName.toUpperCase() == 'HTML') {
3625 val = superclass.getAttribute.call(this, attr);
3630 proto.getAttribute = function(attr) {
3631 var el = this.getEl();
3632 if (this.patterns.color.test(attr)) {
3633 var val = fly(el).getStyle(attr);
3635 if (this.patterns.transparent.test(val)) {
3636 var parent = el.parentNode;
3637 val = fly(parent).getStyle(attr);
3639 while (parent && this.patterns.transparent.test(val)) {
3640 parent = parent.parentNode;
3641 val = fly(parent).getStyle(attr);
3642 if (parent.tagName.toUpperCase() == 'HTML') {
3648 val = superclass.getAttribute.call(this, attr);
3654 proto.doMethod = function(attr, start, end) {
3657 if (this.patterns.color.test(attr)) {
3659 for (var i = 0, len = start.length; i < len; ++i) {
3660 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3663 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3666 val = superclass.doMethod.call(this, attr, start, end);
3672 proto.setRuntimeAttribute = function(attr) {
3673 superclass.setRuntimeAttribute.call(this, attr);
3675 if (this.patterns.color.test(attr)) {
3676 var attributes = this.attributes;
3677 var start = this.parseColor(this.runtimeAttributes[attr].start);
3678 var end = this.parseColor(this.runtimeAttributes[attr].end);
3680 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681 end = this.parseColor(attributes[attr].by);
3683 for (var i = 0, len = start.length; i < len; ++i) {
3684 end[i] = start[i] + end[i];
3688 this.runtimeAttributes[attr].start = start;
3689 this.runtimeAttributes[attr].end = end;
3695 * Portions of this file are based on pieces of Yahoo User Interface Library
3696 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697 * YUI licensed under the BSD License:
3698 * http://developer.yahoo.net/yui/license.txt
3699 * <script type="text/javascript">
3705 easeNone: function (t, b, c, d) {
3706 return c * t / d + b;
3710 easeIn: function (t, b, c, d) {
3711 return c * (t /= d) * t + b;
3715 easeOut: function (t, b, c, d) {
3716 return -c * (t /= d) * (t - 2) + b;
3720 easeBoth: function (t, b, c, d) {
3721 if ((t /= d / 2) < 1) {
3722 return c / 2 * t * t + b;
3725 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729 easeInStrong: function (t, b, c, d) {
3730 return c * (t /= d) * t * t * t + b;
3734 easeOutStrong: function (t, b, c, d) {
3735 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739 easeBothStrong: function (t, b, c, d) {
3740 if ((t /= d / 2) < 1) {
3741 return c / 2 * t * t * t * t + b;
3744 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3749 elasticIn: function (t, b, c, d, a, p) {
3753 if ((t /= d) == 1) {
3760 if (!a || a < Math.abs(c)) {
3765 var s = p / (2 * Math.PI) * Math.asin(c / a);
3768 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772 elasticOut: function (t, b, c, d, a, p) {
3776 if ((t /= d) == 1) {
3783 if (!a || a < Math.abs(c)) {
3788 var s = p / (2 * Math.PI) * Math.asin(c / a);
3791 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795 elasticBoth: function (t, b, c, d, a, p) {
3800 if ((t /= d / 2) == 2) {
3808 if (!a || a < Math.abs(c)) {
3813 var s = p / (2 * Math.PI) * Math.asin(c / a);
3817 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3820 return a * Math.pow(2, -10 * (t -= 1)) *
3821 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3826 backIn: function (t, b, c, d, s) {
3827 if (typeof s == 'undefined') {
3830 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834 backOut: function (t, b, c, d, s) {
3835 if (typeof s == 'undefined') {
3838 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842 backBoth: function (t, b, c, d, s) {
3843 if (typeof s == 'undefined') {
3847 if ((t /= d / 2 ) < 1) {
3848 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3850 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854 bounceIn: function (t, b, c, d) {
3855 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859 bounceOut: function (t, b, c, d) {
3860 if ((t /= d) < (1 / 2.75)) {
3861 return c * (7.5625 * t * t) + b;
3862 } else if (t < (2 / 2.75)) {
3863 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864 } else if (t < (2.5 / 2.75)) {
3865 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3867 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871 bounceBoth: function (t, b, c, d) {
3873 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3875 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3878 * Portions of this file are based on pieces of Yahoo User Interface Library
3879 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880 * YUI licensed under the BSD License:
3881 * http://developer.yahoo.net/yui/license.txt
3882 * <script type="text/javascript">
3886 Roo.lib.Motion = function(el, attributes, duration, method) {
3888 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896 var superclass = Y.Motion.superclass;
3897 var proto = Y.Motion.prototype;
3899 proto.toString = function() {
3900 var el = this.getEl();
3901 var id = el.id || el.tagName;
3902 return ("Motion " + id);
3905 proto.patterns.points = /^points$/i;
3907 proto.setAttribute = function(attr, val, unit) {
3908 if (this.patterns.points.test(attr)) {
3909 unit = unit || 'px';
3910 superclass.setAttribute.call(this, 'left', val[0], unit);
3911 superclass.setAttribute.call(this, 'top', val[1], unit);
3913 superclass.setAttribute.call(this, attr, val, unit);
3917 proto.getAttribute = function(attr) {
3918 if (this.patterns.points.test(attr)) {
3920 superclass.getAttribute.call(this, 'left'),
3921 superclass.getAttribute.call(this, 'top')
3924 val = superclass.getAttribute.call(this, attr);
3930 proto.doMethod = function(attr, start, end) {
3933 if (this.patterns.points.test(attr)) {
3934 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3937 val = superclass.doMethod.call(this, attr, start, end);
3942 proto.setRuntimeAttribute = function(attr) {
3943 if (this.patterns.points.test(attr)) {
3944 var el = this.getEl();
3945 var attributes = this.attributes;
3947 var control = attributes['points']['control'] || [];
3951 if (control.length > 0 && !(control[0] instanceof Array)) {
3952 control = [control];
3955 for (i = 0,len = control.length; i < len; ++i) {
3956 tmp[i] = control[i];
3961 Roo.fly(el).position();
3963 if (isset(attributes['points']['from'])) {
3964 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3967 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3970 start = this.getAttribute('points');
3973 if (isset(attributes['points']['to'])) {
3974 end = translateValues.call(this, attributes['points']['to'], start);
3976 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977 for (i = 0,len = control.length; i < len; ++i) {
3978 control[i] = translateValues.call(this, control[i], start);
3982 } else if (isset(attributes['points']['by'])) {
3983 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3985 for (i = 0,len = control.length; i < len; ++i) {
3986 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990 this.runtimeAttributes[attr] = [start];
3992 if (control.length > 0) {
3993 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3996 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3999 superclass.setRuntimeAttribute.call(this, attr);
4003 var translateValues = function(val, start) {
4004 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4010 var isset = function(prop) {
4011 return (typeof prop !== 'undefined');
4015 * Portions of this file are based on pieces of Yahoo User Interface Library
4016 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017 * YUI licensed under the BSD License:
4018 * http://developer.yahoo.net/yui/license.txt
4019 * <script type="text/javascript">
4023 Roo.lib.Scroll = function(el, attributes, duration, method) {
4025 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033 var superclass = Y.Scroll.superclass;
4034 var proto = Y.Scroll.prototype;
4036 proto.toString = function() {
4037 var el = this.getEl();
4038 var id = el.id || el.tagName;
4039 return ("Scroll " + id);
4042 proto.doMethod = function(attr, start, end) {
4045 if (attr == 'scroll') {
4047 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052 val = superclass.doMethod.call(this, attr, start, end);
4057 proto.getAttribute = function(attr) {
4059 var el = this.getEl();
4061 if (attr == 'scroll') {
4062 val = [ el.scrollLeft, el.scrollTop ];
4064 val = superclass.getAttribute.call(this, attr);
4070 proto.setAttribute = function(attr, val, unit) {
4071 var el = this.getEl();
4073 if (attr == 'scroll') {
4074 el.scrollLeft = val[0];
4075 el.scrollTop = val[1];
4077 superclass.setAttribute.call(this, attr, val, unit);
4083 * Ext JS Library 1.1.1
4084 * Copyright(c) 2006-2007, Ext JS, LLC.
4086 * Originally Released Under LGPL - original licence link has changed is not relivant.
4089 * <script type="text/javascript">
4093 // nasty IE9 hack - what a pile of crap that is..
4095 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096 Range.prototype.createContextualFragment = function (html) {
4097 var doc = window.document;
4098 var container = doc.createElement("div");
4099 container.innerHTML = html;
4100 var frag = doc.createDocumentFragment(), n;
4101 while ((n = container.firstChild)) {
4102 frag.appendChild(n);
4109 * @class Roo.DomHelper
4110 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4114 Roo.DomHelper = function(){
4115 var tempTableEl = null;
4116 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117 var tableRe = /^table|tbody|tr|td$/i;
4119 // build as innerHTML where available
4121 var createHtml = function(o){
4122 if(typeof o == 'string'){
4131 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132 if(attr == "style"){
4134 if(typeof s == "function"){
4137 if(typeof s == "string"){
4138 b += ' style="' + s + '"';
4139 }else if(typeof s == "object"){
4142 if(typeof s[key] != "function"){
4143 b += key + ":" + s[key] + ";";
4150 b += ' class="' + o["cls"] + '"';
4151 }else if(attr == "htmlFor"){
4152 b += ' for="' + o["htmlFor"] + '"';
4154 b += " " + attr + '="' + o[attr] + '"';
4158 if(emptyTags.test(o.tag)){
4162 var cn = o.children || o.cn;
4164 //http://bugs.kde.org/show_bug.cgi?id=71506
4165 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166 for(var i = 0, len = cn.length; i < len; i++) {
4167 b += createHtml(cn[i], b);
4170 b += createHtml(cn, b);
4176 b += "</" + o.tag + ">";
4183 var createDom = function(o, parentNode){
4185 // defininition craeted..
4187 if (o.ns && o.ns != 'html') {
4189 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190 xmlns[o.ns] = o.xmlns;
4193 if (typeof(xmlns[o.ns]) == 'undefined') {
4194 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4200 if (typeof(o) == 'string') {
4201 return parentNode.appendChild(document.createTextNode(o));
4203 o.tag = o.tag || div;
4204 if (o.ns && Roo.isIE) {
4206 o.tag = o.ns + ':' + o.tag;
4209 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4210 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4213 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4214 attr == "style" || typeof o[attr] == "function") continue;
4216 if(attr=="cls" && Roo.isIE){
4217 el.className = o["cls"];
4219 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220 else el[attr] = o[attr];
4223 Roo.DomHelper.applyStyles(el, o.style);
4224 var cn = o.children || o.cn;
4226 //http://bugs.kde.org/show_bug.cgi?id=71506
4227 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228 for(var i = 0, len = cn.length; i < len; i++) {
4229 createDom(cn[i], el);
4236 el.innerHTML = o.html;
4239 parentNode.appendChild(el);
4244 var ieTable = function(depth, s, h, e){
4245 tempTableEl.innerHTML = [s, h, e].join('');
4246 var i = -1, el = tempTableEl;
4253 // kill repeat to save bytes
4257 tbe = '</tbody>'+te,
4263 * Nasty code for IE's broken table implementation
4265 var insertIntoTable = function(tag, where, el, html){
4267 tempTableEl = document.createElement('div');
4272 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4275 if(where == 'beforebegin'){
4279 before = el.nextSibling;
4282 node = ieTable(4, trs, html, tre);
4284 else if(tag == 'tr'){
4285 if(where == 'beforebegin'){
4288 node = ieTable(3, tbs, html, tbe);
4289 } else if(where == 'afterend'){
4290 before = el.nextSibling;
4292 node = ieTable(3, tbs, html, tbe);
4293 } else{ // INTO a TR
4294 if(where == 'afterbegin'){
4295 before = el.firstChild;
4297 node = ieTable(4, trs, html, tre);
4299 } else if(tag == 'tbody'){
4300 if(where == 'beforebegin'){
4303 node = ieTable(2, ts, html, te);
4304 } else if(where == 'afterend'){
4305 before = el.nextSibling;
4307 node = ieTable(2, ts, html, te);
4309 if(where == 'afterbegin'){
4310 before = el.firstChild;
4312 node = ieTable(3, tbs, html, tbe);
4315 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4318 if(where == 'afterbegin'){
4319 before = el.firstChild;
4321 node = ieTable(2, ts, html, te);
4323 el.insertBefore(node, before);
4328 /** True to force the use of DOM instead of html fragments @type Boolean */
4332 * Returns the markup for the passed Element(s) config
4333 * @param {Object} o The Dom object spec (and children)
4336 markup : function(o){
4337 return createHtml(o);
4341 * Applies a style specification to an element
4342 * @param {String/HTMLElement} el The element to apply styles to
4343 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344 * a function which returns such a specification.
4346 applyStyles : function(el, styles){
4349 if(typeof styles == "string"){
4350 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4352 while ((matches = re.exec(styles)) != null){
4353 el.setStyle(matches[1], matches[2]);
4355 }else if (typeof styles == "object"){
4356 for (var style in styles){
4357 el.setStyle(style, styles[style]);
4359 }else if (typeof styles == "function"){
4360 Roo.DomHelper.applyStyles(el, styles.call());
4366 * Inserts an HTML fragment into the Dom
4367 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368 * @param {HTMLElement} el The context element
4369 * @param {String} html The HTML fragmenet
4370 * @return {HTMLElement} The new node
4372 insertHtml : function(where, el, html){
4373 where = where.toLowerCase();
4374 if(el.insertAdjacentHTML){
4375 if(tableRe.test(el.tagName)){
4377 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4383 el.insertAdjacentHTML('BeforeBegin', html);
4384 return el.previousSibling;
4386 el.insertAdjacentHTML('AfterBegin', html);
4387 return el.firstChild;
4389 el.insertAdjacentHTML('BeforeEnd', html);
4390 return el.lastChild;
4392 el.insertAdjacentHTML('AfterEnd', html);
4393 return el.nextSibling;
4395 throw 'Illegal insertion point -> "' + where + '"';
4397 var range = el.ownerDocument.createRange();
4401 range.setStartBefore(el);
4402 frag = range.createContextualFragment(html);
4403 el.parentNode.insertBefore(frag, el);
4404 return el.previousSibling;
4407 range.setStartBefore(el.firstChild);
4408 frag = range.createContextualFragment(html);
4409 el.insertBefore(frag, el.firstChild);
4410 return el.firstChild;
4412 el.innerHTML = html;
4413 return el.firstChild;
4417 range.setStartAfter(el.lastChild);
4418 frag = range.createContextualFragment(html);
4419 el.appendChild(frag);
4420 return el.lastChild;
4422 el.innerHTML = html;
4423 return el.lastChild;
4426 range.setStartAfter(el);
4427 frag = range.createContextualFragment(html);
4428 el.parentNode.insertBefore(frag, el.nextSibling);
4429 return el.nextSibling;
4431 throw 'Illegal insertion point -> "' + where + '"';
4435 * Creates new Dom element(s) and inserts them before el
4436 * @param {String/HTMLElement/Element} el The context element
4437 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439 * @return {HTMLElement/Roo.Element} The new node
4441 insertBefore : function(el, o, returnElement){
4442 return this.doInsert(el, o, returnElement, "beforeBegin");
4446 * Creates new Dom element(s) and inserts them after el
4447 * @param {String/HTMLElement/Element} el The context element
4448 * @param {Object} o The Dom object spec (and children)
4449 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450 * @return {HTMLElement/Roo.Element} The new node
4452 insertAfter : function(el, o, returnElement){
4453 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457 * Creates new Dom element(s) and inserts them as the first child of el
4458 * @param {String/HTMLElement/Element} el The context element
4459 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461 * @return {HTMLElement/Roo.Element} The new node
4463 insertFirst : function(el, o, returnElement){
4464 return this.doInsert(el, o, returnElement, "afterBegin");
4468 doInsert : function(el, o, returnElement, pos, sibling){
4469 el = Roo.getDom(el);
4471 if(this.useDom || o.ns){
4472 newNode = createDom(o, null);
4473 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4475 var html = createHtml(o);
4476 newNode = this.insertHtml(pos, el, html);
4478 return returnElement ? Roo.get(newNode, true) : newNode;
4482 * Creates new Dom element(s) and appends them to el
4483 * @param {String/HTMLElement/Element} el The context element
4484 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486 * @return {HTMLElement/Roo.Element} The new node
4488 append : function(el, o, returnElement){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.appendChild(newNode);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml("beforeEnd", el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and overwrites the contents of el with them
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 overwrite : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4512 while (el.childNodes.length) {
4513 el.removeChild(el.firstChild);
4517 el.innerHTML = createHtml(o);
4520 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524 * Creates a new Roo.DomHelper.Template from the Dom object spec
4525 * @param {Object} o The Dom object spec (and children)
4526 * @return {Roo.DomHelper.Template} The new template
4528 createTemplate : function(o){
4529 var html = createHtml(o);
4530 return new Roo.Template(html);
4536 * Ext JS Library 1.1.1
4537 * Copyright(c) 2006-2007, Ext JS, LLC.
4539 * Originally Released Under LGPL - original licence link has changed is not relivant.
4542 * <script type="text/javascript">
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4551 var t = new Roo.Template({
4552 html : '<div name="{id}">' +
4553 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4555 myformat: function (value, allValues) {
4556 return 'XX' + value;
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4561 * For more information see this blog post with examples:
4562 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563 - Create Elements using DOM, HTML fragments and Templates</a>.
4565 * @param {Object} cfg - Configuration object.
4567 Roo.Template = function(cfg){
4569 if(cfg instanceof Array){
4571 }else if(arguments.length > 1){
4572 cfg = Array.prototype.join.call(arguments, "");
4576 if (typeof(cfg) == 'object') {
4587 Roo.Template.prototype = {
4590 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591 * it should be fixed so that template is observable...
4595 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599 * Returns an HTML fragment of this template with the specified values applied.
4600 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601 * @return {String} The HTML fragment
4603 applyTemplate : function(values){
4607 return this.compiled(values);
4609 var useF = this.disableFormats !== true;
4610 var fm = Roo.util.Format, tpl = this;
4611 var fn = function(m, name, format, args){
4613 if(format.substr(0, 5) == "this."){
4614 return tpl.call(format.substr(5), values[name], values);
4617 // quoted values are required for strings in compiled templates,
4618 // but for non compiled we need to strip them
4619 // quoted reversed for jsmin
4620 var re = /^\s*['"](.*)["']\s*$/;
4621 args = args.split(',');
4622 for(var i = 0, len = args.length; i < len; i++){
4623 args[i] = args[i].replace(re, "$1");
4625 args = [values[name]].concat(args);
4627 args = [values[name]];
4629 return fm[format].apply(fm, args);
4632 return values[name] !== undefined ? values[name] : "";
4635 return this.html.replace(this.re, fn);
4653 this.loading = true;
4654 this.compiled = false;
4656 var cx = new Roo.data.Connection();
4660 success : function (response) {
4662 _t.html = response.responseText;
4666 failure : function(response) {
4667 Roo.log("Template failed to load from " + _t.url);
4674 * Sets the HTML used as the template and optionally compiles it.
4675 * @param {String} html
4676 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677 * @return {Roo.Template} this
4679 set : function(html, compile){
4681 this.compiled = null;
4689 * True to disable format functions (defaults to false)
4692 disableFormats : false,
4695 * The regular expression used to match template variables
4699 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4702 * Compiles the template into an internal function, eliminating the RegEx overhead.
4703 * @return {Roo.Template} this
4705 compile : function(){
4706 var fm = Roo.util.Format;
4707 var useF = this.disableFormats !== true;
4708 var sep = Roo.isGecko ? "+" : ",";
4709 var fn = function(m, name, format, args){
4711 args = args ? ',' + args : "";
4712 if(format.substr(0, 5) != "this."){
4713 format = "fm." + format + '(';
4715 format = 'this.call("'+ format.substr(5) + '", ';
4719 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4721 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4724 // branched to use + in gecko and [].join() in others
4726 body = "this.compiled = function(values){ return '" +
4727 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4730 body = ["this.compiled = function(values){ return ['"];
4731 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732 body.push("'].join('');};");
4733 body = body.join('');
4743 // private function used to call members
4744 call : function(fnName, value, allValues){
4745 return this[fnName](value, allValues);
4749 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750 * @param {String/HTMLElement/Roo.Element} el The context element
4751 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753 * @return {HTMLElement/Roo.Element} The new node or Element
4755 insertFirst: function(el, values, returnElement){
4756 return this.doInsert('afterBegin', el, values, returnElement);
4760 * Applies the supplied values to the template and inserts the new node(s) before el.
4761 * @param {String/HTMLElement/Roo.Element} el The context element
4762 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764 * @return {HTMLElement/Roo.Element} The new node or Element
4766 insertBefore: function(el, values, returnElement){
4767 return this.doInsert('beforeBegin', el, values, returnElement);
4771 * Applies the supplied values to the template and inserts the new node(s) after el.
4772 * @param {String/HTMLElement/Roo.Element} el The context element
4773 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775 * @return {HTMLElement/Roo.Element} The new node or Element
4777 insertAfter : function(el, values, returnElement){
4778 return this.doInsert('afterEnd', el, values, returnElement);
4782 * Applies the supplied values to the template and appends the new node(s) to el.
4783 * @param {String/HTMLElement/Roo.Element} el The context element
4784 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786 * @return {HTMLElement/Roo.Element} The new node or Element
4788 append : function(el, values, returnElement){
4789 return this.doInsert('beforeEnd', el, values, returnElement);
4792 doInsert : function(where, el, values, returnEl){
4793 el = Roo.getDom(el);
4794 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795 return returnEl ? Roo.get(newNode, true) : newNode;
4799 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800 * @param {String/HTMLElement/Roo.Element} el The context element
4801 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803 * @return {HTMLElement/Roo.Element} The new node or Element
4805 overwrite : function(el, values, returnElement){
4806 el = Roo.getDom(el);
4807 el.innerHTML = this.applyTemplate(values);
4808 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812 * Alias for {@link #applyTemplate}
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4818 Roo.DomHelper.Template = Roo.Template;
4821 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822 * @param {String/HTMLElement} el A DOM element or its id
4823 * @returns {Roo.Template} The created template
4826 Roo.Template.from = function(el){
4827 el = Roo.getDom(el);
4828 return new Roo.Template(el.value || el.innerHTML);
4831 * Ext JS Library 1.1.1
4832 * Copyright(c) 2006-2007, Ext JS, LLC.
4834 * Originally Released Under LGPL - original licence link has changed is not relivant.
4837 * <script type="text/javascript">
4842 * This is code is also distributed under MIT license for use
4843 * with jQuery and prototype JavaScript libraries.
4846 * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4854 <h4>Element Selectors:</h4>
4856 <li> <b>*</b> any element</li>
4857 <li> <b>E</b> an element with the tag E</li>
4858 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4866 <li> <b>E[foo]</b> has an attribute "foo"</li>
4867 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4874 <h4>Pseudo Classes:</h4>
4876 <li> <b>E:first-child</b> E is the first child of its parent</li>
4877 <li> <b>E:last-child</b> E is the last child of its parent</li>
4878 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881 <li> <b>E:only-child</b> E is the only child of its parent</li>
4882 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883 <li> <b>E:first</b> the first E in the resultset</li>
4884 <li> <b>E:last</b> the last E in the resultset</li>
4885 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4895 <h4>CSS Value Selectors:</h4>
4897 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 Roo.DomQuery = function(){
4907 var cache = {}, simpleCache = {}, valueCache = {};
4908 var nonSpace = /\S/;
4909 var trimRe = /^\s+|\s+$/g;
4910 var tplRe = /\{(\d+)\}/g;
4911 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912 var tagTokenRe = /^(#)?([\w-\*]+)/;
4913 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4915 function child(p, index){
4917 var n = p.firstChild;
4919 if(n.nodeType == 1){
4930 while((n = n.nextSibling) && n.nodeType != 1);
4935 while((n = n.previousSibling) && n.nodeType != 1);
4939 function children(d){
4940 var n = d.firstChild, ni = -1;
4942 var nx = n.nextSibling;
4943 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4953 function byClassName(c, a, v){
4957 var r = [], ri = -1, cn;
4958 for(var i = 0, ci; ci = c[i]; i++){
4959 if((' '+ci.className+' ').indexOf(v) != -1){
4966 function attrValue(n, attr){
4967 if(!n.tagName && typeof n.length != "undefined"){
4976 if(attr == "class" || attr == "className"){
4979 return n.getAttribute(attr) || n[attr];
4983 function getNodes(ns, mode, tagName){
4984 var result = [], ri = -1, cs;
4988 tagName = tagName || "*";
4989 if(typeof ns.getElementsByTagName != "undefined"){
4993 for(var i = 0, ni; ni = ns[i]; i++){
4994 cs = ni.getElementsByTagName(tagName);
4995 for(var j = 0, ci; ci = cs[j]; j++){
4999 }else if(mode == "/" || mode == ">"){
5000 var utag = tagName.toUpperCase();
5001 for(var i = 0, ni, cn; ni = ns[i]; i++){
5002 cn = ni.children || ni.childNodes;
5003 for(var j = 0, cj; cj = cn[j]; j++){
5004 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5009 }else if(mode == "+"){
5010 var utag = tagName.toUpperCase();
5011 for(var i = 0, n; n = ns[i]; i++){
5012 while((n = n.nextSibling) && n.nodeType != 1);
5013 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017 }else if(mode == "~"){
5018 for(var i = 0, n; n = ns[i]; i++){
5019 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5028 function concat(a, b){
5032 for(var i = 0, l = b.length; i < l; i++){
5038 function byTag(cs, tagName){
5039 if(cs.tagName || cs == document){
5045 var r = [], ri = -1;
5046 tagName = tagName.toLowerCase();
5047 for(var i = 0, ci; ci = cs[i]; i++){
5048 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5055 function byId(cs, attr, id){
5056 if(cs.tagName || cs == document){
5062 var r = [], ri = -1;
5063 for(var i = 0,ci; ci = cs[i]; i++){
5064 if(ci && ci.id == id){
5072 function byAttribute(cs, attr, value, op, custom){
5073 var r = [], ri = -1, st = custom=="{";
5074 var f = Roo.DomQuery.operators[op];
5075 for(var i = 0, ci; ci = cs[i]; i++){
5078 a = Roo.DomQuery.getStyle(ci, attr);
5080 else if(attr == "class" || attr == "className"){
5082 }else if(attr == "for"){
5084 }else if(attr == "href"){
5085 a = ci.getAttribute("href", 2);
5087 a = ci.getAttribute(attr);
5089 if((f && f(a, value)) || (!f && a)){
5096 function byPseudo(cs, name, value){
5097 return Roo.DomQuery.pseudos[name](cs, value);
5100 // This is for IE MSXML which does not support expandos.
5101 // IE runs the same speed using setAttribute, however FF slows way down
5102 // and Safari completely fails so they need to continue to use expandos.
5103 var isIE = window.ActiveXObject ? true : false;
5105 // this eval is stop the compressor from
5106 // renaming the variable to something shorter
5108 /** eval:var:batch */
5113 function nodupIEXml(cs){
5115 cs[0].setAttribute("_nodup", d);
5117 for(var i = 1, len = cs.length; i < len; i++){
5119 if(!c.getAttribute("_nodup") != d){
5120 c.setAttribute("_nodup", d);
5124 for(var i = 0, len = cs.length; i < len; i++){
5125 cs[i].removeAttribute("_nodup");
5134 var len = cs.length, c, i, r = cs, cj, ri = -1;
5135 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5138 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139 return nodupIEXml(cs);
5143 for(i = 1; c = cs[i]; i++){
5148 for(var j = 0; j < i; j++){
5151 for(j = i+1; cj = cs[j]; j++){
5163 function quickDiffIEXml(c1, c2){
5165 for(var i = 0, len = c1.length; i < len; i++){
5166 c1[i].setAttribute("_qdiff", d);
5169 for(var i = 0, len = c2.length; i < len; i++){
5170 if(c2[i].getAttribute("_qdiff") != d){
5171 r[r.length] = c2[i];
5174 for(var i = 0, len = c1.length; i < len; i++){
5175 c1[i].removeAttribute("_qdiff");
5180 function quickDiff(c1, c2){
5181 var len1 = c1.length;
5185 if(isIE && c1[0].selectSingleNode){
5186 return quickDiffIEXml(c1, c2);
5189 for(var i = 0; i < len1; i++){
5193 for(var i = 0, len = c2.length; i < len; i++){
5194 if(c2[i]._qdiff != d){
5195 r[r.length] = c2[i];
5201 function quickId(ns, mode, root, id){
5203 var d = root.ownerDocument || root;
5204 return d.getElementById(id);
5206 ns = getNodes(ns, mode, "*");
5207 return byId(ns, null, id);
5211 getStyle : function(el, name){
5212 return Roo.fly(el).getStyle(name);
5215 * Compiles a selector/xpath query into a reusable function. The returned function
5216 * takes one parameter "root" (optional), which is the context node from where the query should start.
5217 * @param {String} selector The selector/xpath query
5218 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219 * @return {Function}
5221 compile : function(path, type){
5222 type = type || "select";
5224 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225 var q = path, mode, lq;
5226 var tk = Roo.DomQuery.matchers;
5227 var tklen = tk.length;
5230 // accept leading mode switch
5231 var lmode = q.match(modeRe);
5232 if(lmode && lmode[1]){
5233 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234 q = q.replace(lmode[1], "");
5236 // strip leading slashes
5237 while(path.substr(0, 1)=="/"){
5238 path = path.substr(1);
5241 while(q && lq != q){
5243 var tm = q.match(tagTokenRe);
5244 if(type == "select"){
5247 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5249 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5251 q = q.replace(tm[0], "");
5252 }else if(q.substr(0, 1) != '@'){
5253 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5258 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5260 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5262 q = q.replace(tm[0], "");
5265 while(!(mm = q.match(modeRe))){
5266 var matched = false;
5267 for(var j = 0; j < tklen; j++){
5269 var m = q.match(t.re);
5271 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5274 q = q.replace(m[0], "");
5279 // prevent infinite loop on bad selector
5281 throw 'Error parsing selector, parsing failed at "' + q + '"';
5285 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5286 q = q.replace(mm[1], "");
5289 fn[fn.length] = "return nodup(n);\n}";
5292 * list of variables that need from compression as they are used by eval.
5302 * eval:var:byClassName
5304 * eval:var:byAttribute
5305 * eval:var:attrValue
5313 * Selects a group of elements.
5314 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5315 * @param {Node} root (optional) The start of the query (defaults to document).
5318 select : function(path, root, type){
5319 if(!root || root == document){
5322 if(typeof root == "string"){
5323 root = document.getElementById(root);
5325 var paths = path.split(",");
5327 for(var i = 0, len = paths.length; i < len; i++){
5328 var p = paths[i].replace(trimRe, "");
5330 cache[p] = Roo.DomQuery.compile(p);
5332 throw p + " is not a valid selector";
5335 var result = cache[p](root);
5336 if(result && result != document){
5337 results = results.concat(result);
5340 if(paths.length > 1){
5341 return nodup(results);
5347 * Selects a single element.
5348 * @param {String} selector The selector/xpath query
5349 * @param {Node} root (optional) The start of the query (defaults to document).
5352 selectNode : function(path, root){
5353 return Roo.DomQuery.select(path, root)[0];
5357 * Selects the value of a node, optionally replacing null with the defaultValue.
5358 * @param {String} selector The selector/xpath query
5359 * @param {Node} root (optional) The start of the query (defaults to document).
5360 * @param {String} defaultValue
5362 selectValue : function(path, root, defaultValue){
5363 path = path.replace(trimRe, "");
5364 if(!valueCache[path]){
5365 valueCache[path] = Roo.DomQuery.compile(path, "select");
5367 var n = valueCache[path](root);
5368 n = n[0] ? n[0] : n;
5369 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5370 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374 * Selects the value of a node, parsing integers and floats.
5375 * @param {String} selector The selector/xpath query
5376 * @param {Node} root (optional) The start of the query (defaults to document).
5377 * @param {Number} defaultValue
5380 selectNumber : function(path, root, defaultValue){
5381 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5382 return parseFloat(v);
5386 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5387 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5388 * @param {String} selector The simple selector to test
5391 is : function(el, ss){
5392 if(typeof el == "string"){
5393 el = document.getElementById(el);
5395 var isArray = (el instanceof Array);
5396 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5397 return isArray ? (result.length == el.length) : (result.length > 0);
5401 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5402 * @param {Array} el An array of elements to filter
5403 * @param {String} selector The simple selector to test
5404 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5405 * the selector instead of the ones that match
5408 filter : function(els, ss, nonMatches){
5409 ss = ss.replace(trimRe, "");
5410 if(!simpleCache[ss]){
5411 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5413 var result = simpleCache[ss](els);
5414 return nonMatches ? quickDiff(result, els) : result;
5418 * Collection of matching regular expressions and code snippets.
5422 select: 'n = byClassName(n, null, " {1} ");'
5424 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5425 select: 'n = byPseudo(n, "{1}", "{2}");'
5427 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5428 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5431 select: 'n = byId(n, null, "{1}");'
5434 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5439 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5440 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5443 "=" : function(a, v){
5446 "!=" : function(a, v){
5449 "^=" : function(a, v){
5450 return a && a.substr(0, v.length) == v;
5452 "$=" : function(a, v){
5453 return a && a.substr(a.length-v.length) == v;
5455 "*=" : function(a, v){
5456 return a && a.indexOf(v) !== -1;
5458 "%=" : function(a, v){
5459 return (a % v) == 0;
5461 "|=" : function(a, v){
5462 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5464 "~=" : function(a, v){
5465 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5470 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5471 * and the argument (if any) supplied in the selector.
5474 "first-child" : function(c){
5475 var r = [], ri = -1, n;
5476 for(var i = 0, ci; ci = n = c[i]; i++){
5477 while((n = n.previousSibling) && n.nodeType != 1);
5485 "last-child" : function(c){
5486 var r = [], ri = -1, n;
5487 for(var i = 0, ci; ci = n = c[i]; i++){
5488 while((n = n.nextSibling) && n.nodeType != 1);
5496 "nth-child" : function(c, a) {
5497 var r = [], ri = -1;
5498 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5499 var f = (m[1] || 1) - 0, l = m[2] - 0;
5500 for(var i = 0, n; n = c[i]; i++){
5501 var pn = n.parentNode;
5502 if (batch != pn._batch) {
5504 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5505 if(cn.nodeType == 1){
5512 if (l == 0 || n.nodeIndex == l){
5515 } else if ((n.nodeIndex + l) % f == 0){
5523 "only-child" : function(c){
5524 var r = [], ri = -1;;
5525 for(var i = 0, ci; ci = c[i]; i++){
5526 if(!prev(ci) && !next(ci)){
5533 "empty" : function(c){
5534 var r = [], ri = -1;
5535 for(var i = 0, ci; ci = c[i]; i++){
5536 var cns = ci.childNodes, j = 0, cn, empty = true;
5539 if(cn.nodeType == 1 || cn.nodeType == 3){
5551 "contains" : function(c, v){
5552 var r = [], ri = -1;
5553 for(var i = 0, ci; ci = c[i]; i++){
5554 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5561 "nodeValue" : function(c, v){
5562 var r = [], ri = -1;
5563 for(var i = 0, ci; ci = c[i]; i++){
5564 if(ci.firstChild && ci.firstChild.nodeValue == v){
5571 "checked" : function(c){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if(ci.checked == true){
5581 "not" : function(c, ss){
5582 return Roo.DomQuery.filter(c, ss, true);
5585 "odd" : function(c){
5586 return this["nth-child"](c, "odd");
5589 "even" : function(c){
5590 return this["nth-child"](c, "even");
5593 "nth" : function(c, a){
5594 return c[a-1] || [];
5597 "first" : function(c){
5601 "last" : function(c){
5602 return c[c.length-1] || [];
5605 "has" : function(c, ss){
5606 var s = Roo.DomQuery.select;
5607 var r = [], ri = -1;
5608 for(var i = 0, ci; ci = c[i]; i++){
5609 if(s(ss, ci).length > 0){
5616 "next" : function(c, ss){
5617 var is = Roo.DomQuery.is;
5618 var r = [], ri = -1;
5619 for(var i = 0, ci; ci = c[i]; i++){
5628 "prev" : function(c, ss){
5629 var is = Roo.DomQuery.is;
5630 var r = [], ri = -1;
5631 for(var i = 0, ci; ci = c[i]; i++){
5644 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5645 * @param {String} path The selector/xpath query
5646 * @param {Node} root (optional) The start of the query (defaults to document).
5651 Roo.query = Roo.DomQuery.select;
5654 * Ext JS Library 1.1.1
5655 * Copyright(c) 2006-2007, Ext JS, LLC.
5657 * Originally Released Under LGPL - original licence link has changed is not relivant.
5660 * <script type="text/javascript">
5664 * @class Roo.util.Observable
5665 * Base class that provides a common interface for publishing events. Subclasses are expected to
5666 * to have a property "events" with all the events defined.<br>
5669 Employee = function(name){
5676 Roo.extend(Employee, Roo.util.Observable);
5678 * @param {Object} config properties to use (incuding events / listeners)
5681 Roo.util.Observable = function(cfg){
5684 this.addEvents(cfg.events || {});
5686 delete cfg.events; // make sure
5689 Roo.apply(this, cfg);
5692 this.on(this.listeners);
5693 delete this.listeners;
5696 Roo.util.Observable.prototype = {
5698 * @cfg {Object} listeners list of events and functions to call for this object,
5702 'click' : function(e) {
5712 * Fires the specified event with the passed parameters (minus the event name).
5713 * @param {String} eventName
5714 * @param {Object...} args Variable number of parameters are passed to handlers
5715 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5717 fireEvent : function(){
5718 var ce = this.events[arguments[0].toLowerCase()];
5719 if(typeof ce == "object"){
5720 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5727 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5730 * Appends an event handler to this component
5731 * @param {String} eventName The type of event to listen for
5732 * @param {Function} handler The method the event invokes
5733 * @param {Object} scope (optional) The scope in which to execute the handler
5734 * function. The handler function's "this" context.
5735 * @param {Object} options (optional) An object containing handler configuration
5736 * properties. This may contain any of the following properties:<ul>
5737 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5738 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5739 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5740 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5741 * by the specified number of milliseconds. If the event fires again within that time, the original
5742 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5745 * <b>Combining Options</b><br>
5746 * Using the options argument, it is possible to combine different types of listeners:<br>
5748 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5750 el.on('click', this.onClick, this, {
5757 * <b>Attaching multiple handlers in 1 call</b><br>
5758 * The method also allows for a single argument to be passed which is a config object containing properties
5759 * which specify multiple handlers.
5768 fn: this.onMouseOver,
5772 fn: this.onMouseOut,
5778 * Or a shorthand syntax which passes the same scope object to all handlers:
5781 'click': this.onClick,
5782 'mouseover': this.onMouseOver,
5783 'mouseout': this.onMouseOut,
5788 addListener : function(eventName, fn, scope, o){
5789 if(typeof eventName == "object"){
5792 if(this.filterOptRe.test(e)){
5795 if(typeof o[e] == "function"){
5797 this.addListener(e, o[e], o.scope, o);
5799 // individual options
5800 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5805 o = (!o || typeof o == "boolean") ? {} : o;
5806 eventName = eventName.toLowerCase();
5807 var ce = this.events[eventName] || true;
5808 if(typeof ce == "boolean"){
5809 ce = new Roo.util.Event(this, eventName);
5810 this.events[eventName] = ce;
5812 ce.addListener(fn, scope, o);
5816 * Removes a listener
5817 * @param {String} eventName The type of event to listen for
5818 * @param {Function} handler The handler to remove
5819 * @param {Object} scope (optional) The scope (this object) for the handler
5821 removeListener : function(eventName, fn, scope){
5822 var ce = this.events[eventName.toLowerCase()];
5823 if(typeof ce == "object"){
5824 ce.removeListener(fn, scope);
5829 * Removes all listeners for this object
5831 purgeListeners : function(){
5832 for(var evt in this.events){
5833 if(typeof this.events[evt] == "object"){
5834 this.events[evt].clearListeners();
5839 relayEvents : function(o, events){
5840 var createHandler = function(ename){
5842 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5845 for(var i = 0, len = events.length; i < len; i++){
5846 var ename = events[i];
5847 if(!this.events[ename]){ this.events[ename] = true; };
5848 o.on(ename, createHandler(ename), this);
5853 * Used to define events on this Observable
5854 * @param {Object} object The object with the events defined
5856 addEvents : function(o){
5860 Roo.applyIf(this.events, o);
5864 * Checks to see if this object has any listeners for a specified event
5865 * @param {String} eventName The name of the event to check for
5866 * @return {Boolean} True if the event is being listened for, else false
5868 hasListener : function(eventName){
5869 var e = this.events[eventName];
5870 return typeof e == "object" && e.listeners.length > 0;
5874 * Appends an event handler to this element (shorthand for addListener)
5875 * @param {String} eventName The type of event to listen for
5876 * @param {Function} handler The method the event invokes
5877 * @param {Object} scope (optional) The scope in which to execute the handler
5878 * function. The handler function's "this" context.
5879 * @param {Object} options (optional)
5882 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5884 * Removes a listener (shorthand for removeListener)
5885 * @param {String} eventName The type of event to listen for
5886 * @param {Function} handler The handler to remove
5887 * @param {Object} scope (optional) The scope (this object) for the handler
5890 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5893 * Starts capture on the specified Observable. All events will be passed
5894 * to the supplied function with the event name + standard signature of the event
5895 * <b>before</b> the event is fired. If the supplied function returns false,
5896 * the event will not fire.
5897 * @param {Observable} o The Observable to capture
5898 * @param {Function} fn The function to call
5899 * @param {Object} scope (optional) The scope (this object) for the fn
5902 Roo.util.Observable.capture = function(o, fn, scope){
5903 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 * Removes <b>all</b> added captures from the Observable.
5908 * @param {Observable} o The Observable to release
5911 Roo.util.Observable.releaseCapture = function(o){
5912 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5917 var createBuffered = function(h, o, scope){
5918 var task = new Roo.util.DelayedTask();
5920 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924 var createSingle = function(h, e, fn, scope){
5926 e.removeListener(fn, scope);
5927 return h.apply(scope, arguments);
5931 var createDelayed = function(h, o, scope){
5933 var args = Array.prototype.slice.call(arguments, 0);
5934 setTimeout(function(){
5935 h.apply(scope, args);
5940 Roo.util.Event = function(obj, name){
5943 this.listeners = [];
5946 Roo.util.Event.prototype = {
5947 addListener : function(fn, scope, options){
5948 var o = options || {};
5949 scope = scope || this.obj;
5950 if(!this.isListening(fn, scope)){
5951 var l = {fn: fn, scope: scope, options: o};
5954 h = createDelayed(h, o, scope);
5957 h = createSingle(h, this, fn, scope);
5960 h = createBuffered(h, o, scope);
5963 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5964 this.listeners.push(l);
5966 this.listeners = this.listeners.slice(0);
5967 this.listeners.push(l);
5972 findListener : function(fn, scope){
5973 scope = scope || this.obj;
5974 var ls = this.listeners;
5975 for(var i = 0, len = ls.length; i < len; i++){
5977 if(l.fn == fn && l.scope == scope){
5984 isListening : function(fn, scope){
5985 return this.findListener(fn, scope) != -1;
5988 removeListener : function(fn, scope){
5990 if((index = this.findListener(fn, scope)) != -1){
5992 this.listeners.splice(index, 1);
5994 this.listeners = this.listeners.slice(0);
5995 this.listeners.splice(index, 1);
6002 clearListeners : function(){
6003 this.listeners = [];
6007 var ls = this.listeners, scope, len = ls.length;
6010 var args = Array.prototype.slice.call(arguments, 0);
6011 for(var i = 0; i < len; i++){
6013 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6014 this.firing = false;
6018 this.firing = false;
6025 * Ext JS Library 1.1.1
6026 * Copyright(c) 2006-2007, Ext JS, LLC.
6028 * Originally Released Under LGPL - original licence link has changed is not relivant.
6031 * <script type="text/javascript">
6035 * @class Roo.EventManager
6036 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6037 * several useful events directly.
6038 * See {@link Roo.EventObject} for more details on normalized event objects.
6041 Roo.EventManager = function(){
6042 var docReadyEvent, docReadyProcId, docReadyState = false;
6043 var resizeEvent, resizeTask, textEvent, textSize;
6044 var E = Roo.lib.Event;
6045 var D = Roo.lib.Dom;
6048 var fireDocReady = function(){
6050 docReadyState = true;
6053 clearInterval(docReadyProcId);
6055 if(Roo.isGecko || Roo.isOpera) {
6056 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6059 var defer = document.getElementById("ie-deferred-loader");
6061 defer.onreadystatechange = null;
6062 defer.parentNode.removeChild(defer);
6066 docReadyEvent.fire();
6067 docReadyEvent.clearListeners();
6072 var initDocReady = function(){
6073 docReadyEvent = new Roo.util.Event();
6074 if(Roo.isGecko || Roo.isOpera) {
6075 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6077 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6078 var defer = document.getElementById("ie-deferred-loader");
6079 defer.onreadystatechange = function(){
6080 if(this.readyState == "complete"){
6084 }else if(Roo.isSafari){
6085 docReadyProcId = setInterval(function(){
6086 var rs = document.readyState;
6087 if(rs == "complete") {
6092 // no matter what, make sure it fires on load
6093 E.on(window, "load", fireDocReady);
6096 var createBuffered = function(h, o){
6097 var task = new Roo.util.DelayedTask(h);
6099 // create new event object impl so new events don't wipe out properties
6100 e = new Roo.EventObjectImpl(e);
6101 task.delay(o.buffer, h, null, [e]);
6105 var createSingle = function(h, el, ename, fn){
6107 Roo.EventManager.removeListener(el, ename, fn);
6112 var createDelayed = function(h, o){
6114 // create new event object impl so new events don't wipe out properties
6115 e = new Roo.EventObjectImpl(e);
6116 setTimeout(function(){
6122 var listen = function(element, ename, opt, fn, scope){
6123 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6124 fn = fn || o.fn; scope = scope || o.scope;
6125 var el = Roo.getDom(element);
6127 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6129 var h = function(e){
6130 e = Roo.EventObject.setEvent(e);
6133 t = e.getTarget(o.delegate, el);
6140 if(o.stopEvent === true){
6143 if(o.preventDefault === true){
6146 if(o.stopPropagation === true){
6147 e.stopPropagation();
6150 if(o.normalized === false){
6154 fn.call(scope || el, e, t, o);
6157 h = createDelayed(h, o);
6160 h = createSingle(h, el, ename, fn);
6163 h = createBuffered(h, o);
6165 fn._handlers = fn._handlers || [];
6166 fn._handlers.push([Roo.id(el), ename, h]);
6169 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6170 el.addEventListener("DOMMouseScroll", h, false);
6171 E.on(window, 'unload', function(){
6172 el.removeEventListener("DOMMouseScroll", h, false);
6175 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6176 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6181 var stopListening = function(el, ename, fn){
6182 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6184 for(var i = 0, len = hds.length; i < len; i++){
6186 if(h[0] == id && h[1] == ename){
6193 E.un(el, ename, hd);
6194 el = Roo.getDom(el);
6195 if(ename == "mousewheel" && el.addEventListener){
6196 el.removeEventListener("DOMMouseScroll", hd, false);
6198 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6199 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6203 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6210 * @scope Roo.EventManager
6215 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6216 * object with a Roo.EventObject
6217 * @param {Function} fn The method the event invokes
6218 * @param {Object} scope An object that becomes the scope of the handler
6219 * @param {boolean} override If true, the obj passed in becomes
6220 * the execution scope of the listener
6221 * @return {Function} The wrapped function
6224 wrap : function(fn, scope, override){
6226 Roo.EventObject.setEvent(e);
6227 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6232 * Appends an event handler to an element (shorthand for addListener)
6233 * @param {String/HTMLElement} element The html element or id to assign the
6234 * @param {String} eventName The type of event to listen for
6235 * @param {Function} handler The method the event invokes
6236 * @param {Object} scope (optional) The scope in which to execute the handler
6237 * function. The handler function's "this" context.
6238 * @param {Object} options (optional) An object containing handler configuration
6239 * properties. This may contain any of the following properties:<ul>
6240 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6241 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6242 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6243 * <li>preventDefault {Boolean} True to prevent the default action</li>
6244 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6245 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6246 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6247 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6248 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6249 * by the specified number of milliseconds. If the event fires again within that time, the original
6250 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6253 * <b>Combining Options</b><br>
6254 * Using the options argument, it is possible to combine different types of listeners:<br>
6256 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6258 el.on('click', this.onClick, this, {
6265 * <b>Attaching multiple handlers in 1 call</b><br>
6266 * The method also allows for a single argument to be passed which is a config object containing properties
6267 * which specify multiple handlers.
6277 fn: this.onMouseOver
6286 * Or a shorthand syntax:<br>
6289 'click' : this.onClick,
6290 'mouseover' : this.onMouseOver,
6291 'mouseout' : this.onMouseOut
6295 addListener : function(element, eventName, fn, scope, options){
6296 if(typeof eventName == "object"){
6302 if(typeof o[e] == "function"){
6304 listen(element, e, o, o[e], o.scope);
6306 // individual options
6307 listen(element, e, o[e]);
6312 return listen(element, eventName, options, fn, scope);
6316 * Removes an event handler
6318 * @param {String/HTMLElement} element The id or html element to remove the
6320 * @param {String} eventName The type of event
6321 * @param {Function} fn
6322 * @return {Boolean} True if a listener was actually removed
6324 removeListener : function(element, eventName, fn){
6325 return stopListening(element, eventName, fn);
6329 * Fires when the document is ready (before onload and before images are loaded). Can be
6330 * accessed shorthanded Roo.onReady().
6331 * @param {Function} fn The method the event invokes
6332 * @param {Object} scope An object that becomes the scope of the handler
6333 * @param {boolean} options
6335 onDocumentReady : function(fn, scope, options){
6336 if(docReadyState){ // if it already fired
6337 docReadyEvent.addListener(fn, scope, options);
6338 docReadyEvent.fire();
6339 docReadyEvent.clearListeners();
6345 docReadyEvent.addListener(fn, scope, options);
6349 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6350 * @param {Function} fn The method the event invokes
6351 * @param {Object} scope An object that becomes the scope of the handler
6352 * @param {boolean} options
6354 onWindowResize : function(fn, scope, options){
6356 resizeEvent = new Roo.util.Event();
6357 resizeTask = new Roo.util.DelayedTask(function(){
6358 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6360 E.on(window, "resize", function(){
6362 resizeTask.delay(50);
6364 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6368 resizeEvent.addListener(fn, scope, options);
6372 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6373 * @param {Function} fn The method the event invokes
6374 * @param {Object} scope An object that becomes the scope of the handler
6375 * @param {boolean} options
6377 onTextResize : function(fn, scope, options){
6379 textEvent = new Roo.util.Event();
6380 var textEl = new Roo.Element(document.createElement('div'));
6381 textEl.dom.className = 'x-text-resize';
6382 textEl.dom.innerHTML = 'X';
6383 textEl.appendTo(document.body);
6384 textSize = textEl.dom.offsetHeight;
6385 setInterval(function(){
6386 if(textEl.dom.offsetHeight != textSize){
6387 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6389 }, this.textResizeInterval);
6391 textEvent.addListener(fn, scope, options);
6395 * Removes the passed window resize listener.
6396 * @param {Function} fn The method the event invokes
6397 * @param {Object} scope The scope of handler
6399 removeResizeListener : function(fn, scope){
6401 resizeEvent.removeListener(fn, scope);
6406 fireResize : function(){
6408 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6412 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6416 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6418 textResizeInterval : 50
6423 * @scopeAlias pub=Roo.EventManager
6427 * Appends an event handler to an element (shorthand for addListener)
6428 * @param {String/HTMLElement} element The html element or id to assign the
6429 * @param {String} eventName The type of event to listen for
6430 * @param {Function} handler The method the event invokes
6431 * @param {Object} scope (optional) The scope in which to execute the handler
6432 * function. The handler function's "this" context.
6433 * @param {Object} options (optional) An object containing handler configuration
6434 * properties. This may contain any of the following properties:<ul>
6435 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6436 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6437 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6438 * <li>preventDefault {Boolean} True to prevent the default action</li>
6439 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6440 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6441 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6442 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6443 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6444 * by the specified number of milliseconds. If the event fires again within that time, the original
6445 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6448 * <b>Combining Options</b><br>
6449 * Using the options argument, it is possible to combine different types of listeners:<br>
6451 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6453 el.on('click', this.onClick, this, {
6460 * <b>Attaching multiple handlers in 1 call</b><br>
6461 * The method also allows for a single argument to be passed which is a config object containing properties
6462 * which specify multiple handlers.
6472 fn: this.onMouseOver
6481 * Or a shorthand syntax:<br>
6484 'click' : this.onClick,
6485 'mouseover' : this.onMouseOver,
6486 'mouseout' : this.onMouseOut
6490 pub.on = pub.addListener;
6491 pub.un = pub.removeListener;
6493 pub.stoppedMouseDownEvent = new Roo.util.Event();
6497 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6498 * @param {Function} fn The method the event invokes
6499 * @param {Object} scope An object that becomes the scope of the handler
6500 * @param {boolean} override If true, the obj passed in becomes
6501 * the execution scope of the listener
6505 Roo.onReady = Roo.EventManager.onDocumentReady;
6507 Roo.onReady(function(){
6508 var bd = Roo.get(document.body);
6513 : Roo.isGecko ? "roo-gecko"
6514 : Roo.isOpera ? "roo-opera"
6515 : Roo.isSafari ? "roo-safari" : ""];
6518 cls.push("roo-mac");
6521 cls.push("roo-linux");
6523 if(Roo.isBorderBox){
6524 cls.push('roo-border-box');
6526 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6527 var p = bd.dom.parentNode;
6529 p.className += ' roo-strict';
6532 bd.addClass(cls.join(' '));
6536 * @class Roo.EventObject
6537 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6538 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6541 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6543 var target = e.getTarget();
6546 var myDiv = Roo.get("myDiv");
6547 myDiv.on("click", handleClick);
6549 Roo.EventManager.on("myDiv", 'click', handleClick);
6550 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6554 Roo.EventObject = function(){
6556 var E = Roo.lib.Event;
6558 // safari keypress events for special keys return bad keycodes
6561 63235 : 39, // right
6564 63276 : 33, // page up
6565 63277 : 34, // page down
6566 63272 : 46, // delete
6571 // normalize button clicks
6572 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6573 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6575 Roo.EventObjectImpl = function(e){
6577 this.setEvent(e.browserEvent || e);
6580 Roo.EventObjectImpl.prototype = {
6582 * Used to fix doc tools.
6583 * @scope Roo.EventObject.prototype
6589 /** The normal browser event */
6590 browserEvent : null,
6591 /** The button pressed in a mouse event */
6593 /** True if the shift key was down during the event */
6595 /** True if the control key was down during the event */
6597 /** True if the alt key was down during the event */
6656 setEvent : function(e){
6657 if(e == this || (e && e.browserEvent)){ // already wrapped
6660 this.browserEvent = e;
6662 // normalize buttons
6663 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6664 if(e.type == 'click' && this.button == -1){
6668 this.shiftKey = e.shiftKey;
6669 // mac metaKey behaves like ctrlKey
6670 this.ctrlKey = e.ctrlKey || e.metaKey;
6671 this.altKey = e.altKey;
6672 // in getKey these will be normalized for the mac
6673 this.keyCode = e.keyCode;
6674 // keyup warnings on firefox.
6675 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6676 // cache the target for the delayed and or buffered events
6677 this.target = E.getTarget(e);
6679 this.xy = E.getXY(e);
6682 this.shiftKey = false;
6683 this.ctrlKey = false;
6684 this.altKey = false;
6694 * Stop the event (preventDefault and stopPropagation)
6696 stopEvent : function(){
6697 if(this.browserEvent){
6698 if(this.browserEvent.type == 'mousedown'){
6699 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6701 E.stopEvent(this.browserEvent);
6706 * Prevents the browsers default handling of the event.
6708 preventDefault : function(){
6709 if(this.browserEvent){
6710 E.preventDefault(this.browserEvent);
6715 isNavKeyPress : function(){
6716 var k = this.keyCode;
6717 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6718 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6721 isSpecialKey : function(){
6722 var k = this.keyCode;
6723 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6724 (k == 16) || (k == 17) ||
6725 (k >= 18 && k <= 20) ||
6726 (k >= 33 && k <= 35) ||
6727 (k >= 36 && k <= 39) ||
6728 (k >= 44 && k <= 45);
6731 * Cancels bubbling of the event.
6733 stopPropagation : function(){
6734 if(this.browserEvent){
6735 if(this.type == 'mousedown'){
6736 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6738 E.stopPropagation(this.browserEvent);
6743 * Gets the key code for the event.
6746 getCharCode : function(){
6747 return this.charCode || this.keyCode;
6751 * Returns a normalized keyCode for the event.
6752 * @return {Number} The key code
6754 getKey : function(){
6755 var k = this.keyCode || this.charCode;
6756 return Roo.isSafari ? (safariKeys[k] || k) : k;
6760 * Gets the x coordinate of the event.
6763 getPageX : function(){
6768 * Gets the y coordinate of the event.
6771 getPageY : function(){
6776 * Gets the time of the event.
6779 getTime : function(){
6780 if(this.browserEvent){
6781 return E.getTime(this.browserEvent);
6787 * Gets the page coordinates of the event.
6788 * @return {Array} The xy values like [x, y]
6795 * Gets the target for the event.
6796 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6797 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6798 search as a number or element (defaults to 10 || document.body)
6799 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6800 * @return {HTMLelement}
6802 getTarget : function(selector, maxDepth, returnEl){
6803 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6806 * Gets the related target.
6807 * @return {HTMLElement}
6809 getRelatedTarget : function(){
6810 if(this.browserEvent){
6811 return E.getRelatedTarget(this.browserEvent);
6817 * Normalizes mouse wheel delta across browsers
6818 * @return {Number} The delta
6820 getWheelDelta : function(){
6821 var e = this.browserEvent;
6823 if(e.wheelDelta){ /* IE/Opera. */
6824 delta = e.wheelDelta/120;
6825 }else if(e.detail){ /* Mozilla case. */
6826 delta = -e.detail/3;
6832 * Returns true if the control, meta, shift or alt key was pressed during this event.
6835 hasModifier : function(){
6836 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6840 * Returns true if the target of this event equals el or is a child of el
6841 * @param {String/HTMLElement/Element} el
6842 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6845 within : function(el, related){
6846 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6847 return t && Roo.fly(el).contains(t);
6850 getPoint : function(){
6851 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6855 return new Roo.EventObjectImpl();
6860 * Ext JS Library 1.1.1
6861 * Copyright(c) 2006-2007, Ext JS, LLC.
6863 * Originally Released Under LGPL - original licence link has changed is not relivant.
6866 * <script type="text/javascript">
6870 // was in Composite Element!??!?!
6873 var D = Roo.lib.Dom;
6874 var E = Roo.lib.Event;
6875 var A = Roo.lib.Anim;
6877 // local style camelizing for speed
6879 var camelRe = /(-[a-z])/gi;
6880 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6881 var view = document.defaultView;
6884 * @class Roo.Element
6885 * Represents an Element in the DOM.<br><br>
6888 var el = Roo.get("my-div");
6891 var el = getEl("my-div");
6893 // or with a DOM element
6894 var el = Roo.get(myDivElement);
6896 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6897 * each call instead of constructing a new one.<br><br>
6898 * <b>Animations</b><br />
6899 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6900 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6902 Option Default Description
6903 --------- -------- ---------------------------------------------
6904 duration .35 The duration of the animation in seconds
6905 easing easeOut The YUI easing method
6906 callback none A function to execute when the anim completes
6907 scope this The scope (this) of the callback function
6909 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6910 * manipulate the animation. Here's an example:
6912 var el = Roo.get("my-div");
6917 // default animation
6918 el.setWidth(100, true);
6920 // animation with some options set
6927 // using the "anim" property to get the Anim object
6933 el.setWidth(100, opt);
6935 if(opt.anim.isAnimated()){
6939 * <b> Composite (Collections of) Elements</b><br />
6940 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6941 * @constructor Create a new Element directly.
6942 * @param {String/HTMLElement} element
6943 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
6945 Roo.Element = function(element, forceNew){
6946 var dom = typeof element == "string" ?
6947 document.getElementById(element) : element;
6948 if(!dom){ // invalid id/element
6952 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6953 return Roo.Element.cache[id];
6963 * The DOM element ID
6966 this.id = id || Roo.id(dom);
6969 var El = Roo.Element;
6973 * The element's default display mode (defaults to "")
6976 originalDisplay : "",
6980 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6985 * Sets the element's visibility mode. When setVisible() is called it
6986 * will use this to determine whether to set the visibility or the display property.
6987 * @param visMode Element.VISIBILITY or Element.DISPLAY
6988 * @return {Roo.Element} this
6990 setVisibilityMode : function(visMode){
6991 this.visibilityMode = visMode;
6995 * Convenience method for setVisibilityMode(Element.DISPLAY)
6996 * @param {String} display (optional) What to set display to when visible
6997 * @return {Roo.Element} this
6999 enableDisplayMode : function(display){
7000 this.setVisibilityMode(El.DISPLAY);
7001 if(typeof display != "undefined") this.originalDisplay = display;
7006 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7007 * @param {String} selector The simple selector to test
7008 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7009 search as a number or element (defaults to 10 || document.body)
7010 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7011 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7013 findParent : function(simpleSelector, maxDepth, returnEl){
7014 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7015 maxDepth = maxDepth || 50;
7016 if(typeof maxDepth != "number"){
7017 stopEl = Roo.getDom(maxDepth);
7020 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7021 if(dq.is(p, simpleSelector)){
7022 return returnEl ? Roo.get(p) : p;
7032 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7033 * @param {String} selector The simple selector to test
7034 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7035 search as a number or element (defaults to 10 || document.body)
7036 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7037 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7039 findParentNode : function(simpleSelector, maxDepth, returnEl){
7040 var p = Roo.fly(this.dom.parentNode, '_internal');
7041 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7045 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7046 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7047 * @param {String} selector The simple selector to test
7048 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7049 search as a number or element (defaults to 10 || document.body)
7050 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7052 up : function(simpleSelector, maxDepth){
7053 return this.findParentNode(simpleSelector, maxDepth, true);
7059 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7060 * @param {String} selector The simple selector to test
7061 * @return {Boolean} True if this element matches the selector, else false
7063 is : function(simpleSelector){
7064 return Roo.DomQuery.is(this.dom, simpleSelector);
7068 * Perform animation on this element.
7069 * @param {Object} args The YUI animation control args
7070 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7071 * @param {Function} onComplete (optional) Function to call when animation completes
7072 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7073 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7074 * @return {Roo.Element} this
7076 animate : function(args, duration, onComplete, easing, animType){
7077 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7082 * @private Internal animation call
7084 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7085 animType = animType || 'run';
7087 var anim = Roo.lib.Anim[animType](
7089 (opt.duration || defaultDur) || .35,
7090 (opt.easing || defaultEase) || 'easeOut',
7092 Roo.callback(cb, this);
7093 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7101 // private legacy anim prep
7102 preanim : function(a, i){
7103 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7107 * Removes worthless text nodes
7108 * @param {Boolean} forceReclean (optional) By default the element
7109 * keeps track if it has been cleaned already so
7110 * you can call this over and over. However, if you update the element and
7111 * need to force a reclean, you can pass true.
7113 clean : function(forceReclean){
7114 if(this.isCleaned && forceReclean !== true){
7118 var d = this.dom, n = d.firstChild, ni = -1;
7120 var nx = n.nextSibling;
7121 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7128 this.isCleaned = true;
7133 calcOffsetsTo : function(el){
7136 var restorePos = false;
7137 if(el.getStyle('position') == 'static'){
7138 el.position('relative');
7143 while(op && op != d && op.tagName != 'HTML'){
7146 op = op.offsetParent;
7149 el.position('static');
7155 * Scrolls this element into view within the passed container.
7156 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7157 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7158 * @return {Roo.Element} this
7160 scrollIntoView : function(container, hscroll){
7161 var c = Roo.getDom(container) || document.body;
7164 var o = this.calcOffsetsTo(c),
7167 b = t+el.offsetHeight,
7168 r = l+el.offsetWidth;
7170 var ch = c.clientHeight;
7171 var ct = parseInt(c.scrollTop, 10);
7172 var cl = parseInt(c.scrollLeft, 10);
7174 var cr = cl + c.clientWidth;
7182 if(hscroll !== false){
7186 c.scrollLeft = r-c.clientWidth;
7193 scrollChildIntoView : function(child, hscroll){
7194 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7198 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7199 * the new height may not be available immediately.
7200 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7201 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7202 * @param {Function} onComplete (optional) Function to call when animation completes
7203 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7204 * @return {Roo.Element} this
7206 autoHeight : function(animate, duration, onComplete, easing){
7207 var oldHeight = this.getHeight();
7209 this.setHeight(1); // force clipping
7210 setTimeout(function(){
7211 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7213 this.setHeight(height);
7215 if(typeof onComplete == "function"){
7219 this.setHeight(oldHeight); // restore original height
7220 this.setHeight(height, animate, duration, function(){
7222 if(typeof onComplete == "function") onComplete();
7223 }.createDelegate(this), easing);
7225 }.createDelegate(this), 0);
7230 * Returns true if this element is an ancestor of the passed element
7231 * @param {HTMLElement/String} el The element to check
7232 * @return {Boolean} True if this element is an ancestor of el, else false
7234 contains : function(el){
7235 if(!el){return false;}
7236 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7240 * Checks whether the element is currently visible using both visibility and display properties.
7241 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7242 * @return {Boolean} True if the element is currently visible, else false
7244 isVisible : function(deep) {
7245 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7246 if(deep !== true || !vis){
7249 var p = this.dom.parentNode;
7250 while(p && p.tagName.toLowerCase() != "body"){
7251 if(!Roo.fly(p, '_isVisible').isVisible()){
7260 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7261 * @param {String} selector The CSS selector
7262 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7263 * @return {CompositeElement/CompositeElementLite} The composite element
7265 select : function(selector, unique){
7266 return El.select(selector, unique, this.dom);
7270 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7271 * @param {String} selector The CSS selector
7272 * @return {Array} An array of the matched nodes
7274 query : function(selector, unique){
7275 return Roo.DomQuery.select(selector, this.dom);
7279 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7280 * @param {String} selector The CSS selector
7281 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7282 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7284 child : function(selector, returnDom){
7285 var n = Roo.DomQuery.selectNode(selector, this.dom);
7286 return returnDom ? n : Roo.get(n);
7290 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7291 * @param {String} selector The CSS selector
7292 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7293 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7295 down : function(selector, returnDom){
7296 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7297 return returnDom ? n : Roo.get(n);
7301 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7302 * @param {String} group The group the DD object is member of
7303 * @param {Object} config The DD config object
7304 * @param {Object} overrides An object containing methods to override/implement on the DD object
7305 * @return {Roo.dd.DD} The DD object
7307 initDD : function(group, config, overrides){
7308 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7309 return Roo.apply(dd, overrides);
7313 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7314 * @param {String} group The group the DDProxy object is member of
7315 * @param {Object} config The DDProxy config object
7316 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7317 * @return {Roo.dd.DDProxy} The DDProxy object
7319 initDDProxy : function(group, config, overrides){
7320 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7321 return Roo.apply(dd, overrides);
7325 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7326 * @param {String} group The group the DDTarget object is member of
7327 * @param {Object} config The DDTarget config object
7328 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7329 * @return {Roo.dd.DDTarget} The DDTarget object
7331 initDDTarget : function(group, config, overrides){
7332 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7333 return Roo.apply(dd, overrides);
7337 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7338 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7339 * @param {Boolean} visible Whether the element is visible
7340 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7341 * @return {Roo.Element} this
7343 setVisible : function(visible, animate){
7345 if(this.visibilityMode == El.DISPLAY){
7346 this.setDisplayed(visible);
7349 this.dom.style.visibility = visible ? "visible" : "hidden";
7352 // closure for composites
7354 var visMode = this.visibilityMode;
7356 this.setOpacity(.01);
7357 this.setVisible(true);
7359 this.anim({opacity: { to: (visible?1:0) }},
7360 this.preanim(arguments, 1),
7361 null, .35, 'easeIn', function(){
7363 if(visMode == El.DISPLAY){
7364 dom.style.display = "none";
7366 dom.style.visibility = "hidden";
7368 Roo.get(dom).setOpacity(1);
7376 * Returns true if display is not "none"
7379 isDisplayed : function() {
7380 return this.getStyle("display") != "none";
7384 * Toggles the element's visibility or display, depending on visibility mode.
7385 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7386 * @return {Roo.Element} this
7388 toggle : function(animate){
7389 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7394 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7395 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7396 * @return {Roo.Element} this
7398 setDisplayed : function(value) {
7399 if(typeof value == "boolean"){
7400 value = value ? this.originalDisplay : "none";
7402 this.setStyle("display", value);
7407 * Tries to focus the element. Any exceptions are caught and ignored.
7408 * @return {Roo.Element} this
7410 focus : function() {
7418 * Tries to blur the element. Any exceptions are caught and ignored.
7419 * @return {Roo.Element} this
7429 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7430 * @param {String/Array} className The CSS class to add, or an array of classes
7431 * @return {Roo.Element} this
7433 addClass : function(className){
7434 if(className instanceof Array){
7435 for(var i = 0, len = className.length; i < len; i++) {
7436 this.addClass(className[i]);
7439 if(className && !this.hasClass(className)){
7440 this.dom.className = this.dom.className + " " + className;
7447 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7448 * @param {String/Array} className The CSS class to add, or an array of classes
7449 * @return {Roo.Element} this
7451 radioClass : function(className){
7452 var siblings = this.dom.parentNode.childNodes;
7453 for(var i = 0; i < siblings.length; i++) {
7454 var s = siblings[i];
7455 if(s.nodeType == 1){
7456 Roo.get(s).removeClass(className);
7459 this.addClass(className);
7464 * Removes one or more CSS classes from the element.
7465 * @param {String/Array} className The CSS class to remove, or an array of classes
7466 * @return {Roo.Element} this
7468 removeClass : function(className){
7469 if(!className || !this.dom.className){
7472 if(className instanceof Array){
7473 for(var i = 0, len = className.length; i < len; i++) {
7474 this.removeClass(className[i]);
7477 if(this.hasClass(className)){
7478 var re = this.classReCache[className];
7480 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7481 this.classReCache[className] = re;
7483 this.dom.className =
7484 this.dom.className.replace(re, " ");
7494 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7495 * @param {String} className The CSS class to toggle
7496 * @return {Roo.Element} this
7498 toggleClass : function(className){
7499 if(this.hasClass(className)){
7500 this.removeClass(className);
7502 this.addClass(className);
7508 * Checks if the specified CSS class exists on this element's DOM node.
7509 * @param {String} className The CSS class to check for
7510 * @return {Boolean} True if the class exists, else false
7512 hasClass : function(className){
7513 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7517 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7518 * @param {String} oldClassName The CSS class to replace
7519 * @param {String} newClassName The replacement CSS class
7520 * @return {Roo.Element} this
7522 replaceClass : function(oldClassName, newClassName){
7523 this.removeClass(oldClassName);
7524 this.addClass(newClassName);
7529 * Returns an object with properties matching the styles requested.
7530 * For example, el.getStyles('color', 'font-size', 'width') might return
7531 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7532 * @param {String} style1 A style name
7533 * @param {String} style2 A style name
7534 * @param {String} etc.
7535 * @return {Object} The style object
7537 getStyles : function(){
7538 var a = arguments, len = a.length, r = {};
7539 for(var i = 0; i < len; i++){
7540 r[a[i]] = this.getStyle(a[i]);
7546 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7547 * @param {String} property The style property whose value is returned.
7548 * @return {String} The current value of the style property for this element.
7550 getStyle : function(){
7551 return view && view.getComputedStyle ?
7553 var el = this.dom, v, cs, camel;
7554 if(prop == 'float'){
7557 if(el.style && (v = el.style[prop])){
7560 if(cs = view.getComputedStyle(el, "")){
7561 if(!(camel = propCache[prop])){
7562 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7569 var el = this.dom, v, cs, camel;
7570 if(prop == 'opacity'){
7571 if(typeof el.style.filter == 'string'){
7572 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7574 var fv = parseFloat(m[1]);
7576 return fv ? fv / 100 : 0;
7581 }else if(prop == 'float'){
7582 prop = "styleFloat";
7584 if(!(camel = propCache[prop])){
7585 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7587 if(v = el.style[camel]){
7590 if(cs = el.currentStyle){
7598 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7599 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7600 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7601 * @return {Roo.Element} this
7603 setStyle : function(prop, value){
7604 if(typeof prop == "string"){
7606 if (prop == 'float') {
7607 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7612 if(!(camel = propCache[prop])){
7613 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7616 if(camel == 'opacity') {
7617 this.setOpacity(value);
7619 this.dom.style[camel] = value;
7622 for(var style in prop){
7623 if(typeof prop[style] != "function"){
7624 this.setStyle(style, prop[style]);
7632 * More flexible version of {@link #setStyle} for setting style properties.
7633 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7634 * a function which returns such a specification.
7635 * @return {Roo.Element} this
7637 applyStyles : function(style){
7638 Roo.DomHelper.applyStyles(this.dom, style);
7643 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7644 * @return {Number} The X position of the element
7647 return D.getX(this.dom);
7651 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7652 * @return {Number} The Y position of the element
7655 return D.getY(this.dom);
7659 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7660 * @return {Array} The XY position of the element
7663 return D.getXY(this.dom);
7667 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7668 * @param {Number} The X position of the element
7669 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7670 * @return {Roo.Element} this
7672 setX : function(x, animate){
7674 D.setX(this.dom, x);
7676 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7682 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7683 * @param {Number} The Y position of the element
7684 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7685 * @return {Roo.Element} this
7687 setY : function(y, animate){
7689 D.setY(this.dom, y);
7691 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7697 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7698 * @param {String} left The left CSS property value
7699 * @return {Roo.Element} this
7701 setLeft : function(left){
7702 this.setStyle("left", this.addUnits(left));
7707 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7708 * @param {String} top The top CSS property value
7709 * @return {Roo.Element} this
7711 setTop : function(top){
7712 this.setStyle("top", this.addUnits(top));
7717 * Sets the element's CSS right style.
7718 * @param {String} right The right CSS property value
7719 * @return {Roo.Element} this
7721 setRight : function(right){
7722 this.setStyle("right", this.addUnits(right));
7727 * Sets the element's CSS bottom style.
7728 * @param {String} bottom The bottom CSS property value
7729 * @return {Roo.Element} this
7731 setBottom : function(bottom){
7732 this.setStyle("bottom", this.addUnits(bottom));
7737 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7738 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setXY : function(pos, animate){
7745 D.setXY(this.dom, pos);
7747 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7753 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7754 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7755 * @param {Number} x X value for new position (coordinates are page-based)
7756 * @param {Number} y Y value for new position (coordinates are page-based)
7757 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7758 * @return {Roo.Element} this
7760 setLocation : function(x, y, animate){
7761 this.setXY([x, y], this.preanim(arguments, 2));
7766 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7767 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7768 * @param {Number} x X value for new position (coordinates are page-based)
7769 * @param {Number} y Y value for new position (coordinates are page-based)
7770 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7771 * @return {Roo.Element} this
7773 moveTo : function(x, y, animate){
7774 this.setXY([x, y], this.preanim(arguments, 2));
7779 * Returns the region of the given element.
7780 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7781 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7783 getRegion : function(){
7784 return D.getRegion(this.dom);
7788 * Returns the offset height of the element
7789 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7790 * @return {Number} The element's height
7792 getHeight : function(contentHeight){
7793 var h = this.dom.offsetHeight || 0;
7794 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7798 * Returns the offset width of the element
7799 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7800 * @return {Number} The element's width
7802 getWidth : function(contentWidth){
7803 var w = this.dom.offsetWidth || 0;
7804 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7808 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7809 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7810 * if a height has not been set using CSS.
7813 getComputedHeight : function(){
7814 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7816 h = parseInt(this.getStyle('height'), 10) || 0;
7817 if(!this.isBorderBox()){
7818 h += this.getFrameWidth('tb');
7825 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7826 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7827 * if a width has not been set using CSS.
7830 getComputedWidth : function(){
7831 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7833 w = parseInt(this.getStyle('width'), 10) || 0;
7834 if(!this.isBorderBox()){
7835 w += this.getFrameWidth('lr');
7842 * Returns the size of the element.
7843 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7844 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7846 getSize : function(contentSize){
7847 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7851 * Returns the width and height of the viewport.
7852 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7854 getViewSize : function(){
7855 var d = this.dom, doc = document, aw = 0, ah = 0;
7856 if(d == doc || d == doc.body){
7857 return {width : D.getViewWidth(), height: D.getViewHeight()};
7860 width : d.clientWidth,
7861 height: d.clientHeight
7867 * Returns the value of the "value" attribute
7868 * @param {Boolean} asNumber true to parse the value as a number
7869 * @return {String/Number}
7871 getValue : function(asNumber){
7872 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7876 adjustWidth : function(width){
7877 if(typeof width == "number"){
7878 if(this.autoBoxAdjust && !this.isBorderBox()){
7879 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7889 adjustHeight : function(height){
7890 if(typeof height == "number"){
7891 if(this.autoBoxAdjust && !this.isBorderBox()){
7892 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7902 * Set the width of the element
7903 * @param {Number} width The new width
7904 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7905 * @return {Roo.Element} this
7907 setWidth : function(width, animate){
7908 width = this.adjustWidth(width);
7910 this.dom.style.width = this.addUnits(width);
7912 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7918 * Set the height of the element
7919 * @param {Number} height The new height
7920 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7921 * @return {Roo.Element} this
7923 setHeight : function(height, animate){
7924 height = this.adjustHeight(height);
7926 this.dom.style.height = this.addUnits(height);
7928 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7934 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7935 * @param {Number} width The new width
7936 * @param {Number} height The new height
7937 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7938 * @return {Roo.Element} this
7940 setSize : function(width, height, animate){
7941 if(typeof width == "object"){ // in case of object from getSize()
7942 height = width.height; width = width.width;
7944 width = this.adjustWidth(width); height = this.adjustHeight(height);
7946 this.dom.style.width = this.addUnits(width);
7947 this.dom.style.height = this.addUnits(height);
7949 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7955 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7956 * @param {Number} x X value for new position (coordinates are page-based)
7957 * @param {Number} y Y value for new position (coordinates are page-based)
7958 * @param {Number} width The new width
7959 * @param {Number} height The new height
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setBounds : function(x, y, width, height, animate){
7965 this.setSize(width, height);
7966 this.setLocation(x, y);
7968 width = this.adjustWidth(width); height = this.adjustHeight(height);
7969 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7970 this.preanim(arguments, 4), 'motion');
7976 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
7977 * @param {Roo.lib.Region} region The region to fill
7978 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setRegion : function(region, animate){
7982 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7987 * Appends an event handler
7989 * @param {String} eventName The type of event to append
7990 * @param {Function} fn The method the event invokes
7991 * @param {Object} scope (optional) The scope (this object) of the fn
7992 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
7994 addListener : function(eventName, fn, scope, options){
7996 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8001 * Removes an event handler from this element
8002 * @param {String} eventName the type of event to remove
8003 * @param {Function} fn the method the event invokes
8004 * @return {Roo.Element} this
8006 removeListener : function(eventName, fn){
8007 Roo.EventManager.removeListener(this.dom, eventName, fn);
8012 * Removes all previous added listeners from this element
8013 * @return {Roo.Element} this
8015 removeAllListeners : function(){
8016 E.purgeElement(this.dom);
8020 relayEvent : function(eventName, observable){
8021 this.on(eventName, function(e){
8022 observable.fireEvent(eventName, e);
8027 * Set the opacity of the element
8028 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8029 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 setOpacity : function(opacity, animate){
8034 var s = this.dom.style;
8037 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8038 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8040 s.opacity = opacity;
8043 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8049 * Gets the left X coordinate
8050 * @param {Boolean} local True to get the local css position instead of page coordinate
8053 getLeft : function(local){
8057 return parseInt(this.getStyle("left"), 10) || 0;
8062 * Gets the right X coordinate of the element (element X position + element width)
8063 * @param {Boolean} local True to get the local css position instead of page coordinate
8066 getRight : function(local){
8068 return this.getX() + this.getWidth();
8070 return (this.getLeft(true) + this.getWidth()) || 0;
8075 * Gets the top Y coordinate
8076 * @param {Boolean} local True to get the local css position instead of page coordinate
8079 getTop : function(local) {
8083 return parseInt(this.getStyle("top"), 10) || 0;
8088 * Gets the bottom Y coordinate of the element (element Y position + element height)
8089 * @param {Boolean} local True to get the local css position instead of page coordinate
8092 getBottom : function(local){
8094 return this.getY() + this.getHeight();
8096 return (this.getTop(true) + this.getHeight()) || 0;
8101 * Initializes positioning on this element. If a desired position is not passed, it will make the
8102 * the element positioned relative IF it is not already positioned.
8103 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8104 * @param {Number} zIndex (optional) The zIndex to apply
8105 * @param {Number} x (optional) Set the page X position
8106 * @param {Number} y (optional) Set the page Y position
8108 position : function(pos, zIndex, x, y){
8110 if(this.getStyle('position') == 'static'){
8111 this.setStyle('position', 'relative');
8114 this.setStyle("position", pos);
8117 this.setStyle("z-index", zIndex);
8119 if(x !== undefined && y !== undefined){
8121 }else if(x !== undefined){
8123 }else if(y !== undefined){
8129 * Clear positioning back to the default when the document was loaded
8130 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8131 * @return {Roo.Element} this
8133 clearPositioning : function(value){
8141 "position" : "static"
8147 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8148 * snapshot before performing an update and then restoring the element.
8151 getPositioning : function(){
8152 var l = this.getStyle("left");
8153 var t = this.getStyle("top");
8155 "position" : this.getStyle("position"),
8157 "right" : l ? "" : this.getStyle("right"),
8159 "bottom" : t ? "" : this.getStyle("bottom"),
8160 "z-index" : this.getStyle("z-index")
8165 * Gets the width of the border(s) for the specified side(s)
8166 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8167 * passing lr would get the border (l)eft width + the border (r)ight width.
8168 * @return {Number} The width of the sides passed added together
8170 getBorderWidth : function(side){
8171 return this.addStyles(side, El.borders);
8175 * Gets the width of the padding(s) for the specified side(s)
8176 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8177 * passing lr would get the padding (l)eft + the padding (r)ight.
8178 * @return {Number} The padding of the sides passed added together
8180 getPadding : function(side){
8181 return this.addStyles(side, El.paddings);
8185 * Set positioning with an object returned by getPositioning().
8186 * @param {Object} posCfg
8187 * @return {Roo.Element} this
8189 setPositioning : function(pc){
8190 this.applyStyles(pc);
8191 if(pc.right == "auto"){
8192 this.dom.style.right = "";
8194 if(pc.bottom == "auto"){
8195 this.dom.style.bottom = "";
8201 fixDisplay : function(){
8202 if(this.getStyle("display") == "none"){
8203 this.setStyle("visibility", "hidden");
8204 this.setStyle("display", this.originalDisplay); // first try reverting to default
8205 if(this.getStyle("display") == "none"){ // if that fails, default to block
8206 this.setStyle("display", "block");
8212 * Quick set left and top adding default units
8213 * @param {String} left The left CSS property value
8214 * @param {String} top The top CSS property value
8215 * @return {Roo.Element} this
8217 setLeftTop : function(left, top){
8218 this.dom.style.left = this.addUnits(left);
8219 this.dom.style.top = this.addUnits(top);
8224 * Move this element relative to its current position.
8225 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8226 * @param {Number} distance How far to move the element in pixels
8227 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8228 * @return {Roo.Element} this
8230 move : function(direction, distance, animate){
8231 var xy = this.getXY();
8232 direction = direction.toLowerCase();
8236 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8240 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8245 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8250 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8257 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8258 * @return {Roo.Element} this
8261 if(!this.isClipped){
8262 this.isClipped = true;
8263 this.originalClip = {
8264 "o": this.getStyle("overflow"),
8265 "x": this.getStyle("overflow-x"),
8266 "y": this.getStyle("overflow-y")
8268 this.setStyle("overflow", "hidden");
8269 this.setStyle("overflow-x", "hidden");
8270 this.setStyle("overflow-y", "hidden");
8276 * Return clipping (overflow) to original clipping before clip() was called
8277 * @return {Roo.Element} this
8279 unclip : function(){
8281 this.isClipped = false;
8282 var o = this.originalClip;
8283 if(o.o){this.setStyle("overflow", o.o);}
8284 if(o.x){this.setStyle("overflow-x", o.x);}
8285 if(o.y){this.setStyle("overflow-y", o.y);}
8292 * Gets the x,y coordinates specified by the anchor position on the element.
8293 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8294 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8295 * {width: (target width), height: (target height)} (defaults to the element's current size)
8296 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8297 * @return {Array} [x, y] An array containing the element's x and y coordinates
8299 getAnchorXY : function(anchor, local, s){
8300 //Passing a different size is useful for pre-calculating anchors,
8301 //especially for anchored animations that change the el size.
8303 var w, h, vp = false;
8306 if(d == document.body || d == document){
8308 w = D.getViewWidth(); h = D.getViewHeight();
8310 w = this.getWidth(); h = this.getHeight();
8313 w = s.width; h = s.height;
8315 var x = 0, y = 0, r = Math.round;
8316 switch((anchor || "tl").toLowerCase()){
8358 var sc = this.getScroll();
8359 return [x + sc.left, y + sc.top];
8361 //Add the element's offset xy
8362 var o = this.getXY();
8363 return [x+o[0], y+o[1]];
8367 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8368 * supported position values.
8369 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8370 * @param {String} position The position to align to.
8371 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8372 * @return {Array} [x, y]
8374 getAlignToXY : function(el, p, o){
8378 throw "Element.alignTo with an element that doesn't exist";
8380 var c = false; //constrain to viewport
8381 var p1 = "", p2 = "";
8388 }else if(p.indexOf("-") == -1){
8391 p = p.toLowerCase();
8392 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8394 throw "Element.alignTo with an invalid alignment " + p;
8396 p1 = m[1]; p2 = m[2]; c = !!m[3];
8398 //Subtract the aligned el's internal xy from the target's offset xy
8399 //plus custom offset to get the aligned el's new offset xy
8400 var a1 = this.getAnchorXY(p1, true);
8401 var a2 = el.getAnchorXY(p2, false);
8402 var x = a2[0] - a1[0] + o[0];
8403 var y = a2[1] - a1[1] + o[1];
8405 //constrain the aligned el to viewport if necessary
8406 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8407 // 5px of margin for ie
8408 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8410 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8411 //perpendicular to the vp border, allow the aligned el to slide on that border,
8412 //otherwise swap the aligned el to the opposite border of the target.
8413 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8414 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8415 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8416 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8419 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8420 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8422 if((x+w) > dw + scrollX){
8423 x = swapX ? r.left-w : dw+scrollX-w;
8426 x = swapX ? r.right : scrollX;
8428 if((y+h) > dh + scrollY){
8429 y = swapY ? r.top-h : dh+scrollY-h;
8432 y = swapY ? r.bottom : scrollY;
8439 getConstrainToXY : function(){
8440 var os = {top:0, left:0, bottom:0, right: 0};
8442 return function(el, local, offsets, proposedXY){
8444 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8446 var vw, vh, vx = 0, vy = 0;
8447 if(el.dom == document.body || el.dom == document){
8448 vw = Roo.lib.Dom.getViewWidth();
8449 vh = Roo.lib.Dom.getViewHeight();
8451 vw = el.dom.clientWidth;
8452 vh = el.dom.clientHeight;
8454 var vxy = el.getXY();
8460 var s = el.getScroll();
8462 vx += offsets.left + s.left;
8463 vy += offsets.top + s.top;
8465 vw -= offsets.right;
8466 vh -= offsets.bottom;
8471 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8472 var x = xy[0], y = xy[1];
8473 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8475 // only move it if it needs it
8478 // first validate right/bottom
8487 // then make sure top/left isn't negative
8496 return moved ? [x, y] : false;
8501 adjustForConstraints : function(xy, parent, offsets){
8502 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8506 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8507 * document it aligns it to the viewport.
8508 * The position parameter is optional, and can be specified in any one of the following formats:
8510 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8511 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8512 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8513 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8514 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8515 * element's anchor point, and the second value is used as the target's anchor point.</li>
8517 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8518 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8519 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8520 * that specified in order to enforce the viewport constraints.
8521 * Following are all of the supported anchor positions:
8524 ----- -----------------------------
8525 tl The top left corner (default)
8526 t The center of the top edge
8527 tr The top right corner
8528 l The center of the left edge
8529 c In the center of the element
8530 r The center of the right edge
8531 bl The bottom left corner
8532 b The center of the bottom edge
8533 br The bottom right corner
8537 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8538 el.alignTo("other-el");
8540 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8541 el.alignTo("other-el", "tr?");
8543 // align the bottom right corner of el with the center left edge of other-el
8544 el.alignTo("other-el", "br-l?");
8546 // align the center of el with the bottom left corner of other-el and
8547 // adjust the x position by -6 pixels (and the y position by 0)
8548 el.alignTo("other-el", "c-bl", [-6, 0]);
8550 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8551 * @param {String} position The position to align to.
8552 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8553 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8554 * @return {Roo.Element} this
8556 alignTo : function(element, position, offsets, animate){
8557 var xy = this.getAlignToXY(element, position, offsets);
8558 this.setXY(xy, this.preanim(arguments, 3));
8563 * Anchors an element to another element and realigns it when the window is resized.
8564 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8565 * @param {String} position The position to align to.
8566 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8567 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8568 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8569 * is a number, it is used as the buffer delay (defaults to 50ms).
8570 * @param {Function} callback The function to call after the animation finishes
8571 * @return {Roo.Element} this
8573 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8574 var action = function(){
8575 this.alignTo(el, alignment, offsets, animate);
8576 Roo.callback(callback, this);
8578 Roo.EventManager.onWindowResize(action, this);
8579 var tm = typeof monitorScroll;
8580 if(tm != 'undefined'){
8581 Roo.EventManager.on(window, 'scroll', action, this,
8582 {buffer: tm == 'number' ? monitorScroll : 50});
8584 action.call(this); // align immediately
8588 * Clears any opacity settings from this element. Required in some cases for IE.
8589 * @return {Roo.Element} this
8591 clearOpacity : function(){
8592 if (window.ActiveXObject) {
8593 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8594 this.dom.style.filter = "";
8597 this.dom.style.opacity = "";
8598 this.dom.style["-moz-opacity"] = "";
8599 this.dom.style["-khtml-opacity"] = "";
8605 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8606 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8607 * @return {Roo.Element} this
8609 hide : function(animate){
8610 this.setVisible(false, this.preanim(arguments, 0));
8615 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8616 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8617 * @return {Roo.Element} this
8619 show : function(animate){
8620 this.setVisible(true, this.preanim(arguments, 0));
8625 * @private Test if size has a unit, otherwise appends the default
8627 addUnits : function(size){
8628 return Roo.Element.addUnits(size, this.defaultUnit);
8632 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8633 * @return {Roo.Element} this
8635 beginMeasure : function(){
8637 if(el.offsetWidth || el.offsetHeight){
8638 return this; // offsets work already
8641 var p = this.dom, b = document.body; // start with this element
8642 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8643 var pe = Roo.get(p);
8644 if(pe.getStyle('display') == 'none'){
8645 changed.push({el: p, visibility: pe.getStyle("visibility")});
8646 p.style.visibility = "hidden";
8647 p.style.display = "block";
8651 this._measureChanged = changed;
8657 * Restores displays to before beginMeasure was called
8658 * @return {Roo.Element} this
8660 endMeasure : function(){
8661 var changed = this._measureChanged;
8663 for(var i = 0, len = changed.length; i < len; i++) {
8665 r.el.style.visibility = r.visibility;
8666 r.el.style.display = "none";
8668 this._measureChanged = null;
8674 * Update the innerHTML of this element, optionally searching for and processing scripts
8675 * @param {String} html The new HTML
8676 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8677 * @param {Function} callback For async script loading you can be noticed when the update completes
8678 * @return {Roo.Element} this
8680 update : function(html, loadScripts, callback){
8681 if(typeof html == "undefined"){
8684 if(loadScripts !== true){
8685 this.dom.innerHTML = html;
8686 if(typeof callback == "function"){
8694 html += '<span id="' + id + '"></span>';
8696 E.onAvailable(id, function(){
8697 var hd = document.getElementsByTagName("head")[0];
8698 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8699 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8700 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8703 while(match = re.exec(html)){
8704 var attrs = match[1];
8705 var srcMatch = attrs ? attrs.match(srcRe) : false;
8706 if(srcMatch && srcMatch[2]){
8707 var s = document.createElement("script");
8708 s.src = srcMatch[2];
8709 var typeMatch = attrs.match(typeRe);
8710 if(typeMatch && typeMatch[2]){
8711 s.type = typeMatch[2];
8714 }else if(match[2] && match[2].length > 0){
8715 if(window.execScript) {
8716 window.execScript(match[2]);
8724 window.eval(match[2]);
8728 var el = document.getElementById(id);
8729 if(el){el.parentNode.removeChild(el);}
8730 if(typeof callback == "function"){
8734 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8739 * Direct access to the UpdateManager update() method (takes the same parameters).
8740 * @param {String/Function} url The url for this request or a function to call to get the url
8741 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8742 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8743 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8744 * @return {Roo.Element} this
8747 var um = this.getUpdateManager();
8748 um.update.apply(um, arguments);
8753 * Gets this element's UpdateManager
8754 * @return {Roo.UpdateManager} The UpdateManager
8756 getUpdateManager : function(){
8757 if(!this.updateManager){
8758 this.updateManager = new Roo.UpdateManager(this);
8760 return this.updateManager;
8764 * Disables text selection for this element (normalized across browsers)
8765 * @return {Roo.Element} this
8767 unselectable : function(){
8768 this.dom.unselectable = "on";
8769 this.swallowEvent("selectstart", true);
8770 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8771 this.addClass("x-unselectable");
8776 * Calculates the x, y to center this element on the screen
8777 * @return {Array} The x, y values [x, y]
8779 getCenterXY : function(){
8780 return this.getAlignToXY(document, 'c-c');
8784 * Centers the Element in either the viewport, or another Element.
8785 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8787 center : function(centerIn){
8788 this.alignTo(centerIn || document, 'c-c');
8793 * Tests various css rules/browsers to determine if this element uses a border box
8796 isBorderBox : function(){
8797 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8801 * Return a box {x, y, width, height} that can be used to set another elements
8802 * size/location to match this element.
8803 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8804 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8805 * @return {Object} box An object in the format {x, y, width, height}
8807 getBox : function(contentBox, local){
8812 var left = parseInt(this.getStyle("left"), 10) || 0;
8813 var top = parseInt(this.getStyle("top"), 10) || 0;
8816 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8818 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8820 var l = this.getBorderWidth("l")+this.getPadding("l");
8821 var r = this.getBorderWidth("r")+this.getPadding("r");
8822 var t = this.getBorderWidth("t")+this.getPadding("t");
8823 var b = this.getBorderWidth("b")+this.getPadding("b");
8824 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8826 bx.right = bx.x + bx.width;
8827 bx.bottom = bx.y + bx.height;
8832 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8833 for more information about the sides.
8834 * @param {String} sides
8837 getFrameWidth : function(sides, onlyContentBox){
8838 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8842 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8843 * @param {Object} box The box to fill {x, y, width, height}
8844 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8845 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8846 * @return {Roo.Element} this
8848 setBox : function(box, adjust, animate){
8849 var w = box.width, h = box.height;
8850 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8851 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8852 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8854 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8859 * Forces the browser to repaint this element
8860 * @return {Roo.Element} this
8862 repaint : function(){
8864 this.addClass("x-repaint");
8865 setTimeout(function(){
8866 Roo.get(dom).removeClass("x-repaint");
8872 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8873 * then it returns the calculated width of the sides (see getPadding)
8874 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8875 * @return {Object/Number}
8877 getMargins : function(side){
8880 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8881 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8882 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8883 right: parseInt(this.getStyle("margin-right"), 10) || 0
8886 return this.addStyles(side, El.margins);
8891 addStyles : function(sides, styles){
8893 for(var i = 0, len = sides.length; i < len; i++){
8894 v = this.getStyle(styles[sides.charAt(i)]);
8896 w = parseInt(v, 10);
8904 * Creates a proxy element of this element
8905 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8906 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8907 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8908 * @return {Roo.Element} The new proxy element
8910 createProxy : function(config, renderTo, matchBox){
8912 renderTo = Roo.getDom(renderTo);
8914 renderTo = document.body;
8916 config = typeof config == "object" ?
8917 config : {tag : "div", cls: config};
8918 var proxy = Roo.DomHelper.append(renderTo, config, true);
8920 proxy.setBox(this.getBox());
8926 * Puts a mask over this element to disable user interaction. Requires core.css.
8927 * This method can only be applied to elements which accept child nodes.
8928 * @param {String} msg (optional) A message to display in the mask
8929 * @param {String} msgCls (optional) A css class to apply to the msg element
8930 * @return {Element} The mask element
8932 mask : function(msg, msgCls)
8934 if(this.getStyle("position") == "static"){
8935 this.setStyle("position", "relative");
8938 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8940 this.addClass("x-masked");
8941 this._mask.setDisplayed(true);
8946 while (dom && dom.style) {
8947 if (!isNaN(parseInt(dom.style.zIndex))) {
8948 z = Math.max(z, parseInt(dom.style.zIndex));
8950 dom = dom.parentNode;
8952 // if we are masking the body - then it hides everything..
8953 if (this.dom == document.body) {
8955 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8956 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8959 if(typeof msg == 'string'){
8961 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8963 var mm = this._maskMsg;
8964 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8965 mm.dom.firstChild.innerHTML = msg;
8966 mm.setDisplayed(true);
8968 mm.setStyle('z-index', z + 102);
8970 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8971 this._mask.setHeight(this.getHeight());
8973 this._mask.setStyle('z-index', z + 100);
8979 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8980 * it is cached for reuse.
8982 unmask : function(removeEl){
8984 if(removeEl === true){
8985 this._mask.remove();
8988 this._maskMsg.remove();
8989 delete this._maskMsg;
8992 this._mask.setDisplayed(false);
8994 this._maskMsg.setDisplayed(false);
8998 this.removeClass("x-masked");
9002 * Returns true if this element is masked
9005 isMasked : function(){
9006 return this._mask && this._mask.isVisible();
9010 * Creates an iframe shim for this element to keep selects and other windowed objects from
9012 * @return {Roo.Element} The new shim element
9014 createShim : function(){
9015 var el = document.createElement('iframe');
9016 el.frameBorder = 'no';
9017 el.className = 'roo-shim';
9018 if(Roo.isIE && Roo.isSecure){
9019 el.src = Roo.SSL_SECURE_URL;
9021 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9022 shim.autoBoxAdjust = false;
9027 * Removes this element from the DOM and deletes it from the cache
9029 remove : function(){
9030 if(this.dom.parentNode){
9031 this.dom.parentNode.removeChild(this.dom);
9033 delete El.cache[this.dom.id];
9037 * Sets up event handlers to add and remove a css class when the mouse is over this element
9038 * @param {String} className
9039 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9040 * mouseout events for children elements
9041 * @return {Roo.Element} this
9043 addClassOnOver : function(className, preventFlicker){
9044 this.on("mouseover", function(){
9045 Roo.fly(this, '_internal').addClass(className);
9047 var removeFn = function(e){
9048 if(preventFlicker !== true || !e.within(this, true)){
9049 Roo.fly(this, '_internal').removeClass(className);
9052 this.on("mouseout", removeFn, this.dom);
9057 * Sets up event handlers to add and remove a css class when this element has the focus
9058 * @param {String} className
9059 * @return {Roo.Element} this
9061 addClassOnFocus : function(className){
9062 this.on("focus", function(){
9063 Roo.fly(this, '_internal').addClass(className);
9065 this.on("blur", function(){
9066 Roo.fly(this, '_internal').removeClass(className);
9071 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9072 * @param {String} className
9073 * @return {Roo.Element} this
9075 addClassOnClick : function(className){
9077 this.on("mousedown", function(){
9078 Roo.fly(dom, '_internal').addClass(className);
9079 var d = Roo.get(document);
9080 var fn = function(){
9081 Roo.fly(dom, '_internal').removeClass(className);
9082 d.removeListener("mouseup", fn);
9084 d.on("mouseup", fn);
9090 * Stops the specified event from bubbling and optionally prevents the default action
9091 * @param {String} eventName
9092 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9093 * @return {Roo.Element} this
9095 swallowEvent : function(eventName, preventDefault){
9096 var fn = function(e){
9097 e.stopPropagation();
9102 if(eventName instanceof Array){
9103 for(var i = 0, len = eventName.length; i < len; i++){
9104 this.on(eventName[i], fn);
9108 this.on(eventName, fn);
9115 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9118 * Sizes this element to its parent element's dimensions performing
9119 * neccessary box adjustments.
9120 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9121 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9122 * @return {Roo.Element} this
9124 fitToParent : function(monitorResize, targetParent) {
9125 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9126 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9127 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9130 var p = Roo.get(targetParent || this.dom.parentNode);
9131 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9132 if (monitorResize === true) {
9133 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9134 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9140 * Gets the next sibling, skipping text nodes
9141 * @return {HTMLElement} The next sibling or null
9143 getNextSibling : function(){
9144 var n = this.dom.nextSibling;
9145 while(n && n.nodeType != 1){
9152 * Gets the previous sibling, skipping text nodes
9153 * @return {HTMLElement} The previous sibling or null
9155 getPrevSibling : function(){
9156 var n = this.dom.previousSibling;
9157 while(n && n.nodeType != 1){
9158 n = n.previousSibling;
9165 * Appends the passed element(s) to this element
9166 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9167 * @return {Roo.Element} this
9169 appendChild: function(el){
9176 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9177 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9178 * automatically generated with the specified attributes.
9179 * @param {HTMLElement} insertBefore (optional) a child element of this element
9180 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9181 * @return {Roo.Element} The new child element
9183 createChild: function(config, insertBefore, returnDom){
9184 config = config || {tag:'div'};
9186 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9188 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9192 * Appends this element to the passed element
9193 * @param {String/HTMLElement/Element} el The new parent element
9194 * @return {Roo.Element} this
9196 appendTo: function(el){
9197 el = Roo.getDom(el);
9198 el.appendChild(this.dom);
9203 * Inserts this element before the passed element in the DOM
9204 * @param {String/HTMLElement/Element} el The element to insert before
9205 * @return {Roo.Element} this
9207 insertBefore: function(el){
9208 el = Roo.getDom(el);
9209 el.parentNode.insertBefore(this.dom, el);
9214 * Inserts this element after the passed element in the DOM
9215 * @param {String/HTMLElement/Element} el The element to insert after
9216 * @return {Roo.Element} this
9218 insertAfter: function(el){
9219 el = Roo.getDom(el);
9220 el.parentNode.insertBefore(this.dom, el.nextSibling);
9225 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9226 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9227 * @return {Roo.Element} The new child
9229 insertFirst: function(el, returnDom){
9231 if(typeof el == 'object' && !el.nodeType){ // dh config
9232 return this.createChild(el, this.dom.firstChild, returnDom);
9234 el = Roo.getDom(el);
9235 this.dom.insertBefore(el, this.dom.firstChild);
9236 return !returnDom ? Roo.get(el) : el;
9241 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9242 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9243 * @param {String} where (optional) 'before' or 'after' defaults to before
9244 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9245 * @return {Roo.Element} the inserted Element
9247 insertSibling: function(el, where, returnDom){
9248 where = where ? where.toLowerCase() : 'before';
9250 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9252 if(typeof el == 'object' && !el.nodeType){ // dh config
9253 if(where == 'after' && !this.dom.nextSibling){
9254 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9256 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9260 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9261 where == 'before' ? this.dom : this.dom.nextSibling);
9270 * Creates and wraps this element with another element
9271 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9272 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9273 * @return {HTMLElement/Element} The newly created wrapper element
9275 wrap: function(config, returnDom){
9277 config = {tag: "div"};
9279 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9280 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9285 * Replaces the passed element with this element
9286 * @param {String/HTMLElement/Element} el The element to replace
9287 * @return {Roo.Element} this
9289 replace: function(el){
9291 this.insertBefore(el);
9297 * Inserts an html fragment into this element
9298 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9299 * @param {String} html The HTML fragment
9300 * @param {Boolean} returnEl True to return an Roo.Element
9301 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9303 insertHtml : function(where, html, returnEl){
9304 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9305 return returnEl ? Roo.get(el) : el;
9309 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9310 * @param {Object} o The object with the attributes
9311 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9312 * @return {Roo.Element} this
9314 set : function(o, useSet){
9316 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9318 if(attr == "style" || typeof o[attr] == "function") continue;
9320 el.className = o["cls"];
9322 if(useSet) el.setAttribute(attr, o[attr]);
9323 else el[attr] = o[attr];
9327 Roo.DomHelper.applyStyles(el, o.style);
9333 * Convenience method for constructing a KeyMap
9334 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9335 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9336 * @param {Function} fn The function to call
9337 * @param {Object} scope (optional) The scope of the function
9338 * @return {Roo.KeyMap} The KeyMap created
9340 addKeyListener : function(key, fn, scope){
9342 if(typeof key != "object" || key instanceof Array){
9358 return new Roo.KeyMap(this, config);
9362 * Creates a KeyMap for this element
9363 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9364 * @return {Roo.KeyMap} The KeyMap created
9366 addKeyMap : function(config){
9367 return new Roo.KeyMap(this, config);
9371 * Returns true if this element is scrollable.
9374 isScrollable : function(){
9376 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9380 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9381 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9382 * @param {Number} value The new scroll value
9383 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9384 * @return {Element} this
9387 scrollTo : function(side, value, animate){
9388 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9390 this.dom[prop] = value;
9392 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9393 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9399 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9400 * within this element's scrollable range.
9401 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9402 * @param {Number} distance How far to scroll the element in pixels
9403 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9404 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9405 * was scrolled as far as it could go.
9407 scroll : function(direction, distance, animate){
9408 if(!this.isScrollable()){
9412 var l = el.scrollLeft, t = el.scrollTop;
9413 var w = el.scrollWidth, h = el.scrollHeight;
9414 var cw = el.clientWidth, ch = el.clientHeight;
9415 direction = direction.toLowerCase();
9416 var scrolled = false;
9417 var a = this.preanim(arguments, 2);
9422 var v = Math.min(l + distance, w-cw);
9423 this.scrollTo("left", v, a);
9430 var v = Math.max(l - distance, 0);
9431 this.scrollTo("left", v, a);
9439 var v = Math.max(t - distance, 0);
9440 this.scrollTo("top", v, a);
9448 var v = Math.min(t + distance, h-ch);
9449 this.scrollTo("top", v, a);
9458 * Translates the passed page coordinates into left/top css values for this element
9459 * @param {Number/Array} x The page x or an array containing [x, y]
9460 * @param {Number} y The page y
9461 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9463 translatePoints : function(x, y){
9464 if(typeof x == 'object' || x instanceof Array){
9467 var p = this.getStyle('position');
9468 var o = this.getXY();
9470 var l = parseInt(this.getStyle('left'), 10);
9471 var t = parseInt(this.getStyle('top'), 10);
9474 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9477 t = (p == "relative") ? 0 : this.dom.offsetTop;
9480 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9484 * Returns the current scroll position of the element.
9485 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9487 getScroll : function(){
9488 var d = this.dom, doc = document;
9489 if(d == doc || d == doc.body){
9490 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9491 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9492 return {left: l, top: t};
9494 return {left: d.scrollLeft, top: d.scrollTop};
9499 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9500 * are convert to standard 6 digit hex color.
9501 * @param {String} attr The css attribute
9502 * @param {String} defaultValue The default value to use when a valid color isn't found
9503 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9506 getColor : function(attr, defaultValue, prefix){
9507 var v = this.getStyle(attr);
9508 if(!v || v == "transparent" || v == "inherit") {
9509 return defaultValue;
9511 var color = typeof prefix == "undefined" ? "#" : prefix;
9512 if(v.substr(0, 4) == "rgb("){
9513 var rvs = v.slice(4, v.length -1).split(",");
9514 for(var i = 0; i < 3; i++){
9515 var h = parseInt(rvs[i]).toString(16);
9522 if(v.substr(0, 1) == "#"){
9524 for(var i = 1; i < 4; i++){
9525 var c = v.charAt(i);
9528 }else if(v.length == 7){
9529 color += v.substr(1);
9533 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9537 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9538 * gradient background, rounded corners and a 4-way shadow.
9539 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9540 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9541 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9542 * @return {Roo.Element} this
9544 boxWrap : function(cls){
9545 cls = cls || 'x-box';
9546 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9547 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9552 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9553 * @param {String} namespace The namespace in which to look for the attribute
9554 * @param {String} name The attribute name
9555 * @return {String} The attribute value
9557 getAttributeNS : Roo.isIE ? function(ns, name){
9559 var type = typeof d[ns+":"+name];
9560 if(type != 'undefined' && type != 'unknown'){
9561 return d[ns+":"+name];
9564 } : function(ns, name){
9566 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9571 * Sets or Returns the value the dom attribute value
9572 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9573 * @param {String} value (optional) The value to set the attribute to
9574 * @return {String} The attribute value
9576 attr : function(name){
9577 if (arguments.length > 1) {
9578 this.dom.setAttribute(name, arguments[1]);
9579 return arguments[1];
9581 if (typeof(name) == 'object') {
9582 for(var i in name) {
9583 this.attr(i, name[i]);
9589 if (!this.dom.hasAttribute(name)) {
9592 return this.dom.getAttribute(name);
9599 var ep = El.prototype;
9602 * Appends an event handler (Shorthand for addListener)
9603 * @param {String} eventName The type of event to append
9604 * @param {Function} fn The method the event invokes
9605 * @param {Object} scope (optional) The scope (this object) of the fn
9606 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9609 ep.on = ep.addListener;
9611 ep.mon = ep.addListener;
9614 * Removes an event handler from this element (shorthand for removeListener)
9615 * @param {String} eventName the type of event to remove
9616 * @param {Function} fn the method the event invokes
9617 * @return {Roo.Element} this
9620 ep.un = ep.removeListener;
9623 * true to automatically adjust width and height settings for box-model issues (default to true)
9625 ep.autoBoxAdjust = true;
9628 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9631 El.addUnits = function(v, defaultUnit){
9632 if(v === "" || v == "auto"){
9635 if(v === undefined){
9638 if(typeof v == "number" || !El.unitPattern.test(v)){
9639 return v + (defaultUnit || 'px');
9644 // special markup used throughout Roo when box wrapping elements
9645 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>';
9647 * Visibility mode constant - Use visibility to hide element
9653 * Visibility mode constant - Use display to hide element
9659 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9660 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9661 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9673 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9674 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9675 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9676 * @return {Element} The Element object
9679 El.get = function(el){
9681 if(!el){ return null; }
9682 if(typeof el == "string"){ // element id
9683 if(!(elm = document.getElementById(el))){
9686 if(ex = El.cache[el]){
9689 ex = El.cache[el] = new El(elm);
9692 }else if(el.tagName){ // dom element
9696 if(ex = El.cache[id]){
9699 ex = El.cache[id] = new El(el);
9702 }else if(el instanceof El){
9704 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9705 // catch case where it hasn't been appended
9706 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9709 }else if(el.isComposite){
9711 }else if(el instanceof Array){
9712 return El.select(el);
9713 }else if(el == document){
9714 // create a bogus element object representing the document object
9716 var f = function(){};
9717 f.prototype = El.prototype;
9719 docEl.dom = document;
9727 El.uncache = function(el){
9728 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9730 delete El.cache[a[i].id || a[i]];
9736 // Garbage collection - uncache elements/purge listeners on orphaned elements
9737 // so we don't hold a reference and cause the browser to retain them
9738 El.garbageCollect = function(){
9739 if(!Roo.enableGarbageCollector){
9740 clearInterval(El.collectorThread);
9743 for(var eid in El.cache){
9744 var el = El.cache[eid], d = el.dom;
9745 // -------------------------------------------------------
9746 // Determining what is garbage:
9747 // -------------------------------------------------------
9749 // dom node is null, definitely garbage
9750 // -------------------------------------------------------
9752 // no parentNode == direct orphan, definitely garbage
9753 // -------------------------------------------------------
9754 // !d.offsetParent && !document.getElementById(eid)
9755 // display none elements have no offsetParent so we will
9756 // also try to look it up by it's id. However, check
9757 // offsetParent first so we don't do unneeded lookups.
9758 // This enables collection of elements that are not orphans
9759 // directly, but somewhere up the line they have an orphan
9761 // -------------------------------------------------------
9762 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9763 delete El.cache[eid];
9764 if(d && Roo.enableListenerCollection){
9770 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9774 El.Flyweight = function(dom){
9777 El.Flyweight.prototype = El.prototype;
9779 El._flyweights = {};
9781 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9782 * the dom node can be overwritten by other code.
9783 * @param {String/HTMLElement} el The dom node or id
9784 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9785 * prevent conflicts (e.g. internally Roo uses "_internal")
9787 * @return {Element} The shared Element object
9789 El.fly = function(el, named){
9790 named = named || '_global';
9791 el = Roo.getDom(el);
9795 if(!El._flyweights[named]){
9796 El._flyweights[named] = new El.Flyweight();
9798 El._flyweights[named].dom = el;
9799 return El._flyweights[named];
9803 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9804 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9805 * Shorthand of {@link Roo.Element#get}
9806 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9807 * @return {Element} The Element object
9813 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9814 * the dom node can be overwritten by other code.
9815 * Shorthand of {@link Roo.Element#fly}
9816 * @param {String/HTMLElement} el The dom node or id
9817 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9818 * prevent conflicts (e.g. internally Roo uses "_internal")
9820 * @return {Element} The shared Element object
9826 // speedy lookup for elements never to box adjust
9827 var noBoxAdjust = Roo.isStrict ? {
9830 input:1, select:1, textarea:1
9832 if(Roo.isIE || Roo.isGecko){
9833 noBoxAdjust['button'] = 1;
9837 Roo.EventManager.on(window, 'unload', function(){
9839 delete El._flyweights;
9847 Roo.Element.selectorFunction = Roo.DomQuery.select;
9850 Roo.Element.select = function(selector, unique, root){
9852 if(typeof selector == "string"){
9853 els = Roo.Element.selectorFunction(selector, root);
9854 }else if(selector.length !== undefined){
9857 throw "Invalid selector";
9859 if(unique === true){
9860 return new Roo.CompositeElement(els);
9862 return new Roo.CompositeElementLite(els);
9866 * Selects elements based on the passed CSS selector to enable working on them as 1.
9867 * @param {String/Array} selector The CSS selector or an array of elements
9868 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9869 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9870 * @return {CompositeElementLite/CompositeElement}
9874 Roo.select = Roo.Element.select;
9891 * Ext JS Library 1.1.1
9892 * Copyright(c) 2006-2007, Ext JS, LLC.
9894 * Originally Released Under LGPL - original licence link has changed is not relivant.
9897 * <script type="text/javascript">
9902 //Notifies Element that fx methods are available
9903 Roo.enableFx = true;
9907 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9908 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9909 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9910 * Element effects to work.</p><br/>
9912 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9913 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9914 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9915 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9916 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9917 * expected results and should be done with care.</p><br/>
9919 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9920 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9923 ----- -----------------------------
9924 tl The top left corner
9925 t The center of the top edge
9926 tr The top right corner
9927 l The center of the left edge
9928 r The center of the right edge
9929 bl The bottom left corner
9930 b The center of the bottom edge
9931 br The bottom right corner
9933 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9934 * below are common options that can be passed to any Fx method.</b>
9935 * @cfg {Function} callback A function called when the effect is finished
9936 * @cfg {Object} scope The scope of the effect function
9937 * @cfg {String} easing A valid Easing value for the effect
9938 * @cfg {String} afterCls A css class to apply after the effect
9939 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9940 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9941 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
9942 * effects that end with the element being visually hidden, ignored otherwise)
9943 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9944 * a function which returns such a specification that will be applied to the Element after the effect finishes
9945 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9946 * @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
9947 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9951 * Slides the element into view. An anchor point can be optionally passed to set the point of
9952 * origin for the slide effect. This function automatically handles wrapping the element with
9953 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
9956 // default: slide the element in from the top
9959 // custom: slide the element in from the right with a 2-second duration
9960 el.slideIn('r', { duration: 2 });
9962 // common config options shown with default values
9968 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9969 * @param {Object} options (optional) Object literal with any of the Fx config options
9970 * @return {Roo.Element} The Element
9972 slideIn : function(anchor, o){
9973 var el = this.getFxEl();
9976 el.queueFx(o, function(){
9978 anchor = anchor || "t";
9980 // fix display to visibility
9983 // restore values after effect
9984 var r = this.getFxRestore();
9985 var b = this.getBox();
9986 // fixed size for slide
9990 var wrap = this.fxWrap(r.pos, o, "hidden");
9992 var st = this.dom.style;
9993 st.visibility = "visible";
9994 st.position = "absolute";
9996 // clear out temp styles after slide and unwrap
9997 var after = function(){
9998 el.fxUnwrap(wrap, r.pos, o);
10000 st.height = r.height;
10003 // time to calc the positions
10004 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10006 switch(anchor.toLowerCase()){
10008 wrap.setSize(b.width, 0);
10009 st.left = st.bottom = "0";
10013 wrap.setSize(0, b.height);
10014 st.right = st.top = "0";
10018 wrap.setSize(0, b.height);
10019 wrap.setX(b.right);
10020 st.left = st.top = "0";
10021 a = {width: bw, points: pt};
10024 wrap.setSize(b.width, 0);
10025 wrap.setY(b.bottom);
10026 st.left = st.top = "0";
10027 a = {height: bh, points: pt};
10030 wrap.setSize(0, 0);
10031 st.right = st.bottom = "0";
10032 a = {width: bw, height: bh};
10035 wrap.setSize(0, 0);
10036 wrap.setY(b.y+b.height);
10037 st.right = st.top = "0";
10038 a = {width: bw, height: bh, points: pt};
10041 wrap.setSize(0, 0);
10042 wrap.setXY([b.right, b.bottom]);
10043 st.left = st.top = "0";
10044 a = {width: bw, height: bh, points: pt};
10047 wrap.setSize(0, 0);
10048 wrap.setX(b.x+b.width);
10049 st.left = st.bottom = "0";
10050 a = {width: bw, height: bh, points: pt};
10053 this.dom.style.visibility = "visible";
10056 arguments.callee.anim = wrap.fxanim(a,
10066 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10067 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10068 * 'hidden') but block elements will still take up space in the document. The element must be removed
10069 * from the DOM using the 'remove' config option if desired. This function automatically handles
10070 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10073 // default: slide the element out to the top
10076 // custom: slide the element out to the right with a 2-second duration
10077 el.slideOut('r', { duration: 2 });
10079 // common config options shown with default values
10087 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10088 * @param {Object} options (optional) Object literal with any of the Fx config options
10089 * @return {Roo.Element} The Element
10091 slideOut : function(anchor, o){
10092 var el = this.getFxEl();
10095 el.queueFx(o, function(){
10097 anchor = anchor || "t";
10099 // restore values after effect
10100 var r = this.getFxRestore();
10102 var b = this.getBox();
10103 // fixed size for slide
10107 var wrap = this.fxWrap(r.pos, o, "visible");
10109 var st = this.dom.style;
10110 st.visibility = "visible";
10111 st.position = "absolute";
10115 var after = function(){
10117 el.setDisplayed(false);
10122 el.fxUnwrap(wrap, r.pos, o);
10124 st.width = r.width;
10125 st.height = r.height;
10130 var a, zero = {to: 0};
10131 switch(anchor.toLowerCase()){
10133 st.left = st.bottom = "0";
10134 a = {height: zero};
10137 st.right = st.top = "0";
10141 st.left = st.top = "0";
10142 a = {width: zero, points: {to:[b.right, b.y]}};
10145 st.left = st.top = "0";
10146 a = {height: zero, points: {to:[b.x, b.bottom]}};
10149 st.right = st.bottom = "0";
10150 a = {width: zero, height: zero};
10153 st.right = st.top = "0";
10154 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10157 st.left = st.top = "0";
10158 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10161 st.left = st.bottom = "0";
10162 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10166 arguments.callee.anim = wrap.fxanim(a,
10176 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10177 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10178 * The element must be removed from the DOM using the 'remove' config option if desired.
10184 // common config options shown with default values
10192 * @param {Object} options (optional) Object literal with any of the Fx config options
10193 * @return {Roo.Element} The Element
10195 puff : function(o){
10196 var el = this.getFxEl();
10199 el.queueFx(o, function(){
10200 this.clearOpacity();
10203 // restore values after effect
10204 var r = this.getFxRestore();
10205 var st = this.dom.style;
10207 var after = function(){
10209 el.setDisplayed(false);
10216 el.setPositioning(r.pos);
10217 st.width = r.width;
10218 st.height = r.height;
10223 var width = this.getWidth();
10224 var height = this.getHeight();
10226 arguments.callee.anim = this.fxanim({
10227 width : {to: this.adjustWidth(width * 2)},
10228 height : {to: this.adjustHeight(height * 2)},
10229 points : {by: [-(width * .5), -(height * .5)]},
10231 fontSize: {to:200, unit: "%"}
10242 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10243 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10244 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10250 // all config options shown with default values
10258 * @param {Object} options (optional) Object literal with any of the Fx config options
10259 * @return {Roo.Element} The Element
10261 switchOff : function(o){
10262 var el = this.getFxEl();
10265 el.queueFx(o, function(){
10266 this.clearOpacity();
10269 // restore values after effect
10270 var r = this.getFxRestore();
10271 var st = this.dom.style;
10273 var after = function(){
10275 el.setDisplayed(false);
10281 el.setPositioning(r.pos);
10282 st.width = r.width;
10283 st.height = r.height;
10288 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10289 this.clearOpacity();
10293 points:{by:[0, this.getHeight() * .5]}
10294 }, o, 'motion', 0.3, 'easeIn', after);
10295 }).defer(100, this);
10302 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10303 * changed using the "attr" config option) and then fading back to the original color. If no original
10304 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10307 // default: highlight background to yellow
10310 // custom: highlight foreground text to blue for 2 seconds
10311 el.highlight("0000ff", { attr: 'color', duration: 2 });
10313 // common config options shown with default values
10314 el.highlight("ffff9c", {
10315 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10316 endColor: (current color) or "ffffff",
10321 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10322 * @param {Object} options (optional) Object literal with any of the Fx config options
10323 * @return {Roo.Element} The Element
10325 highlight : function(color, o){
10326 var el = this.getFxEl();
10329 el.queueFx(o, function(){
10330 color = color || "ffff9c";
10331 attr = o.attr || "backgroundColor";
10333 this.clearOpacity();
10336 var origColor = this.getColor(attr);
10337 var restoreColor = this.dom.style[attr];
10338 endColor = (o.endColor || origColor) || "ffffff";
10340 var after = function(){
10341 el.dom.style[attr] = restoreColor;
10346 a[attr] = {from: color, to: endColor};
10347 arguments.callee.anim = this.fxanim(a,
10357 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10360 // default: a single light blue ripple
10363 // custom: 3 red ripples lasting 3 seconds total
10364 el.frame("ff0000", 3, { duration: 3 });
10366 // common config options shown with default values
10367 el.frame("C3DAF9", 1, {
10368 duration: 1 //duration of entire animation (not each individual ripple)
10369 // Note: Easing is not configurable and will be ignored if included
10372 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10373 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10374 * @param {Object} options (optional) Object literal with any of the Fx config options
10375 * @return {Roo.Element} The Element
10377 frame : function(color, count, o){
10378 var el = this.getFxEl();
10381 el.queueFx(o, function(){
10382 color = color || "#C3DAF9";
10383 if(color.length == 6){
10384 color = "#" + color;
10386 count = count || 1;
10387 duration = o.duration || 1;
10390 var b = this.getBox();
10391 var animFn = function(){
10392 var proxy = this.createProxy({
10395 visbility:"hidden",
10396 position:"absolute",
10397 "z-index":"35000", // yee haw
10398 border:"0px solid " + color
10401 var scale = Roo.isBorderBox ? 2 : 1;
10403 top:{from:b.y, to:b.y - 20},
10404 left:{from:b.x, to:b.x - 20},
10405 borderWidth:{from:0, to:10},
10406 opacity:{from:1, to:0},
10407 height:{from:b.height, to:(b.height + (20*scale))},
10408 width:{from:b.width, to:(b.width + (20*scale))}
10409 }, duration, function(){
10413 animFn.defer((duration/2)*1000, this);
10424 * Creates a pause before any subsequent queued effects begin. If there are
10425 * no effects queued after the pause it will have no effect.
10430 * @param {Number} seconds The length of time to pause (in seconds)
10431 * @return {Roo.Element} The Element
10433 pause : function(seconds){
10434 var el = this.getFxEl();
10437 el.queueFx(o, function(){
10438 setTimeout(function(){
10440 }, seconds * 1000);
10446 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10447 * using the "endOpacity" config option.
10450 // default: fade in from opacity 0 to 100%
10453 // custom: fade in from opacity 0 to 75% over 2 seconds
10454 el.fadeIn({ endOpacity: .75, duration: 2});
10456 // common config options shown with default values
10458 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10463 * @param {Object} options (optional) Object literal with any of the Fx config options
10464 * @return {Roo.Element} The Element
10466 fadeIn : function(o){
10467 var el = this.getFxEl();
10469 el.queueFx(o, function(){
10470 this.setOpacity(0);
10472 this.dom.style.visibility = 'visible';
10473 var to = o.endOpacity || 1;
10474 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10475 o, null, .5, "easeOut", function(){
10477 this.clearOpacity();
10486 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10487 * using the "endOpacity" config option.
10490 // default: fade out from the element's current opacity to 0
10493 // custom: fade out from the element's current opacity to 25% over 2 seconds
10494 el.fadeOut({ endOpacity: .25, duration: 2});
10496 // common config options shown with default values
10498 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10505 * @param {Object} options (optional) Object literal with any of the Fx config options
10506 * @return {Roo.Element} The Element
10508 fadeOut : function(o){
10509 var el = this.getFxEl();
10511 el.queueFx(o, function(){
10512 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10513 o, null, .5, "easeOut", function(){
10514 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10515 this.dom.style.display = "none";
10517 this.dom.style.visibility = "hidden";
10519 this.clearOpacity();
10527 * Animates the transition of an element's dimensions from a starting height/width
10528 * to an ending height/width.
10531 // change height and width to 100x100 pixels
10532 el.scale(100, 100);
10534 // common config options shown with default values. The height and width will default to
10535 // the element's existing values if passed as null.
10538 [element's height], {
10543 * @param {Number} width The new width (pass undefined to keep the original width)
10544 * @param {Number} height The new height (pass undefined to keep the original height)
10545 * @param {Object} options (optional) Object literal with any of the Fx config options
10546 * @return {Roo.Element} The Element
10548 scale : function(w, h, o){
10549 this.shift(Roo.apply({}, o, {
10557 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10558 * Any of these properties not specified in the config object will not be changed. This effect
10559 * requires that at least one new dimension, position or opacity setting must be passed in on
10560 * the config object in order for the function to have any effect.
10563 // slide the element horizontally to x position 200 while changing the height and opacity
10564 el.shift({ x: 200, height: 50, opacity: .8 });
10566 // common config options shown with default values.
10568 width: [element's width],
10569 height: [element's height],
10570 x: [element's x position],
10571 y: [element's y position],
10572 opacity: [element's opacity],
10577 * @param {Object} options Object literal with any of the Fx config options
10578 * @return {Roo.Element} The Element
10580 shift : function(o){
10581 var el = this.getFxEl();
10583 el.queueFx(o, function(){
10584 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10585 if(w !== undefined){
10586 a.width = {to: this.adjustWidth(w)};
10588 if(h !== undefined){
10589 a.height = {to: this.adjustHeight(h)};
10591 if(x !== undefined || y !== undefined){
10593 x !== undefined ? x : this.getX(),
10594 y !== undefined ? y : this.getY()
10597 if(op !== undefined){
10598 a.opacity = {to: op};
10600 if(o.xy !== undefined){
10601 a.points = {to: o.xy};
10603 arguments.callee.anim = this.fxanim(a,
10604 o, 'motion', .35, "easeOut", function(){
10612 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10613 * ending point of the effect.
10616 // default: slide the element downward while fading out
10619 // custom: slide the element out to the right with a 2-second duration
10620 el.ghost('r', { duration: 2 });
10622 // common config options shown with default values
10630 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10631 * @param {Object} options (optional) Object literal with any of the Fx config options
10632 * @return {Roo.Element} The Element
10634 ghost : function(anchor, o){
10635 var el = this.getFxEl();
10638 el.queueFx(o, function(){
10639 anchor = anchor || "b";
10641 // restore values after effect
10642 var r = this.getFxRestore();
10643 var w = this.getWidth(),
10644 h = this.getHeight();
10646 var st = this.dom.style;
10648 var after = function(){
10650 el.setDisplayed(false);
10656 el.setPositioning(r.pos);
10657 st.width = r.width;
10658 st.height = r.height;
10663 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10664 switch(anchor.toLowerCase()){
10691 arguments.callee.anim = this.fxanim(a,
10701 * Ensures that all effects queued after syncFx is called on the element are
10702 * run concurrently. This is the opposite of {@link #sequenceFx}.
10703 * @return {Roo.Element} The Element
10705 syncFx : function(){
10706 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10715 * Ensures that all effects queued after sequenceFx is called on the element are
10716 * run in sequence. This is the opposite of {@link #syncFx}.
10717 * @return {Roo.Element} The Element
10719 sequenceFx : function(){
10720 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10722 concurrent : false,
10729 nextFx : function(){
10730 var ef = this.fxQueue[0];
10737 * Returns true if the element has any effects actively running or queued, else returns false.
10738 * @return {Boolean} True if element has active effects, else false
10740 hasActiveFx : function(){
10741 return this.fxQueue && this.fxQueue[0];
10745 * Stops any running effects and clears the element's internal effects queue if it contains
10746 * any additional effects that haven't started yet.
10747 * @return {Roo.Element} The Element
10749 stopFx : function(){
10750 if(this.hasActiveFx()){
10751 var cur = this.fxQueue[0];
10752 if(cur && cur.anim && cur.anim.isAnimated()){
10753 this.fxQueue = [cur]; // clear out others
10754 cur.anim.stop(true);
10761 beforeFx : function(o){
10762 if(this.hasActiveFx() && !o.concurrent){
10773 * Returns true if the element is currently blocking so that no other effect can be queued
10774 * until this effect is finished, else returns false if blocking is not set. This is commonly
10775 * used to ensure that an effect initiated by a user action runs to completion prior to the
10776 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10777 * @return {Boolean} True if blocking, else false
10779 hasFxBlock : function(){
10780 var q = this.fxQueue;
10781 return q && q[0] && q[0].block;
10785 queueFx : function(o, fn){
10789 if(!this.hasFxBlock()){
10790 Roo.applyIf(o, this.fxDefaults);
10792 var run = this.beforeFx(o);
10793 fn.block = o.block;
10794 this.fxQueue.push(fn);
10806 fxWrap : function(pos, o, vis){
10808 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10811 wrapXY = this.getXY();
10813 var div = document.createElement("div");
10814 div.style.visibility = vis;
10815 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10816 wrap.setPositioning(pos);
10817 if(wrap.getStyle("position") == "static"){
10818 wrap.position("relative");
10820 this.clearPositioning('auto');
10822 wrap.dom.appendChild(this.dom);
10824 wrap.setXY(wrapXY);
10831 fxUnwrap : function(wrap, pos, o){
10832 this.clearPositioning();
10833 this.setPositioning(pos);
10835 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10841 getFxRestore : function(){
10842 var st = this.dom.style;
10843 return {pos: this.getPositioning(), width: st.width, height : st.height};
10847 afterFx : function(o){
10849 this.applyStyles(o.afterStyle);
10852 this.addClass(o.afterCls);
10854 if(o.remove === true){
10857 Roo.callback(o.callback, o.scope, [this]);
10859 this.fxQueue.shift();
10865 getFxEl : function(){ // support for composite element fx
10866 return Roo.get(this.dom);
10870 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10871 animType = animType || 'run';
10873 var anim = Roo.lib.Anim[animType](
10875 (opt.duration || defaultDur) || .35,
10876 (opt.easing || defaultEase) || 'easeOut',
10878 Roo.callback(cb, this);
10887 // backwords compat
10888 Roo.Fx.resize = Roo.Fx.scale;
10890 //When included, Roo.Fx is automatically applied to Element so that all basic
10891 //effects are available directly via the Element API
10892 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10894 * Ext JS Library 1.1.1
10895 * Copyright(c) 2006-2007, Ext JS, LLC.
10897 * Originally Released Under LGPL - original licence link has changed is not relivant.
10900 * <script type="text/javascript">
10905 * @class Roo.CompositeElement
10906 * Standard composite class. Creates a Roo.Element for every element in the collection.
10908 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10909 * actions will be performed on all the elements in this collection.</b>
10911 * All methods return <i>this</i> and can be chained.
10913 var els = Roo.select("#some-el div.some-class", true);
10914 // or select directly from an existing element
10915 var el = Roo.get('some-el');
10916 el.select('div.some-class', true);
10918 els.setWidth(100); // all elements become 100 width
10919 els.hide(true); // all elements fade out and hide
10921 els.setWidth(100).hide(true);
10924 Roo.CompositeElement = function(els){
10925 this.elements = [];
10926 this.addElements(els);
10928 Roo.CompositeElement.prototype = {
10930 addElements : function(els){
10931 if(!els) return this;
10932 if(typeof els == "string"){
10933 els = Roo.Element.selectorFunction(els);
10935 var yels = this.elements;
10936 var index = yels.length-1;
10937 for(var i = 0, len = els.length; i < len; i++) {
10938 yels[++index] = Roo.get(els[i]);
10944 * Clears this composite and adds the elements returned by the passed selector.
10945 * @param {String/Array} els A string CSS selector, an array of elements or an element
10946 * @return {CompositeElement} this
10948 fill : function(els){
10949 this.elements = [];
10955 * Filters this composite to only elements that match the passed selector.
10956 * @param {String} selector A string CSS selector
10957 * @param {Boolean} inverse return inverse filter (not matches)
10958 * @return {CompositeElement} this
10960 filter : function(selector, inverse){
10962 inverse = inverse || false;
10963 this.each(function(el){
10964 var match = inverse ? !el.is(selector) : el.is(selector);
10966 els[els.length] = el.dom;
10973 invoke : function(fn, args){
10974 var els = this.elements;
10975 for(var i = 0, len = els.length; i < len; i++) {
10976 Roo.Element.prototype[fn].apply(els[i], args);
10981 * Adds elements to this composite.
10982 * @param {String/Array} els A string CSS selector, an array of elements or an element
10983 * @return {CompositeElement} this
10985 add : function(els){
10986 if(typeof els == "string"){
10987 this.addElements(Roo.Element.selectorFunction(els));
10988 }else if(els.length !== undefined){
10989 this.addElements(els);
10991 this.addElements([els]);
10996 * Calls the passed function passing (el, this, index) for each element in this composite.
10997 * @param {Function} fn The function to call
10998 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10999 * @return {CompositeElement} this
11001 each : function(fn, scope){
11002 var els = this.elements;
11003 for(var i = 0, len = els.length; i < len; i++){
11004 if(fn.call(scope || els[i], els[i], this, i) === false) {
11012 * Returns the Element object at the specified index
11013 * @param {Number} index
11014 * @return {Roo.Element}
11016 item : function(index){
11017 return this.elements[index] || null;
11021 * Returns the first Element
11022 * @return {Roo.Element}
11024 first : function(){
11025 return this.item(0);
11029 * Returns the last Element
11030 * @return {Roo.Element}
11033 return this.item(this.elements.length-1);
11037 * Returns the number of elements in this composite
11040 getCount : function(){
11041 return this.elements.length;
11045 * Returns true if this composite contains the passed element
11048 contains : function(el){
11049 return this.indexOf(el) !== -1;
11053 * Returns true if this composite contains the passed element
11056 indexOf : function(el){
11057 return this.elements.indexOf(Roo.get(el));
11062 * Removes the specified element(s).
11063 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11064 * or an array of any of those.
11065 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11066 * @return {CompositeElement} this
11068 removeElement : function(el, removeDom){
11069 if(el instanceof Array){
11070 for(var i = 0, len = el.length; i < len; i++){
11071 this.removeElement(el[i]);
11075 var index = typeof el == 'number' ? el : this.indexOf(el);
11078 var d = this.elements[index];
11082 d.parentNode.removeChild(d);
11085 this.elements.splice(index, 1);
11091 * Replaces the specified element with the passed element.
11092 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11094 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11095 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11096 * @return {CompositeElement} this
11098 replaceElement : function(el, replacement, domReplace){
11099 var index = typeof el == 'number' ? el : this.indexOf(el);
11102 this.elements[index].replaceWith(replacement);
11104 this.elements.splice(index, 1, Roo.get(replacement))
11111 * Removes all elements.
11113 clear : function(){
11114 this.elements = [];
11118 Roo.CompositeElement.createCall = function(proto, fnName){
11119 if(!proto[fnName]){
11120 proto[fnName] = function(){
11121 return this.invoke(fnName, arguments);
11125 for(var fnName in Roo.Element.prototype){
11126 if(typeof Roo.Element.prototype[fnName] == "function"){
11127 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11133 * Ext JS Library 1.1.1
11134 * Copyright(c) 2006-2007, Ext JS, LLC.
11136 * Originally Released Under LGPL - original licence link has changed is not relivant.
11139 * <script type="text/javascript">
11143 * @class Roo.CompositeElementLite
11144 * @extends Roo.CompositeElement
11145 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11147 var els = Roo.select("#some-el div.some-class");
11148 // or select directly from an existing element
11149 var el = Roo.get('some-el');
11150 el.select('div.some-class');
11152 els.setWidth(100); // all elements become 100 width
11153 els.hide(true); // all elements fade out and hide
11155 els.setWidth(100).hide(true);
11156 </code></pre><br><br>
11157 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11158 * actions will be performed on all the elements in this collection.</b>
11160 Roo.CompositeElementLite = function(els){
11161 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11162 this.el = new Roo.Element.Flyweight();
11164 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11165 addElements : function(els){
11167 if(els instanceof Array){
11168 this.elements = this.elements.concat(els);
11170 var yels = this.elements;
11171 var index = yels.length-1;
11172 for(var i = 0, len = els.length; i < len; i++) {
11173 yels[++index] = els[i];
11179 invoke : function(fn, args){
11180 var els = this.elements;
11182 for(var i = 0, len = els.length; i < len; i++) {
11184 Roo.Element.prototype[fn].apply(el, args);
11189 * Returns a flyweight Element of the dom element object at the specified index
11190 * @param {Number} index
11191 * @return {Roo.Element}
11193 item : function(index){
11194 if(!this.elements[index]){
11197 this.el.dom = this.elements[index];
11201 // fixes scope with flyweight
11202 addListener : function(eventName, handler, scope, opt){
11203 var els = this.elements;
11204 for(var i = 0, len = els.length; i < len; i++) {
11205 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11211 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11212 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11213 * a reference to the dom node, use el.dom.</b>
11214 * @param {Function} fn The function to call
11215 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11216 * @return {CompositeElement} this
11218 each : function(fn, scope){
11219 var els = this.elements;
11221 for(var i = 0, len = els.length; i < len; i++){
11223 if(fn.call(scope || el, el, this, i) === false){
11230 indexOf : function(el){
11231 return this.elements.indexOf(Roo.getDom(el));
11234 replaceElement : function(el, replacement, domReplace){
11235 var index = typeof el == 'number' ? el : this.indexOf(el);
11237 replacement = Roo.getDom(replacement);
11239 var d = this.elements[index];
11240 d.parentNode.insertBefore(replacement, d);
11241 d.parentNode.removeChild(d);
11243 this.elements.splice(index, 1, replacement);
11248 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11252 * Ext JS Library 1.1.1
11253 * Copyright(c) 2006-2007, Ext JS, LLC.
11255 * Originally Released Under LGPL - original licence link has changed is not relivant.
11258 * <script type="text/javascript">
11264 * @class Roo.data.Connection
11265 * @extends Roo.util.Observable
11266 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11267 * either to a configured URL, or to a URL specified at request time.<br><br>
11269 * Requests made by this class are asynchronous, and will return immediately. No data from
11270 * the server will be available to the statement immediately following the {@link #request} call.
11271 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11273 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11274 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11275 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11276 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11277 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11278 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11279 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11280 * standard DOM methods.
11282 * @param {Object} config a configuration object.
11284 Roo.data.Connection = function(config){
11285 Roo.apply(this, config);
11288 * @event beforerequest
11289 * Fires before a network request is made to retrieve a data object.
11290 * @param {Connection} conn This Connection object.
11291 * @param {Object} options The options config object passed to the {@link #request} method.
11293 "beforerequest" : true,
11295 * @event requestcomplete
11296 * Fires if the request was successfully completed.
11297 * @param {Connection} conn This Connection object.
11298 * @param {Object} response The XHR object containing the response data.
11299 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11300 * @param {Object} options The options config object passed to the {@link #request} method.
11302 "requestcomplete" : true,
11304 * @event requestexception
11305 * Fires if an error HTTP status was returned from the server.
11306 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11307 * @param {Connection} conn This Connection object.
11308 * @param {Object} response The XHR object containing the response data.
11309 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11310 * @param {Object} options The options config object passed to the {@link #request} method.
11312 "requestexception" : true
11314 Roo.data.Connection.superclass.constructor.call(this);
11317 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11319 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11322 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11323 * extra parameters to each request made by this object. (defaults to undefined)
11326 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11327 * to each request made by this object. (defaults to undefined)
11330 * @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)
11333 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11337 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11343 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11346 disableCaching: true,
11349 * Sends an HTTP request to a remote server.
11350 * @param {Object} options An object which may contain the following properties:<ul>
11351 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11352 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11353 * request, a url encoded string or a function to call to get either.</li>
11354 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11355 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11356 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11357 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11358 * <li>options {Object} The parameter to the request call.</li>
11359 * <li>success {Boolean} True if the request succeeded.</li>
11360 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11362 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11363 * The callback is passed the following parameters:<ul>
11364 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11365 * <li>options {Object} The parameter to the request call.</li>
11367 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11368 * The callback is passed the following parameters:<ul>
11369 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11370 * <li>options {Object} The parameter to the request call.</li>
11372 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11373 * for the callback function. Defaults to the browser window.</li>
11374 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11375 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11376 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11377 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11378 * params for the post data. Any params will be appended to the URL.</li>
11379 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11381 * @return {Number} transactionId
11383 request : function(o){
11384 if(this.fireEvent("beforerequest", this, o) !== false){
11387 if(typeof p == "function"){
11388 p = p.call(o.scope||window, o);
11390 if(typeof p == "object"){
11391 p = Roo.urlEncode(o.params);
11393 if(this.extraParams){
11394 var extras = Roo.urlEncode(this.extraParams);
11395 p = p ? (p + '&' + extras) : extras;
11398 var url = o.url || this.url;
11399 if(typeof url == 'function'){
11400 url = url.call(o.scope||window, o);
11404 var form = Roo.getDom(o.form);
11405 url = url || form.action;
11407 var enctype = form.getAttribute("enctype");
11408 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11409 return this.doFormUpload(o, p, url);
11411 var f = Roo.lib.Ajax.serializeForm(form);
11412 p = p ? (p + '&' + f) : f;
11415 var hs = o.headers;
11416 if(this.defaultHeaders){
11417 hs = Roo.apply(hs || {}, this.defaultHeaders);
11424 success: this.handleResponse,
11425 failure: this.handleFailure,
11427 argument: {options: o},
11428 timeout : o.timeout || this.timeout
11431 var method = o.method||this.method||(p ? "POST" : "GET");
11433 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11434 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11437 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11441 }else if(this.autoAbort !== false){
11445 if((method == 'GET' && p) || o.xmlData){
11446 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11449 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11450 return this.transId;
11452 Roo.callback(o.callback, o.scope, [o, null, null]);
11458 * Determine whether this object has a request outstanding.
11459 * @param {Number} transactionId (Optional) defaults to the last transaction
11460 * @return {Boolean} True if there is an outstanding request.
11462 isLoading : function(transId){
11464 return Roo.lib.Ajax.isCallInProgress(transId);
11466 return this.transId ? true : false;
11471 * Aborts any outstanding request.
11472 * @param {Number} transactionId (Optional) defaults to the last transaction
11474 abort : function(transId){
11475 if(transId || this.isLoading()){
11476 Roo.lib.Ajax.abort(transId || this.transId);
11481 handleResponse : function(response){
11482 this.transId = false;
11483 var options = response.argument.options;
11484 response.argument = options ? options.argument : null;
11485 this.fireEvent("requestcomplete", this, response, options);
11486 Roo.callback(options.success, options.scope, [response, options]);
11487 Roo.callback(options.callback, options.scope, [options, true, response]);
11491 handleFailure : function(response, e){
11492 this.transId = false;
11493 var options = response.argument.options;
11494 response.argument = options ? options.argument : null;
11495 this.fireEvent("requestexception", this, response, options, e);
11496 Roo.callback(options.failure, options.scope, [response, options]);
11497 Roo.callback(options.callback, options.scope, [options, false, response]);
11501 doFormUpload : function(o, ps, url){
11503 var frame = document.createElement('iframe');
11506 frame.className = 'x-hidden';
11508 frame.src = Roo.SSL_SECURE_URL;
11510 document.body.appendChild(frame);
11513 document.frames[id].name = id;
11516 var form = Roo.getDom(o.form);
11518 form.method = 'POST';
11519 form.enctype = form.encoding = 'multipart/form-data';
11525 if(ps){ // add dynamic params
11527 ps = Roo.urlDecode(ps, false);
11529 if(ps.hasOwnProperty(k)){
11530 hd = document.createElement('input');
11531 hd.type = 'hidden';
11534 form.appendChild(hd);
11541 var r = { // bogus response object
11546 r.argument = o ? o.argument : null;
11551 doc = frame.contentWindow.document;
11553 doc = (frame.contentDocument || window.frames[id].document);
11555 if(doc && doc.body){
11556 r.responseText = doc.body.innerHTML;
11558 if(doc && doc.XMLDocument){
11559 r.responseXML = doc.XMLDocument;
11561 r.responseXML = doc;
11568 Roo.EventManager.removeListener(frame, 'load', cb, this);
11570 this.fireEvent("requestcomplete", this, r, o);
11571 Roo.callback(o.success, o.scope, [r, o]);
11572 Roo.callback(o.callback, o.scope, [o, true, r]);
11574 setTimeout(function(){document.body.removeChild(frame);}, 100);
11577 Roo.EventManager.on(frame, 'load', cb, this);
11580 if(hiddens){ // remove dynamic params
11581 for(var i = 0, len = hiddens.length; i < len; i++){
11582 form.removeChild(hiddens[i]);
11589 * Ext JS Library 1.1.1
11590 * Copyright(c) 2006-2007, Ext JS, LLC.
11592 * Originally Released Under LGPL - original licence link has changed is not relivant.
11595 * <script type="text/javascript">
11599 * Global Ajax request class.
11602 * @extends Roo.data.Connection
11605 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11606 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11607 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11608 * @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)
11609 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11610 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11611 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11613 Roo.Ajax = new Roo.data.Connection({
11622 * Serialize the passed form into a url encoded string
11624 * @param {String/HTMLElement} form
11627 serializeForm : function(form){
11628 return Roo.lib.Ajax.serializeForm(form);
11632 * Ext JS Library 1.1.1
11633 * Copyright(c) 2006-2007, Ext JS, LLC.
11635 * Originally Released Under LGPL - original licence link has changed is not relivant.
11638 * <script type="text/javascript">
11643 * @class Roo.UpdateManager
11644 * @extends Roo.util.Observable
11645 * Provides AJAX-style update for Element object.<br><br>
11648 * // Get it from a Roo.Element object
11649 * var el = Roo.get("foo");
11650 * var mgr = el.getUpdateManager();
11651 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11653 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11655 * // or directly (returns the same UpdateManager instance)
11656 * var mgr = new Roo.UpdateManager("myElementId");
11657 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11658 * mgr.on("update", myFcnNeedsToKnow);
11660 // short handed call directly from the element object
11661 Roo.get("foo").load({
11665 text: "Loading Foo..."
11669 * Create new UpdateManager directly.
11670 * @param {String/HTMLElement/Roo.Element} el The element to update
11671 * @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).
11673 Roo.UpdateManager = function(el, forceNew){
11675 if(!forceNew && el.updateManager){
11676 return el.updateManager;
11679 * The Element object
11680 * @type Roo.Element
11684 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11687 this.defaultUrl = null;
11691 * @event beforeupdate
11692 * Fired before an update is made, return false from your handler and the update is cancelled.
11693 * @param {Roo.Element} el
11694 * @param {String/Object/Function} url
11695 * @param {String/Object} params
11697 "beforeupdate": true,
11700 * Fired after successful update is made.
11701 * @param {Roo.Element} el
11702 * @param {Object} oResponseObject The response Object
11707 * Fired on update failure.
11708 * @param {Roo.Element} el
11709 * @param {Object} oResponseObject The response Object
11713 var d = Roo.UpdateManager.defaults;
11715 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11718 this.sslBlankUrl = d.sslBlankUrl;
11720 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11723 this.disableCaching = d.disableCaching;
11725 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11728 this.indicatorText = d.indicatorText;
11730 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11733 this.showLoadIndicator = d.showLoadIndicator;
11735 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11738 this.timeout = d.timeout;
11741 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11744 this.loadScripts = d.loadScripts;
11747 * Transaction object of current executing transaction
11749 this.transaction = null;
11754 this.autoRefreshProcId = null;
11756 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11759 this.refreshDelegate = this.refresh.createDelegate(this);
11761 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11764 this.updateDelegate = this.update.createDelegate(this);
11766 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11769 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11773 this.successDelegate = this.processSuccess.createDelegate(this);
11777 this.failureDelegate = this.processFailure.createDelegate(this);
11779 if(!this.renderer){
11781 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11783 this.renderer = new Roo.UpdateManager.BasicRenderer();
11786 Roo.UpdateManager.superclass.constructor.call(this);
11789 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11791 * Get the Element this UpdateManager is bound to
11792 * @return {Roo.Element} The element
11794 getEl : function(){
11798 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11799 * @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:
11802 url: "your-url.php",<br/>
11803 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11804 callback: yourFunction,<br/>
11805 scope: yourObject, //(optional scope) <br/>
11806 discardUrl: false, <br/>
11807 nocache: false,<br/>
11808 text: "Loading...",<br/>
11810 scripts: false<br/>
11813 * The only required property is url. The optional properties nocache, text and scripts
11814 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11815 * @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}
11816 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11817 * @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.
11819 update : function(url, params, callback, discardUrl){
11820 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11821 var method = this.method,
11823 if(typeof url == "object"){ // must be config object
11826 params = params || cfg.params;
11827 callback = callback || cfg.callback;
11828 discardUrl = discardUrl || cfg.discardUrl;
11829 if(callback && cfg.scope){
11830 callback = callback.createDelegate(cfg.scope);
11832 if(typeof cfg.method != "undefined"){method = cfg.method;};
11833 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11834 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11835 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11836 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11838 this.showLoading();
11840 this.defaultUrl = url;
11842 if(typeof url == "function"){
11843 url = url.call(this);
11846 method = method || (params ? "POST" : "GET");
11847 if(method == "GET"){
11848 url = this.prepareUrl(url);
11851 var o = Roo.apply(cfg ||{}, {
11854 success: this.successDelegate,
11855 failure: this.failureDelegate,
11856 callback: undefined,
11857 timeout: (this.timeout*1000),
11858 argument: {"url": url, "form": null, "callback": callback, "params": params}
11860 Roo.log("updated manager called with timeout of " + o.timeout);
11861 this.transaction = Roo.Ajax.request(o);
11866 * 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.
11867 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11868 * @param {String/HTMLElement} form The form Id or form element
11869 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11870 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11871 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11873 formUpdate : function(form, url, reset, callback){
11874 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11875 if(typeof url == "function"){
11876 url = url.call(this);
11878 form = Roo.getDom(form);
11879 this.transaction = Roo.Ajax.request({
11882 success: this.successDelegate,
11883 failure: this.failureDelegate,
11884 timeout: (this.timeout*1000),
11885 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11887 this.showLoading.defer(1, this);
11892 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11893 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11895 refresh : function(callback){
11896 if(this.defaultUrl == null){
11899 this.update(this.defaultUrl, null, callback, true);
11903 * Set this element to auto refresh.
11904 * @param {Number} interval How often to update (in seconds).
11905 * @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)
11906 * @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}
11907 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11908 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11910 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11912 this.update(url || this.defaultUrl, params, callback, true);
11914 if(this.autoRefreshProcId){
11915 clearInterval(this.autoRefreshProcId);
11917 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11921 * Stop auto refresh on this element.
11923 stopAutoRefresh : function(){
11924 if(this.autoRefreshProcId){
11925 clearInterval(this.autoRefreshProcId);
11926 delete this.autoRefreshProcId;
11930 isAutoRefreshing : function(){
11931 return this.autoRefreshProcId ? true : false;
11934 * Called to update the element to "Loading" state. Override to perform custom action.
11936 showLoading : function(){
11937 if(this.showLoadIndicator){
11938 this.el.update(this.indicatorText);
11943 * Adds unique parameter to query string if disableCaching = true
11946 prepareUrl : function(url){
11947 if(this.disableCaching){
11948 var append = "_dc=" + (new Date().getTime());
11949 if(url.indexOf("?") !== -1){
11950 url += "&" + append;
11952 url += "?" + append;
11961 processSuccess : function(response){
11962 this.transaction = null;
11963 if(response.argument.form && response.argument.reset){
11964 try{ // put in try/catch since some older FF releases had problems with this
11965 response.argument.form.reset();
11968 if(this.loadScripts){
11969 this.renderer.render(this.el, response, this,
11970 this.updateComplete.createDelegate(this, [response]));
11972 this.renderer.render(this.el, response, this);
11973 this.updateComplete(response);
11977 updateComplete : function(response){
11978 this.fireEvent("update", this.el, response);
11979 if(typeof response.argument.callback == "function"){
11980 response.argument.callback(this.el, true, response);
11987 processFailure : function(response){
11988 this.transaction = null;
11989 this.fireEvent("failure", this.el, response);
11990 if(typeof response.argument.callback == "function"){
11991 response.argument.callback(this.el, false, response);
11996 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11997 * @param {Object} renderer The object implementing the render() method
11999 setRenderer : function(renderer){
12000 this.renderer = renderer;
12003 getRenderer : function(){
12004 return this.renderer;
12008 * Set the defaultUrl used for updates
12009 * @param {String/Function} defaultUrl The url or a function to call to get the url
12011 setDefaultUrl : function(defaultUrl){
12012 this.defaultUrl = defaultUrl;
12016 * Aborts the executing transaction
12018 abort : function(){
12019 if(this.transaction){
12020 Roo.Ajax.abort(this.transaction);
12025 * Returns true if an update is in progress
12026 * @return {Boolean}
12028 isUpdating : function(){
12029 if(this.transaction){
12030 return Roo.Ajax.isLoading(this.transaction);
12037 * @class Roo.UpdateManager.defaults
12038 * @static (not really - but it helps the doc tool)
12039 * The defaults collection enables customizing the default properties of UpdateManager
12041 Roo.UpdateManager.defaults = {
12043 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12049 * True to process scripts by default (Defaults to false).
12052 loadScripts : false,
12055 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12058 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12060 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12063 disableCaching : false,
12065 * Whether to show indicatorText when loading (Defaults to true).
12068 showLoadIndicator : true,
12070 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12073 indicatorText : '<div class="loading-indicator">Loading...</div>'
12077 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12079 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12080 * @param {String/HTMLElement/Roo.Element} el The element to update
12081 * @param {String} url The url
12082 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12083 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12086 * @member Roo.UpdateManager
12088 Roo.UpdateManager.updateElement = function(el, url, params, options){
12089 var um = Roo.get(el, true).getUpdateManager();
12090 Roo.apply(um, options);
12091 um.update(url, params, options ? options.callback : null);
12093 // alias for backwards compat
12094 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12096 * @class Roo.UpdateManager.BasicRenderer
12097 * Default Content renderer. Updates the elements innerHTML with the responseText.
12099 Roo.UpdateManager.BasicRenderer = function(){};
12101 Roo.UpdateManager.BasicRenderer.prototype = {
12103 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12104 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12105 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12106 * @param {Roo.Element} el The element being rendered
12107 * @param {Object} response The YUI Connect response object
12108 * @param {UpdateManager} updateManager The calling update manager
12109 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12111 render : function(el, response, updateManager, callback){
12112 el.update(response.responseText, updateManager.loadScripts, callback);
12118 * (c)) Alan Knowles
12124 * @class Roo.DomTemplate
12125 * @extends Roo.Template
12126 * An effort at a dom based template engine..
12128 * Similar to XTemplate, except it uses dom parsing to create the template..
12130 * Supported features:
12135 {a_variable} - output encoded.
12136 {a_variable.format:("Y-m-d")} - call a method on the variable
12137 {a_variable:raw} - unencoded output
12138 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12139 {a_variable:this.method_on_template(...)} - call a method on the template object.
12144 <div roo-for="a_variable or condition.."></div>
12145 <div roo-if="a_variable or condition"></div>
12146 <div roo-exec="some javascript"></div>
12147 <div roo-name="named_template"></div>
12152 Roo.DomTemplate = function()
12154 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12161 Roo.extend(Roo.DomTemplate, Roo.Template, {
12163 * id counter for sub templates.
12167 * flag to indicate if dom parser is inside a pre,
12168 * it will strip whitespace if not.
12173 * The various sub templates
12181 * basic tag replacing syntax
12184 * // you can fake an object call by doing this
12188 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12189 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12191 iterChild : function (node, method) {
12193 var oldPre = this.inPre;
12194 if (node.tagName == 'PRE') {
12197 for( var i = 0; i < node.childNodes.length; i++) {
12198 method.call(this, node.childNodes[i]);
12200 this.inPre = oldPre;
12206 * compile the template
12208 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12211 compile: function()
12215 // covert the html into DOM...
12219 doc = document.implementation.createHTMLDocument("");
12220 doc.documentElement.innerHTML = this.html ;
12221 div = doc.documentElement;
12223 // old IE... - nasty -- it causes all sorts of issues.. with
12224 // images getting pulled from server..
12225 div = document.createElement('div');
12226 div.innerHTML = this.html;
12228 //doc.documentElement.innerHTML = htmlBody
12234 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12236 var tpls = this.tpls;
12238 // create a top level template from the snippet..
12240 //Roo.log(div.innerHTML);
12247 body : div.innerHTML,
12260 Roo.each(tpls, function(tp){
12261 this.compileTpl(tp);
12262 this.tpls[tp.id] = tp;
12265 this.master = tpls[0];
12271 compileNode : function(node, istop) {
12276 // skip anything not a tag..
12277 if (node.nodeType != 1) {
12278 if (node.nodeType == 3 && !this.inPre) {
12279 // reduce white space..
12280 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12303 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12304 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12305 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12306 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12312 // just itterate children..
12313 this.iterChild(node,this.compileNode);
12316 tpl.uid = this.id++;
12317 tpl.value = node.getAttribute('roo-' + tpl.attr);
12318 node.removeAttribute('roo-'+ tpl.attr);
12319 if (tpl.attr != 'name') {
12320 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12321 node.parentNode.replaceChild(placeholder, node);
12324 var placeholder = document.createElement('span');
12325 placeholder.className = 'roo-tpl-' + tpl.value;
12326 node.parentNode.replaceChild(placeholder, node);
12329 // parent now sees '{domtplXXXX}
12330 this.iterChild(node,this.compileNode);
12332 // we should now have node body...
12333 var div = document.createElement('div');
12334 div.appendChild(node);
12336 // this has the unfortunate side effect of converting tagged attributes
12337 // eg. href="{...}" into %7C...%7D
12338 // this has been fixed by searching for those combo's although it's a bit hacky..
12341 tpl.body = div.innerHTML;
12348 switch (tpl.value) {
12349 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12350 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12351 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12356 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12360 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12364 tpl.id = tpl.value; // replace non characters???
12370 this.tpls.push(tpl);
12380 * Compile a segment of the template into a 'sub-template'
12386 compileTpl : function(tpl)
12388 var fm = Roo.util.Format;
12389 var useF = this.disableFormats !== true;
12391 var sep = Roo.isGecko ? "+\n" : ",\n";
12393 var undef = function(str) {
12394 Roo.debug && Roo.log("Property not found :" + str);
12398 //Roo.log(tpl.body);
12402 var fn = function(m, lbrace, name, format, args)
12405 //Roo.log(arguments);
12406 args = args ? args.replace(/\\'/g,"'") : args;
12407 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12408 if (typeof(format) == 'undefined') {
12409 format = 'htmlEncode';
12411 if (format == 'raw' ) {
12415 if(name.substr(0, 6) == 'domtpl'){
12416 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12419 // build an array of options to determine if value is undefined..
12421 // basically get 'xxxx.yyyy' then do
12422 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12423 // (function () { Roo.log("Property not found"); return ''; })() :
12428 Roo.each(name.split('.'), function(st) {
12429 lookfor += (lookfor.length ? '.': '') + st;
12430 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12433 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12436 if(format && useF){
12438 args = args ? ',' + args : "";
12440 if(format.substr(0, 5) != "this."){
12441 format = "fm." + format + '(';
12443 format = 'this.call("'+ format.substr(5) + '", ';
12447 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12450 if (args && args.length) {
12451 // called with xxyx.yuu:(test,test)
12453 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12455 // raw.. - :raw modifier..
12456 return "'"+ sep + udef_st + name + ")"+sep+"'";
12460 // branched to use + in gecko and [].join() in others
12462 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12463 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12466 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12467 body.push(tpl.body.replace(/(\r\n|\n)/g,
12468 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12469 body.push("'].join('');};};");
12470 body = body.join('');
12473 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12475 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12482 * same as applyTemplate, except it's done to one of the subTemplates
12483 * when using named templates, you can do:
12485 * var str = pl.applySubTemplate('your-name', values);
12488 * @param {Number} id of the template
12489 * @param {Object} values to apply to template
12490 * @param {Object} parent (normaly the instance of this object)
12492 applySubTemplate : function(id, values, parent)
12496 var t = this.tpls[id];
12500 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12501 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12505 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12512 if(t.execCall && t.execCall.call(this, values, parent)){
12516 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12522 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12523 parent = t.target ? values : parent;
12524 if(t.forCall && vs instanceof Array){
12526 for(var i = 0, len = vs.length; i < len; i++){
12528 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12530 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12532 //Roo.log(t.compiled);
12536 return buf.join('');
12539 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12544 return t.compiled.call(this, vs, parent);
12546 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12548 //Roo.log(t.compiled);
12556 applyTemplate : function(values){
12557 return this.master.compiled.call(this, values, {});
12558 //var s = this.subs;
12561 apply : function(){
12562 return this.applyTemplate.apply(this, arguments);
12567 Roo.DomTemplate.from = function(el){
12568 el = Roo.getDom(el);
12569 return new Roo.Domtemplate(el.value || el.innerHTML);
12572 * Ext JS Library 1.1.1
12573 * Copyright(c) 2006-2007, Ext JS, LLC.
12575 * Originally Released Under LGPL - original licence link has changed is not relivant.
12578 * <script type="text/javascript">
12582 * @class Roo.util.DelayedTask
12583 * Provides a convenient method of performing setTimeout where a new
12584 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12585 * You can use this class to buffer
12586 * the keypress events for a certain number of milliseconds, and perform only if they stop
12587 * for that amount of time.
12588 * @constructor The parameters to this constructor serve as defaults and are not required.
12589 * @param {Function} fn (optional) The default function to timeout
12590 * @param {Object} scope (optional) The default scope of that timeout
12591 * @param {Array} args (optional) The default Array of arguments
12593 Roo.util.DelayedTask = function(fn, scope, args){
12594 var id = null, d, t;
12596 var call = function(){
12597 var now = new Date().getTime();
12601 fn.apply(scope, args || []);
12605 * Cancels any pending timeout and queues a new one
12606 * @param {Number} delay The milliseconds to delay
12607 * @param {Function} newFn (optional) Overrides function passed to constructor
12608 * @param {Object} newScope (optional) Overrides scope passed to constructor
12609 * @param {Array} newArgs (optional) Overrides args passed to constructor
12611 this.delay = function(delay, newFn, newScope, newArgs){
12612 if(id && delay != d){
12616 t = new Date().getTime();
12618 scope = newScope || scope;
12619 args = newArgs || args;
12621 id = setInterval(call, d);
12626 * Cancel the last queued timeout
12628 this.cancel = function(){
12636 * Ext JS Library 1.1.1
12637 * Copyright(c) 2006-2007, Ext JS, LLC.
12639 * Originally Released Under LGPL - original licence link has changed is not relivant.
12642 * <script type="text/javascript">
12646 Roo.util.TaskRunner = function(interval){
12647 interval = interval || 10;
12648 var tasks = [], removeQueue = [];
12650 var running = false;
12652 var stopThread = function(){
12658 var startThread = function(){
12661 id = setInterval(runTasks, interval);
12665 var removeTask = function(task){
12666 removeQueue.push(task);
12672 var runTasks = function(){
12673 if(removeQueue.length > 0){
12674 for(var i = 0, len = removeQueue.length; i < len; i++){
12675 tasks.remove(removeQueue[i]);
12678 if(tasks.length < 1){
12683 var now = new Date().getTime();
12684 for(var i = 0, len = tasks.length; i < len; ++i){
12686 var itime = now - t.taskRunTime;
12687 if(t.interval <= itime){
12688 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12689 t.taskRunTime = now;
12690 if(rt === false || t.taskRunCount === t.repeat){
12695 if(t.duration && t.duration <= (now - t.taskStartTime)){
12702 * Queues a new task.
12703 * @param {Object} task
12705 this.start = function(task){
12707 task.taskStartTime = new Date().getTime();
12708 task.taskRunTime = 0;
12709 task.taskRunCount = 0;
12714 this.stop = function(task){
12719 this.stopAll = function(){
12721 for(var i = 0, len = tasks.length; i < len; i++){
12722 if(tasks[i].onStop){
12731 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12733 * Ext JS Library 1.1.1
12734 * Copyright(c) 2006-2007, Ext JS, LLC.
12736 * Originally Released Under LGPL - original licence link has changed is not relivant.
12739 * <script type="text/javascript">
12744 * @class Roo.util.MixedCollection
12745 * @extends Roo.util.Observable
12746 * A Collection class that maintains both numeric indexes and keys and exposes events.
12748 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12749 * collection (defaults to false)
12750 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12751 * and return the key value for that item. This is used when available to look up the key on items that
12752 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12753 * equivalent to providing an implementation for the {@link #getKey} method.
12755 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12763 * Fires when the collection is cleared.
12768 * Fires when an item is added to the collection.
12769 * @param {Number} index The index at which the item was added.
12770 * @param {Object} o The item added.
12771 * @param {String} key The key associated with the added item.
12776 * Fires when an item is replaced in the collection.
12777 * @param {String} key he key associated with the new added.
12778 * @param {Object} old The item being replaced.
12779 * @param {Object} new The new item.
12784 * Fires when an item is removed from the collection.
12785 * @param {Object} o The item being removed.
12786 * @param {String} key (optional) The key associated with the removed item.
12791 this.allowFunctions = allowFunctions === true;
12793 this.getKey = keyFn;
12795 Roo.util.MixedCollection.superclass.constructor.call(this);
12798 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12799 allowFunctions : false,
12802 * Adds an item to the collection.
12803 * @param {String} key The key to associate with the item
12804 * @param {Object} o The item to add.
12805 * @return {Object} The item added.
12807 add : function(key, o){
12808 if(arguments.length == 1){
12810 key = this.getKey(o);
12812 if(typeof key == "undefined" || key === null){
12814 this.items.push(o);
12815 this.keys.push(null);
12817 var old = this.map[key];
12819 return this.replace(key, o);
12822 this.items.push(o);
12824 this.keys.push(key);
12826 this.fireEvent("add", this.length-1, o, key);
12831 * MixedCollection has a generic way to fetch keys if you implement getKey.
12834 var mc = new Roo.util.MixedCollection();
12835 mc.add(someEl.dom.id, someEl);
12836 mc.add(otherEl.dom.id, otherEl);
12840 var mc = new Roo.util.MixedCollection();
12841 mc.getKey = function(el){
12847 // or via the constructor
12848 var mc = new Roo.util.MixedCollection(false, function(el){
12854 * @param o {Object} The item for which to find the key.
12855 * @return {Object} The key for the passed item.
12857 getKey : function(o){
12862 * Replaces an item in the collection.
12863 * @param {String} key The key associated with the item to replace, or the item to replace.
12864 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12865 * @return {Object} The new item.
12867 replace : function(key, o){
12868 if(arguments.length == 1){
12870 key = this.getKey(o);
12872 var old = this.item(key);
12873 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12874 return this.add(key, o);
12876 var index = this.indexOfKey(key);
12877 this.items[index] = o;
12879 this.fireEvent("replace", key, old, o);
12884 * Adds all elements of an Array or an Object to the collection.
12885 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12886 * an Array of values, each of which are added to the collection.
12888 addAll : function(objs){
12889 if(arguments.length > 1 || objs instanceof Array){
12890 var args = arguments.length > 1 ? arguments : objs;
12891 for(var i = 0, len = args.length; i < len; i++){
12895 for(var key in objs){
12896 if(this.allowFunctions || typeof objs[key] != "function"){
12897 this.add(key, objs[key]);
12904 * Executes the specified function once for every item in the collection, passing each
12905 * item as the first and only parameter. returning false from the function will stop the iteration.
12906 * @param {Function} fn The function to execute for each item.
12907 * @param {Object} scope (optional) The scope in which to execute the function.
12909 each : function(fn, scope){
12910 var items = [].concat(this.items); // each safe for removal
12911 for(var i = 0, len = items.length; i < len; i++){
12912 if(fn.call(scope || items[i], items[i], i, len) === false){
12919 * Executes the specified function once for every key in the collection, passing each
12920 * key, and its associated item as the first two parameters.
12921 * @param {Function} fn The function to execute for each item.
12922 * @param {Object} scope (optional) The scope in which to execute the function.
12924 eachKey : function(fn, scope){
12925 for(var i = 0, len = this.keys.length; i < len; i++){
12926 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12931 * Returns the first item in the collection which elicits a true return value from the
12932 * passed selection function.
12933 * @param {Function} fn The selection function to execute for each item.
12934 * @param {Object} scope (optional) The scope in which to execute the function.
12935 * @return {Object} The first item in the collection which returned true from the selection function.
12937 find : function(fn, scope){
12938 for(var i = 0, len = this.items.length; i < len; i++){
12939 if(fn.call(scope || window, this.items[i], this.keys[i])){
12940 return this.items[i];
12947 * Inserts an item at the specified index in the collection.
12948 * @param {Number} index The index to insert the item at.
12949 * @param {String} key The key to associate with the new item, or the item itself.
12950 * @param {Object} o (optional) If the second parameter was a key, the new item.
12951 * @return {Object} The item inserted.
12953 insert : function(index, key, o){
12954 if(arguments.length == 2){
12956 key = this.getKey(o);
12958 if(index >= this.length){
12959 return this.add(key, o);
12962 this.items.splice(index, 0, o);
12963 if(typeof key != "undefined" && key != null){
12966 this.keys.splice(index, 0, key);
12967 this.fireEvent("add", index, o, key);
12972 * Removed an item from the collection.
12973 * @param {Object} o The item to remove.
12974 * @return {Object} The item removed.
12976 remove : function(o){
12977 return this.removeAt(this.indexOf(o));
12981 * Remove an item from a specified index in the collection.
12982 * @param {Number} index The index within the collection of the item to remove.
12984 removeAt : function(index){
12985 if(index < this.length && index >= 0){
12987 var o = this.items[index];
12988 this.items.splice(index, 1);
12989 var key = this.keys[index];
12990 if(typeof key != "undefined"){
12991 delete this.map[key];
12993 this.keys.splice(index, 1);
12994 this.fireEvent("remove", o, key);
12999 * Removed an item associated with the passed key fom the collection.
13000 * @param {String} key The key of the item to remove.
13002 removeKey : function(key){
13003 return this.removeAt(this.indexOfKey(key));
13007 * Returns the number of items in the collection.
13008 * @return {Number} the number of items in the collection.
13010 getCount : function(){
13011 return this.length;
13015 * Returns index within the collection of the passed Object.
13016 * @param {Object} o The item to find the index of.
13017 * @return {Number} index of the item.
13019 indexOf : function(o){
13020 if(!this.items.indexOf){
13021 for(var i = 0, len = this.items.length; i < len; i++){
13022 if(this.items[i] == o) return i;
13026 return this.items.indexOf(o);
13031 * Returns index within the collection of the passed key.
13032 * @param {String} key The key to find the index of.
13033 * @return {Number} index of the key.
13035 indexOfKey : function(key){
13036 if(!this.keys.indexOf){
13037 for(var i = 0, len = this.keys.length; i < len; i++){
13038 if(this.keys[i] == key) return i;
13042 return this.keys.indexOf(key);
13047 * Returns the item associated with the passed key OR index. Key has priority over index.
13048 * @param {String/Number} key The key or index of the item.
13049 * @return {Object} The item associated with the passed key.
13051 item : function(key){
13052 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13053 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13057 * Returns the item at the specified index.
13058 * @param {Number} index The index of the item.
13061 itemAt : function(index){
13062 return this.items[index];
13066 * Returns the item associated with the passed key.
13067 * @param {String/Number} key The key of the item.
13068 * @return {Object} The item associated with the passed key.
13070 key : function(key){
13071 return this.map[key];
13075 * Returns true if the collection contains the passed Object as an item.
13076 * @param {Object} o The Object to look for in the collection.
13077 * @return {Boolean} True if the collection contains the Object as an item.
13079 contains : function(o){
13080 return this.indexOf(o) != -1;
13084 * Returns true if the collection contains the passed Object as a key.
13085 * @param {String} key The key to look for in the collection.
13086 * @return {Boolean} True if the collection contains the Object as a key.
13088 containsKey : function(key){
13089 return typeof this.map[key] != "undefined";
13093 * Removes all items from the collection.
13095 clear : function(){
13100 this.fireEvent("clear");
13104 * Returns the first item in the collection.
13105 * @return {Object} the first item in the collection..
13107 first : function(){
13108 return this.items[0];
13112 * Returns the last item in the collection.
13113 * @return {Object} the last item in the collection..
13116 return this.items[this.length-1];
13119 _sort : function(property, dir, fn){
13120 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13121 fn = fn || function(a, b){
13124 var c = [], k = this.keys, items = this.items;
13125 for(var i = 0, len = items.length; i < len; i++){
13126 c[c.length] = {key: k[i], value: items[i], index: i};
13128 c.sort(function(a, b){
13129 var v = fn(a[property], b[property]) * dsc;
13131 v = (a.index < b.index ? -1 : 1);
13135 for(var i = 0, len = c.length; i < len; i++){
13136 items[i] = c[i].value;
13139 this.fireEvent("sort", this);
13143 * Sorts this collection with the passed comparison function
13144 * @param {String} direction (optional) "ASC" or "DESC"
13145 * @param {Function} fn (optional) comparison function
13147 sort : function(dir, fn){
13148 this._sort("value", dir, fn);
13152 * Sorts this collection by keys
13153 * @param {String} direction (optional) "ASC" or "DESC"
13154 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13156 keySort : function(dir, fn){
13157 this._sort("key", dir, fn || function(a, b){
13158 return String(a).toUpperCase()-String(b).toUpperCase();
13163 * Returns a range of items in this collection
13164 * @param {Number} startIndex (optional) defaults to 0
13165 * @param {Number} endIndex (optional) default to the last item
13166 * @return {Array} An array of items
13168 getRange : function(start, end){
13169 var items = this.items;
13170 if(items.length < 1){
13173 start = start || 0;
13174 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13177 for(var i = start; i <= end; i++) {
13178 r[r.length] = items[i];
13181 for(var i = start; i >= end; i--) {
13182 r[r.length] = items[i];
13189 * Filter the <i>objects</i> in this collection by a specific property.
13190 * Returns a new collection that has been filtered.
13191 * @param {String} property A property on your objects
13192 * @param {String/RegExp} value Either string that the property values
13193 * should start with or a RegExp to test against the property
13194 * @return {MixedCollection} The new filtered collection
13196 filter : function(property, value){
13197 if(!value.exec){ // not a regex
13198 value = String(value);
13199 if(value.length == 0){
13200 return this.clone();
13202 value = new RegExp("^" + Roo.escapeRe(value), "i");
13204 return this.filterBy(function(o){
13205 return o && value.test(o[property]);
13210 * Filter by a function. * Returns a new collection that has been filtered.
13211 * The passed function will be called with each
13212 * object in the collection. If the function returns true, the value is included
13213 * otherwise it is filtered.
13214 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13215 * @param {Object} scope (optional) The scope of the function (defaults to this)
13216 * @return {MixedCollection} The new filtered collection
13218 filterBy : function(fn, scope){
13219 var r = new Roo.util.MixedCollection();
13220 r.getKey = this.getKey;
13221 var k = this.keys, it = this.items;
13222 for(var i = 0, len = it.length; i < len; i++){
13223 if(fn.call(scope||this, it[i], k[i])){
13224 r.add(k[i], it[i]);
13231 * Creates a duplicate of this collection
13232 * @return {MixedCollection}
13234 clone : function(){
13235 var r = new Roo.util.MixedCollection();
13236 var k = this.keys, it = this.items;
13237 for(var i = 0, len = it.length; i < len; i++){
13238 r.add(k[i], it[i]);
13240 r.getKey = this.getKey;
13245 * Returns the item associated with the passed key or index.
13247 * @param {String/Number} key The key or index of the item.
13248 * @return {Object} The item associated with the passed key.
13250 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13252 * Ext JS Library 1.1.1
13253 * Copyright(c) 2006-2007, Ext JS, LLC.
13255 * Originally Released Under LGPL - original licence link has changed is not relivant.
13258 * <script type="text/javascript">
13261 * @class Roo.util.JSON
13262 * Modified version of Douglas Crockford"s json.js that doesn"t
13263 * mess with the Object prototype
13264 * http://www.json.org/js.html
13267 Roo.util.JSON = new (function(){
13268 var useHasOwn = {}.hasOwnProperty ? true : false;
13270 // crashes Safari in some instances
13271 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13273 var pad = function(n) {
13274 return n < 10 ? "0" + n : n;
13287 var encodeString = function(s){
13288 if (/["\\\x00-\x1f]/.test(s)) {
13289 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13294 c = b.charCodeAt();
13296 Math.floor(c / 16).toString(16) +
13297 (c % 16).toString(16);
13300 return '"' + s + '"';
13303 var encodeArray = function(o){
13304 var a = ["["], b, i, l = o.length, v;
13305 for (i = 0; i < l; i += 1) {
13307 switch (typeof v) {
13316 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13324 var encodeDate = function(o){
13325 return '"' + o.getFullYear() + "-" +
13326 pad(o.getMonth() + 1) + "-" +
13327 pad(o.getDate()) + "T" +
13328 pad(o.getHours()) + ":" +
13329 pad(o.getMinutes()) + ":" +
13330 pad(o.getSeconds()) + '"';
13334 * Encodes an Object, Array or other value
13335 * @param {Mixed} o The variable to encode
13336 * @return {String} The JSON string
13338 this.encode = function(o)
13340 // should this be extended to fully wrap stringify..
13342 if(typeof o == "undefined" || o === null){
13344 }else if(o instanceof Array){
13345 return encodeArray(o);
13346 }else if(o instanceof Date){
13347 return encodeDate(o);
13348 }else if(typeof o == "string"){
13349 return encodeString(o);
13350 }else if(typeof o == "number"){
13351 return isFinite(o) ? String(o) : "null";
13352 }else if(typeof o == "boolean"){
13355 var a = ["{"], b, i, v;
13357 if(!useHasOwn || o.hasOwnProperty(i)) {
13359 switch (typeof v) {
13368 a.push(this.encode(i), ":",
13369 v === null ? "null" : this.encode(v));
13380 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13381 * @param {String} json The JSON string
13382 * @return {Object} The resulting object
13384 this.decode = function(json){
13386 return /** eval:var:json */ eval("(" + json + ')');
13390 * Shorthand for {@link Roo.util.JSON#encode}
13391 * @member Roo encode
13393 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13395 * Shorthand for {@link Roo.util.JSON#decode}
13396 * @member Roo decode
13398 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13401 * Ext JS Library 1.1.1
13402 * Copyright(c) 2006-2007, Ext JS, LLC.
13404 * Originally Released Under LGPL - original licence link has changed is not relivant.
13407 * <script type="text/javascript">
13411 * @class Roo.util.Format
13412 * Reusable data formatting functions
13415 Roo.util.Format = function(){
13416 var trimRe = /^\s+|\s+$/g;
13419 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13420 * @param {String} value The string to truncate
13421 * @param {Number} length The maximum length to allow before truncating
13422 * @return {String} The converted text
13424 ellipsis : function(value, len){
13425 if(value && value.length > len){
13426 return value.substr(0, len-3)+"...";
13432 * Checks a reference and converts it to empty string if it is undefined
13433 * @param {Mixed} value Reference to check
13434 * @return {Mixed} Empty string if converted, otherwise the original value
13436 undef : function(value){
13437 return typeof value != "undefined" ? value : "";
13441 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13442 * @param {String} value The string to encode
13443 * @return {String} The encoded text
13445 htmlEncode : function(value){
13446 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13450 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13451 * @param {String} value The string to decode
13452 * @return {String} The decoded text
13454 htmlDecode : function(value){
13455 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13459 * Trims any whitespace from either side of a string
13460 * @param {String} value The text to trim
13461 * @return {String} The trimmed text
13463 trim : function(value){
13464 return String(value).replace(trimRe, "");
13468 * Returns a substring from within an original string
13469 * @param {String} value The original text
13470 * @param {Number} start The start index of the substring
13471 * @param {Number} length The length of the substring
13472 * @return {String} The substring
13474 substr : function(value, start, length){
13475 return String(value).substr(start, length);
13479 * Converts a string to all lower case letters
13480 * @param {String} value The text to convert
13481 * @return {String} The converted text
13483 lowercase : function(value){
13484 return String(value).toLowerCase();
13488 * Converts a string to all upper case letters
13489 * @param {String} value The text to convert
13490 * @return {String} The converted text
13492 uppercase : function(value){
13493 return String(value).toUpperCase();
13497 * Converts the first character only of a string to upper case
13498 * @param {String} value The text to convert
13499 * @return {String} The converted text
13501 capitalize : function(value){
13502 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13506 call : function(value, fn){
13507 if(arguments.length > 2){
13508 var args = Array.prototype.slice.call(arguments, 2);
13509 args.unshift(value);
13511 return /** eval:var:value */ eval(fn).apply(window, args);
13513 /** eval:var:value */
13514 return /** eval:var:value */ eval(fn).call(window, value);
13520 * safer version of Math.toFixed..??/
13521 * @param {Number/String} value The numeric value to format
13522 * @param {Number/String} value Decimal places
13523 * @return {String} The formatted currency string
13525 toFixed : function(v, n)
13527 // why not use to fixed - precision is buggered???
13529 return Math.round(v-0);
13531 var fact = Math.pow(10,n+1);
13532 v = (Math.round((v-0)*fact))/fact;
13533 var z = (''+fact).substring(2);
13534 if (v == Math.floor(v)) {
13535 return Math.floor(v) + '.' + z;
13538 // now just padd decimals..
13539 var ps = String(v).split('.');
13540 var fd = (ps[1] + z);
13541 var r = fd.substring(0,n);
13542 var rm = fd.substring(n);
13544 return ps[0] + '.' + r;
13546 r*=1; // turn it into a number;
13548 if (String(r).length != n) {
13551 r = String(r).substring(1); // chop the end off.
13554 return ps[0] + '.' + r;
13559 * Format a number as US currency
13560 * @param {Number/String} value The numeric value to format
13561 * @return {String} The formatted currency string
13563 usMoney : function(v){
13564 return '$' + Roo.util.Format.number(v);
13569 * eventually this should probably emulate php's number_format
13570 * @param {Number/String} value The numeric value to format
13571 * @param {Number} decimals number of decimal places
13572 * @return {String} The formatted currency string
13574 number : function(v,decimals)
13576 // multiply and round.
13577 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13578 var mul = Math.pow(10, decimals);
13579 var zero = String(mul).substring(1);
13580 v = (Math.round((v-0)*mul))/mul;
13582 // if it's '0' number.. then
13584 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13586 var ps = v.split('.');
13590 var r = /(\d+)(\d{3})/;
13592 while (r.test(whole)) {
13593 whole = whole.replace(r, '$1' + ',' + '$2');
13599 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13600 // does not have decimals
13601 (decimals ? ('.' + zero) : '');
13604 return whole + sub ;
13608 * Parse a value into a formatted date using the specified format pattern.
13609 * @param {Mixed} value The value to format
13610 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13611 * @return {String} The formatted date string
13613 date : function(v, format){
13617 if(!(v instanceof Date)){
13618 v = new Date(Date.parse(v));
13620 return v.dateFormat(format || Roo.util.Format.defaults.date);
13624 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13625 * @param {String} format Any valid date format string
13626 * @return {Function} The date formatting function
13628 dateRenderer : function(format){
13629 return function(v){
13630 return Roo.util.Format.date(v, format);
13635 stripTagsRE : /<\/?[^>]+>/gi,
13638 * Strips all HTML tags
13639 * @param {Mixed} value The text from which to strip tags
13640 * @return {String} The stripped text
13642 stripTags : function(v){
13643 return !v ? v : String(v).replace(this.stripTagsRE, "");
13647 Roo.util.Format.defaults = {
13651 * Ext JS Library 1.1.1
13652 * Copyright(c) 2006-2007, Ext JS, LLC.
13654 * Originally Released Under LGPL - original licence link has changed is not relivant.
13657 * <script type="text/javascript">
13664 * @class Roo.MasterTemplate
13665 * @extends Roo.Template
13666 * Provides a template that can have child templates. The syntax is:
13668 var t = new Roo.MasterTemplate(
13669 '<select name="{name}">',
13670 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13673 t.add('options', {value: 'foo', text: 'bar'});
13674 // or you can add multiple child elements in one shot
13675 t.addAll('options', [
13676 {value: 'foo', text: 'bar'},
13677 {value: 'foo2', text: 'bar2'},
13678 {value: 'foo3', text: 'bar3'}
13680 // then append, applying the master template values
13681 t.append('my-form', {name: 'my-select'});
13683 * A name attribute for the child template is not required if you have only one child
13684 * template or you want to refer to them by index.
13686 Roo.MasterTemplate = function(){
13687 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13688 this.originalHtml = this.html;
13690 var m, re = this.subTemplateRe;
13693 while(m = re.exec(this.html)){
13694 var name = m[1], content = m[2];
13699 tpl : new Roo.Template(content)
13702 st[name] = st[subIndex];
13704 st[subIndex].tpl.compile();
13705 st[subIndex].tpl.call = this.call.createDelegate(this);
13708 this.subCount = subIndex;
13711 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13713 * The regular expression used to match sub templates
13717 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13720 * Applies the passed values to a child template.
13721 * @param {String/Number} name (optional) The name or index of the child template
13722 * @param {Array/Object} values The values to be applied to the template
13723 * @return {MasterTemplate} this
13725 add : function(name, values){
13726 if(arguments.length == 1){
13727 values = arguments[0];
13730 var s = this.subs[name];
13731 s.buffer[s.buffer.length] = s.tpl.apply(values);
13736 * Applies all the passed values to a child template.
13737 * @param {String/Number} name (optional) The name or index of the child template
13738 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13739 * @param {Boolean} reset (optional) True to reset the template first
13740 * @return {MasterTemplate} this
13742 fill : function(name, values, reset){
13744 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13752 for(var i = 0, len = values.length; i < len; i++){
13753 this.add(name, values[i]);
13759 * Resets the template for reuse
13760 * @return {MasterTemplate} this
13762 reset : function(){
13764 for(var i = 0; i < this.subCount; i++){
13770 applyTemplate : function(values){
13772 var replaceIndex = -1;
13773 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13774 return s[++replaceIndex].buffer.join("");
13776 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13779 apply : function(){
13780 return this.applyTemplate.apply(this, arguments);
13783 compile : function(){return this;}
13787 * Alias for fill().
13790 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13792 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13793 * var tpl = Roo.MasterTemplate.from('element-id');
13794 * @param {String/HTMLElement} el
13795 * @param {Object} config
13798 Roo.MasterTemplate.from = function(el, config){
13799 el = Roo.getDom(el);
13800 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13803 * Ext JS Library 1.1.1
13804 * Copyright(c) 2006-2007, Ext JS, LLC.
13806 * Originally Released Under LGPL - original licence link has changed is not relivant.
13809 * <script type="text/javascript">
13814 * @class Roo.util.CSS
13815 * Utility class for manipulating CSS rules
13818 Roo.util.CSS = function(){
13820 var doc = document;
13822 var camelRe = /(-[a-z])/gi;
13823 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13827 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13828 * tag and appended to the HEAD of the document.
13829 * @param {String|Object} cssText The text containing the css rules
13830 * @param {String} id An id to add to the stylesheet for later removal
13831 * @return {StyleSheet}
13833 createStyleSheet : function(cssText, id){
13835 var head = doc.getElementsByTagName("head")[0];
13836 var nrules = doc.createElement("style");
13837 nrules.setAttribute("type", "text/css");
13839 nrules.setAttribute("id", id);
13841 if (typeof(cssText) != 'string') {
13842 // support object maps..
13843 // not sure if this a good idea..
13844 // perhaps it should be merged with the general css handling
13845 // and handle js style props.
13846 var cssTextNew = [];
13847 for(var n in cssText) {
13849 for(var k in cssText[n]) {
13850 citems.push( k + ' : ' +cssText[n][k] + ';' );
13852 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13855 cssText = cssTextNew.join("\n");
13861 head.appendChild(nrules);
13862 ss = nrules.styleSheet;
13863 ss.cssText = cssText;
13866 nrules.appendChild(doc.createTextNode(cssText));
13868 nrules.cssText = cssText;
13870 head.appendChild(nrules);
13871 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13873 this.cacheStyleSheet(ss);
13878 * Removes a style or link tag by id
13879 * @param {String} id The id of the tag
13881 removeStyleSheet : function(id){
13882 var existing = doc.getElementById(id);
13884 existing.parentNode.removeChild(existing);
13889 * Dynamically swaps an existing stylesheet reference for a new one
13890 * @param {String} id The id of an existing link tag to remove
13891 * @param {String} url The href of the new stylesheet to include
13893 swapStyleSheet : function(id, url){
13894 this.removeStyleSheet(id);
13895 var ss = doc.createElement("link");
13896 ss.setAttribute("rel", "stylesheet");
13897 ss.setAttribute("type", "text/css");
13898 ss.setAttribute("id", id);
13899 ss.setAttribute("href", url);
13900 doc.getElementsByTagName("head")[0].appendChild(ss);
13904 * Refresh the rule cache if you have dynamically added stylesheets
13905 * @return {Object} An object (hash) of rules indexed by selector
13907 refreshCache : function(){
13908 return this.getRules(true);
13912 cacheStyleSheet : function(stylesheet){
13916 try{// try catch for cross domain access issue
13917 var ssRules = stylesheet.cssRules || stylesheet.rules;
13918 for(var j = ssRules.length-1; j >= 0; --j){
13919 rules[ssRules[j].selectorText] = ssRules[j];
13925 * Gets all css rules for the document
13926 * @param {Boolean} refreshCache true to refresh the internal cache
13927 * @return {Object} An object (hash) of rules indexed by selector
13929 getRules : function(refreshCache){
13930 if(rules == null || refreshCache){
13932 var ds = doc.styleSheets;
13933 for(var i =0, len = ds.length; i < len; i++){
13935 this.cacheStyleSheet(ds[i]);
13943 * Gets an an individual CSS rule by selector(s)
13944 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13945 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13946 * @return {CSSRule} The CSS rule or null if one is not found
13948 getRule : function(selector, refreshCache){
13949 var rs = this.getRules(refreshCache);
13950 if(!(selector instanceof Array)){
13951 return rs[selector];
13953 for(var i = 0; i < selector.length; i++){
13954 if(rs[selector[i]]){
13955 return rs[selector[i]];
13963 * Updates a rule property
13964 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13965 * @param {String} property The css property
13966 * @param {String} value The new value for the property
13967 * @return {Boolean} true If a rule was found and updated
13969 updateRule : function(selector, property, value){
13970 if(!(selector instanceof Array)){
13971 var rule = this.getRule(selector);
13973 rule.style[property.replace(camelRe, camelFn)] = value;
13977 for(var i = 0; i < selector.length; i++){
13978 if(this.updateRule(selector[i], property, value)){
13988 * Ext JS Library 1.1.1
13989 * Copyright(c) 2006-2007, Ext JS, LLC.
13991 * Originally Released Under LGPL - original licence link has changed is not relivant.
13994 * <script type="text/javascript">
14000 * @class Roo.util.ClickRepeater
14001 * @extends Roo.util.Observable
14003 * A wrapper class which can be applied to any element. Fires a "click" event while the
14004 * mouse is pressed. The interval between firings may be specified in the config but
14005 * defaults to 10 milliseconds.
14007 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14009 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14010 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14011 * Similar to an autorepeat key delay.
14012 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14013 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14014 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14015 * "interval" and "delay" are ignored. "immediate" is honored.
14016 * @cfg {Boolean} preventDefault True to prevent the default click event
14017 * @cfg {Boolean} stopDefault True to stop the default click event
14020 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14021 * 2007-02-02 jvs Renamed to ClickRepeater
14022 * 2007-02-03 jvs Modifications for FF Mac and Safari
14025 * @param {String/HTMLElement/Element} el The element to listen on
14026 * @param {Object} config
14028 Roo.util.ClickRepeater = function(el, config)
14030 this.el = Roo.get(el);
14031 this.el.unselectable();
14033 Roo.apply(this, config);
14038 * Fires when the mouse button is depressed.
14039 * @param {Roo.util.ClickRepeater} this
14041 "mousedown" : true,
14044 * Fires on a specified interval during the time the element is pressed.
14045 * @param {Roo.util.ClickRepeater} this
14050 * Fires when the mouse key is released.
14051 * @param {Roo.util.ClickRepeater} this
14056 this.el.on("mousedown", this.handleMouseDown, this);
14057 if(this.preventDefault || this.stopDefault){
14058 this.el.on("click", function(e){
14059 if(this.preventDefault){
14060 e.preventDefault();
14062 if(this.stopDefault){
14068 // allow inline handler
14070 this.on("click", this.handler, this.scope || this);
14073 Roo.util.ClickRepeater.superclass.constructor.call(this);
14076 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14079 preventDefault : true,
14080 stopDefault : false,
14084 handleMouseDown : function(){
14085 clearTimeout(this.timer);
14087 if(this.pressClass){
14088 this.el.addClass(this.pressClass);
14090 this.mousedownTime = new Date();
14092 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14093 this.el.on("mouseout", this.handleMouseOut, this);
14095 this.fireEvent("mousedown", this);
14096 this.fireEvent("click", this);
14098 this.timer = this.click.defer(this.delay || this.interval, this);
14102 click : function(){
14103 this.fireEvent("click", this);
14104 this.timer = this.click.defer(this.getInterval(), this);
14108 getInterval: function(){
14109 if(!this.accelerate){
14110 return this.interval;
14112 var pressTime = this.mousedownTime.getElapsed();
14113 if(pressTime < 500){
14115 }else if(pressTime < 1700){
14117 }else if(pressTime < 2600){
14119 }else if(pressTime < 3500){
14121 }else if(pressTime < 4400){
14123 }else if(pressTime < 5300){
14125 }else if(pressTime < 6200){
14133 handleMouseOut : function(){
14134 clearTimeout(this.timer);
14135 if(this.pressClass){
14136 this.el.removeClass(this.pressClass);
14138 this.el.on("mouseover", this.handleMouseReturn, this);
14142 handleMouseReturn : function(){
14143 this.el.un("mouseover", this.handleMouseReturn);
14144 if(this.pressClass){
14145 this.el.addClass(this.pressClass);
14151 handleMouseUp : function(){
14152 clearTimeout(this.timer);
14153 this.el.un("mouseover", this.handleMouseReturn);
14154 this.el.un("mouseout", this.handleMouseOut);
14155 Roo.get(document).un("mouseup", this.handleMouseUp);
14156 this.el.removeClass(this.pressClass);
14157 this.fireEvent("mouseup", this);
14161 * Ext JS Library 1.1.1
14162 * Copyright(c) 2006-2007, Ext JS, LLC.
14164 * Originally Released Under LGPL - original licence link has changed is not relivant.
14167 * <script type="text/javascript">
14172 * @class Roo.KeyNav
14173 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14174 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14175 * way to implement custom navigation schemes for any UI component.</p>
14176 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14177 * pageUp, pageDown, del, home, end. Usage:</p>
14179 var nav = new Roo.KeyNav("my-element", {
14180 "left" : function(e){
14181 this.moveLeft(e.ctrlKey);
14183 "right" : function(e){
14184 this.moveRight(e.ctrlKey);
14186 "enter" : function(e){
14193 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14194 * @param {Object} config The config
14196 Roo.KeyNav = function(el, config){
14197 this.el = Roo.get(el);
14198 Roo.apply(this, config);
14199 if(!this.disabled){
14200 this.disabled = true;
14205 Roo.KeyNav.prototype = {
14207 * @cfg {Boolean} disabled
14208 * True to disable this KeyNav instance (defaults to false)
14212 * @cfg {String} defaultEventAction
14213 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14214 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14215 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14217 defaultEventAction: "stopEvent",
14219 * @cfg {Boolean} forceKeyDown
14220 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14221 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14222 * handle keydown instead of keypress.
14224 forceKeyDown : false,
14227 prepareEvent : function(e){
14228 var k = e.getKey();
14229 var h = this.keyToHandler[k];
14230 //if(h && this[h]){
14231 // e.stopPropagation();
14233 if(Roo.isSafari && h && k >= 37 && k <= 40){
14239 relay : function(e){
14240 var k = e.getKey();
14241 var h = this.keyToHandler[k];
14243 if(this.doRelay(e, this[h], h) !== true){
14244 e[this.defaultEventAction]();
14250 doRelay : function(e, h, hname){
14251 return h.call(this.scope || this, e);
14254 // possible handlers
14268 // quick lookup hash
14285 * Enable this KeyNav
14287 enable: function(){
14289 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14290 // the EventObject will normalize Safari automatically
14291 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14292 this.el.on("keydown", this.relay, this);
14294 this.el.on("keydown", this.prepareEvent, this);
14295 this.el.on("keypress", this.relay, this);
14297 this.disabled = false;
14302 * Disable this KeyNav
14304 disable: function(){
14305 if(!this.disabled){
14306 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14307 this.el.un("keydown", this.relay);
14309 this.el.un("keydown", this.prepareEvent);
14310 this.el.un("keypress", this.relay);
14312 this.disabled = true;
14317 * Ext JS Library 1.1.1
14318 * Copyright(c) 2006-2007, Ext JS, LLC.
14320 * Originally Released Under LGPL - original licence link has changed is not relivant.
14323 * <script type="text/javascript">
14328 * @class Roo.KeyMap
14329 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14330 * The constructor accepts the same config object as defined by {@link #addBinding}.
14331 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14332 * combination it will call the function with this signature (if the match is a multi-key
14333 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14334 * A KeyMap can also handle a string representation of keys.<br />
14337 // map one key by key code
14338 var map = new Roo.KeyMap("my-element", {
14339 key: 13, // or Roo.EventObject.ENTER
14344 // map multiple keys to one action by string
14345 var map = new Roo.KeyMap("my-element", {
14351 // map multiple keys to multiple actions by strings and array of codes
14352 var map = new Roo.KeyMap("my-element", [
14355 fn: function(){ alert("Return was pressed"); }
14358 fn: function(){ alert('a, b or c was pressed'); }
14363 fn: function(){ alert('Control + shift + tab was pressed.'); }
14367 * <b>Note: A KeyMap starts enabled</b>
14369 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14370 * @param {Object} config The config (see {@link #addBinding})
14371 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14373 Roo.KeyMap = function(el, config, eventName){
14374 this.el = Roo.get(el);
14375 this.eventName = eventName || "keydown";
14376 this.bindings = [];
14378 this.addBinding(config);
14383 Roo.KeyMap.prototype = {
14385 * True to stop the event from bubbling and prevent the default browser action if the
14386 * key was handled by the KeyMap (defaults to false)
14392 * Add a new binding to this KeyMap. The following config object properties are supported:
14394 Property Type Description
14395 ---------- --------------- ----------------------------------------------------------------------
14396 key String/Array A single keycode or an array of keycodes to handle
14397 shift Boolean True to handle key only when shift is pressed (defaults to false)
14398 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14399 alt Boolean True to handle key only when alt is pressed (defaults to false)
14400 fn Function The function to call when KeyMap finds the expected key combination
14401 scope Object The scope of the callback function
14407 var map = new Roo.KeyMap(document, {
14408 key: Roo.EventObject.ENTER,
14413 //Add a new binding to the existing KeyMap later
14421 * @param {Object/Array} config A single KeyMap config or an array of configs
14423 addBinding : function(config){
14424 if(config instanceof Array){
14425 for(var i = 0, len = config.length; i < len; i++){
14426 this.addBinding(config[i]);
14430 var keyCode = config.key,
14431 shift = config.shift,
14432 ctrl = config.ctrl,
14435 scope = config.scope;
14436 if(typeof keyCode == "string"){
14438 var keyString = keyCode.toUpperCase();
14439 for(var j = 0, len = keyString.length; j < len; j++){
14440 ks.push(keyString.charCodeAt(j));
14444 var keyArray = keyCode instanceof Array;
14445 var handler = function(e){
14446 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14447 var k = e.getKey();
14449 for(var i = 0, len = keyCode.length; i < len; i++){
14450 if(keyCode[i] == k){
14451 if(this.stopEvent){
14454 fn.call(scope || window, k, e);
14460 if(this.stopEvent){
14463 fn.call(scope || window, k, e);
14468 this.bindings.push(handler);
14472 * Shorthand for adding a single key listener
14473 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14474 * following options:
14475 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14476 * @param {Function} fn The function to call
14477 * @param {Object} scope (optional) The scope of the function
14479 on : function(key, fn, scope){
14480 var keyCode, shift, ctrl, alt;
14481 if(typeof key == "object" && !(key instanceof Array)){
14500 handleKeyDown : function(e){
14501 if(this.enabled){ //just in case
14502 var b = this.bindings;
14503 for(var i = 0, len = b.length; i < len; i++){
14504 b[i].call(this, e);
14510 * Returns true if this KeyMap is enabled
14511 * @return {Boolean}
14513 isEnabled : function(){
14514 return this.enabled;
14518 * Enables this KeyMap
14520 enable: function(){
14522 this.el.on(this.eventName, this.handleKeyDown, this);
14523 this.enabled = true;
14528 * Disable this KeyMap
14530 disable: function(){
14532 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14533 this.enabled = false;
14538 * Ext JS Library 1.1.1
14539 * Copyright(c) 2006-2007, Ext JS, LLC.
14541 * Originally Released Under LGPL - original licence link has changed is not relivant.
14544 * <script type="text/javascript">
14549 * @class Roo.util.TextMetrics
14550 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14551 * wide, in pixels, a given block of text will be.
14554 Roo.util.TextMetrics = function(){
14558 * Measures the size of the specified text
14559 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14560 * that can affect the size of the rendered text
14561 * @param {String} text The text to measure
14562 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14563 * in order to accurately measure the text height
14564 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14566 measure : function(el, text, fixedWidth){
14568 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14571 shared.setFixedWidth(fixedWidth || 'auto');
14572 return shared.getSize(text);
14576 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14577 * the overhead of multiple calls to initialize the style properties on each measurement.
14578 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14579 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14580 * in order to accurately measure the text height
14581 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14583 createInstance : function(el, fixedWidth){
14584 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14591 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14592 var ml = new Roo.Element(document.createElement('div'));
14593 document.body.appendChild(ml.dom);
14594 ml.position('absolute');
14595 ml.setLeftTop(-1000, -1000);
14599 ml.setWidth(fixedWidth);
14604 * Returns the size of the specified text based on the internal element's style and width properties
14605 * @memberOf Roo.util.TextMetrics.Instance#
14606 * @param {String} text The text to measure
14607 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14609 getSize : function(text){
14611 var s = ml.getSize();
14617 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14618 * that can affect the size of the rendered text
14619 * @memberOf Roo.util.TextMetrics.Instance#
14620 * @param {String/HTMLElement} el The element, dom node or id
14622 bind : function(el){
14624 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14629 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14630 * to set a fixed width in order to accurately measure the text height.
14631 * @memberOf Roo.util.TextMetrics.Instance#
14632 * @param {Number} width The width to set on the element
14634 setFixedWidth : function(width){
14635 ml.setWidth(width);
14639 * Returns the measured width of the specified text
14640 * @memberOf Roo.util.TextMetrics.Instance#
14641 * @param {String} text The text to measure
14642 * @return {Number} width The width in pixels
14644 getWidth : function(text){
14645 ml.dom.style.width = 'auto';
14646 return this.getSize(text).width;
14650 * Returns the measured height of the specified text. For multiline text, be sure to call
14651 * {@link #setFixedWidth} if necessary.
14652 * @memberOf Roo.util.TextMetrics.Instance#
14653 * @param {String} text The text to measure
14654 * @return {Number} height The height in pixels
14656 getHeight : function(text){
14657 return this.getSize(text).height;
14661 instance.bind(bindTo);
14666 // backwards compat
14667 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14669 * Ext JS Library 1.1.1
14670 * Copyright(c) 2006-2007, Ext JS, LLC.
14672 * Originally Released Under LGPL - original licence link has changed is not relivant.
14675 * <script type="text/javascript">
14679 * @class Roo.state.Provider
14680 * Abstract base class for state provider implementations. This class provides methods
14681 * for encoding and decoding <b>typed</b> variables including dates and defines the
14682 * Provider interface.
14684 Roo.state.Provider = function(){
14686 * @event statechange
14687 * Fires when a state change occurs.
14688 * @param {Provider} this This state provider
14689 * @param {String} key The state key which was changed
14690 * @param {String} value The encoded value for the state
14693 "statechange": true
14696 Roo.state.Provider.superclass.constructor.call(this);
14698 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14700 * Returns the current value for a key
14701 * @param {String} name The key name
14702 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14703 * @return {Mixed} The state data
14705 get : function(name, defaultValue){
14706 return typeof this.state[name] == "undefined" ?
14707 defaultValue : this.state[name];
14711 * Clears a value from the state
14712 * @param {String} name The key name
14714 clear : function(name){
14715 delete this.state[name];
14716 this.fireEvent("statechange", this, name, null);
14720 * Sets the value for a key
14721 * @param {String} name The key name
14722 * @param {Mixed} value The value to set
14724 set : function(name, value){
14725 this.state[name] = value;
14726 this.fireEvent("statechange", this, name, value);
14730 * Decodes a string previously encoded with {@link #encodeValue}.
14731 * @param {String} value The value to decode
14732 * @return {Mixed} The decoded value
14734 decodeValue : function(cookie){
14735 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14736 var matches = re.exec(unescape(cookie));
14737 if(!matches || !matches[1]) return; // non state cookie
14738 var type = matches[1];
14739 var v = matches[2];
14742 return parseFloat(v);
14744 return new Date(Date.parse(v));
14749 var values = v.split("^");
14750 for(var i = 0, len = values.length; i < len; i++){
14751 all.push(this.decodeValue(values[i]));
14756 var values = v.split("^");
14757 for(var i = 0, len = values.length; i < len; i++){
14758 var kv = values[i].split("=");
14759 all[kv[0]] = this.decodeValue(kv[1]);
14768 * Encodes a value including type information. Decode with {@link #decodeValue}.
14769 * @param {Mixed} value The value to encode
14770 * @return {String} The encoded value
14772 encodeValue : function(v){
14774 if(typeof v == "number"){
14776 }else if(typeof v == "boolean"){
14777 enc = "b:" + (v ? "1" : "0");
14778 }else if(v instanceof Date){
14779 enc = "d:" + v.toGMTString();
14780 }else if(v instanceof Array){
14782 for(var i = 0, len = v.length; i < len; i++){
14783 flat += this.encodeValue(v[i]);
14784 if(i != len-1) flat += "^";
14787 }else if(typeof v == "object"){
14790 if(typeof v[key] != "function"){
14791 flat += key + "=" + this.encodeValue(v[key]) + "^";
14794 enc = "o:" + flat.substring(0, flat.length-1);
14798 return escape(enc);
14804 * Ext JS Library 1.1.1
14805 * Copyright(c) 2006-2007, Ext JS, LLC.
14807 * Originally Released Under LGPL - original licence link has changed is not relivant.
14810 * <script type="text/javascript">
14813 * @class Roo.state.Manager
14814 * This is the global state manager. By default all components that are "state aware" check this class
14815 * for state information if you don't pass them a custom state provider. In order for this class
14816 * to be useful, it must be initialized with a provider when your application initializes.
14818 // in your initialization function
14820 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14822 // supposed you have a {@link Roo.BorderLayout}
14823 var layout = new Roo.BorderLayout(...);
14824 layout.restoreState();
14825 // or a {Roo.BasicDialog}
14826 var dialog = new Roo.BasicDialog(...);
14827 dialog.restoreState();
14831 Roo.state.Manager = function(){
14832 var provider = new Roo.state.Provider();
14836 * Configures the default state provider for your application
14837 * @param {Provider} stateProvider The state provider to set
14839 setProvider : function(stateProvider){
14840 provider = stateProvider;
14844 * Returns the current value for a key
14845 * @param {String} name The key name
14846 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14847 * @return {Mixed} The state data
14849 get : function(key, defaultValue){
14850 return provider.get(key, defaultValue);
14854 * Sets the value for a key
14855 * @param {String} name The key name
14856 * @param {Mixed} value The state data
14858 set : function(key, value){
14859 provider.set(key, value);
14863 * Clears a value from the state
14864 * @param {String} name The key name
14866 clear : function(key){
14867 provider.clear(key);
14871 * Gets the currently configured state provider
14872 * @return {Provider} The state provider
14874 getProvider : function(){
14881 * Ext JS Library 1.1.1
14882 * Copyright(c) 2006-2007, Ext JS, LLC.
14884 * Originally Released Under LGPL - original licence link has changed is not relivant.
14887 * <script type="text/javascript">
14890 * @class Roo.state.CookieProvider
14891 * @extends Roo.state.Provider
14892 * The default Provider implementation which saves state via cookies.
14895 var cp = new Roo.state.CookieProvider({
14897 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14898 domain: "roojs.com"
14900 Roo.state.Manager.setProvider(cp);
14902 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14903 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14904 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14905 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14906 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14907 * domain the page is running on including the 'www' like 'www.roojs.com')
14908 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14910 * Create a new CookieProvider
14911 * @param {Object} config The configuration object
14913 Roo.state.CookieProvider = function(config){
14914 Roo.state.CookieProvider.superclass.constructor.call(this);
14916 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14917 this.domain = null;
14918 this.secure = false;
14919 Roo.apply(this, config);
14920 this.state = this.readCookies();
14923 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14925 set : function(name, value){
14926 if(typeof value == "undefined" || value === null){
14930 this.setCookie(name, value);
14931 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14935 clear : function(name){
14936 this.clearCookie(name);
14937 Roo.state.CookieProvider.superclass.clear.call(this, name);
14941 readCookies : function(){
14943 var c = document.cookie + ";";
14944 var re = /\s?(.*?)=(.*?);/g;
14946 while((matches = re.exec(c)) != null){
14947 var name = matches[1];
14948 var value = matches[2];
14949 if(name && name.substring(0,3) == "ys-"){
14950 cookies[name.substr(3)] = this.decodeValue(value);
14957 setCookie : function(name, value){
14958 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14959 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14960 ((this.path == null) ? "" : ("; path=" + this.path)) +
14961 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14962 ((this.secure == true) ? "; secure" : "");
14966 clearCookie : function(name){
14967 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14968 ((this.path == null) ? "" : ("; path=" + this.path)) +
14969 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14970 ((this.secure == true) ? "; secure" : "");
14974 * Ext JS Library 1.1.1
14975 * Copyright(c) 2006-2007, Ext JS, LLC.
14977 * Originally Released Under LGPL - original licence link has changed is not relivant.
14980 * <script type="text/javascript">
14985 * @class Roo.ComponentMgr
14986 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14989 Roo.ComponentMgr = function(){
14990 var all = new Roo.util.MixedCollection();
14994 * Registers a component.
14995 * @param {Roo.Component} c The component
14997 register : function(c){
15002 * Unregisters a component.
15003 * @param {Roo.Component} c The component
15005 unregister : function(c){
15010 * Returns a component by id
15011 * @param {String} id The component id
15013 get : function(id){
15014 return all.get(id);
15018 * Registers a function that will be called when a specified component is added to ComponentMgr
15019 * @param {String} id The component id
15020 * @param {Funtction} fn The callback function
15021 * @param {Object} scope The scope of the callback
15023 onAvailable : function(id, fn, scope){
15024 all.on("add", function(index, o){
15026 fn.call(scope || o, o);
15027 all.un("add", fn, scope);
15034 * Ext JS Library 1.1.1
15035 * Copyright(c) 2006-2007, Ext JS, LLC.
15037 * Originally Released Under LGPL - original licence link has changed is not relivant.
15040 * <script type="text/javascript">
15044 * @class Roo.Component
15045 * @extends Roo.util.Observable
15046 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15047 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15048 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15049 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15050 * All visual components (widgets) that require rendering into a layout should subclass Component.
15052 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15053 * 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
15054 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15056 Roo.Component = function(config){
15057 config = config || {};
15058 if(config.tagName || config.dom || typeof config == "string"){ // element object
15059 config = {el: config, id: config.id || config};
15061 this.initialConfig = config;
15063 Roo.apply(this, config);
15067 * Fires after the component is disabled.
15068 * @param {Roo.Component} this
15073 * Fires after the component is enabled.
15074 * @param {Roo.Component} this
15078 * @event beforeshow
15079 * Fires before the component is shown. Return false to stop the show.
15080 * @param {Roo.Component} this
15085 * Fires after the component is shown.
15086 * @param {Roo.Component} this
15090 * @event beforehide
15091 * Fires before the component is hidden. Return false to stop the hide.
15092 * @param {Roo.Component} this
15097 * Fires after the component is hidden.
15098 * @param {Roo.Component} this
15102 * @event beforerender
15103 * Fires before the component is rendered. Return false to stop the render.
15104 * @param {Roo.Component} this
15106 beforerender : true,
15109 * Fires after the component is rendered.
15110 * @param {Roo.Component} this
15114 * @event beforedestroy
15115 * Fires before the component is destroyed. Return false to stop the destroy.
15116 * @param {Roo.Component} this
15118 beforedestroy : true,
15121 * Fires after the component is destroyed.
15122 * @param {Roo.Component} this
15127 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15129 Roo.ComponentMgr.register(this);
15130 Roo.Component.superclass.constructor.call(this);
15131 this.initComponent();
15132 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15133 this.render(this.renderTo);
15134 delete this.renderTo;
15139 Roo.Component.AUTO_ID = 1000;
15141 Roo.extend(Roo.Component, Roo.util.Observable, {
15143 * @scope Roo.Component.prototype
15145 * true if this component is hidden. Read-only.
15150 * true if this component is disabled. Read-only.
15155 * true if this component has been rendered. Read-only.
15159 /** @cfg {String} disableClass
15160 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15162 disabledClass : "x-item-disabled",
15163 /** @cfg {Boolean} allowDomMove
15164 * Whether the component can move the Dom node when rendering (defaults to true).
15166 allowDomMove : true,
15167 /** @cfg {String} hideMode
15168 * How this component should hidden. Supported values are
15169 * "visibility" (css visibility), "offsets" (negative offset position) and
15170 * "display" (css display) - defaults to "display".
15172 hideMode: 'display',
15175 ctype : "Roo.Component",
15178 * @cfg {String} actionMode
15179 * which property holds the element that used for hide() / show() / disable() / enable()
15185 getActionEl : function(){
15186 return this[this.actionMode];
15189 initComponent : Roo.emptyFn,
15191 * If this is a lazy rendering component, render it to its container element.
15192 * @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.
15194 render : function(container, position){
15195 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15196 if(!container && this.el){
15197 this.el = Roo.get(this.el);
15198 container = this.el.dom.parentNode;
15199 this.allowDomMove = false;
15201 this.container = Roo.get(container);
15202 this.rendered = true;
15203 if(position !== undefined){
15204 if(typeof position == 'number'){
15205 position = this.container.dom.childNodes[position];
15207 position = Roo.getDom(position);
15210 this.onRender(this.container, position || null);
15212 this.el.addClass(this.cls);
15216 this.el.applyStyles(this.style);
15219 this.fireEvent("render", this);
15220 this.afterRender(this.container);
15232 // default function is not really useful
15233 onRender : function(ct, position){
15235 this.el = Roo.get(this.el);
15236 if(this.allowDomMove !== false){
15237 ct.dom.insertBefore(this.el.dom, position);
15243 getAutoCreate : function(){
15244 var cfg = typeof this.autoCreate == "object" ?
15245 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15246 if(this.id && !cfg.id){
15253 afterRender : Roo.emptyFn,
15256 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15257 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15259 destroy : function(){
15260 if(this.fireEvent("beforedestroy", this) !== false){
15261 this.purgeListeners();
15262 this.beforeDestroy();
15264 this.el.removeAllListeners();
15266 if(this.actionMode == "container"){
15267 this.container.remove();
15271 Roo.ComponentMgr.unregister(this);
15272 this.fireEvent("destroy", this);
15277 beforeDestroy : function(){
15282 onDestroy : function(){
15287 * Returns the underlying {@link Roo.Element}.
15288 * @return {Roo.Element} The element
15290 getEl : function(){
15295 * Returns the id of this component.
15298 getId : function(){
15303 * Try to focus this component.
15304 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15305 * @return {Roo.Component} this
15307 focus : function(selectText){
15310 if(selectText === true){
15311 this.el.dom.select();
15326 * Disable this component.
15327 * @return {Roo.Component} this
15329 disable : function(){
15333 this.disabled = true;
15334 this.fireEvent("disable", this);
15339 onDisable : function(){
15340 this.getActionEl().addClass(this.disabledClass);
15341 this.el.dom.disabled = true;
15345 * Enable this component.
15346 * @return {Roo.Component} this
15348 enable : function(){
15352 this.disabled = false;
15353 this.fireEvent("enable", this);
15358 onEnable : function(){
15359 this.getActionEl().removeClass(this.disabledClass);
15360 this.el.dom.disabled = false;
15364 * Convenience function for setting disabled/enabled by boolean.
15365 * @param {Boolean} disabled
15367 setDisabled : function(disabled){
15368 this[disabled ? "disable" : "enable"]();
15372 * Show this component.
15373 * @return {Roo.Component} this
15376 if(this.fireEvent("beforeshow", this) !== false){
15377 this.hidden = false;
15381 this.fireEvent("show", this);
15387 onShow : function(){
15388 var ae = this.getActionEl();
15389 if(this.hideMode == 'visibility'){
15390 ae.dom.style.visibility = "visible";
15391 }else if(this.hideMode == 'offsets'){
15392 ae.removeClass('x-hidden');
15394 ae.dom.style.display = "";
15399 * Hide this component.
15400 * @return {Roo.Component} this
15403 if(this.fireEvent("beforehide", this) !== false){
15404 this.hidden = true;
15408 this.fireEvent("hide", this);
15414 onHide : function(){
15415 var ae = this.getActionEl();
15416 if(this.hideMode == 'visibility'){
15417 ae.dom.style.visibility = "hidden";
15418 }else if(this.hideMode == 'offsets'){
15419 ae.addClass('x-hidden');
15421 ae.dom.style.display = "none";
15426 * Convenience function to hide or show this component by boolean.
15427 * @param {Boolean} visible True to show, false to hide
15428 * @return {Roo.Component} this
15430 setVisible: function(visible){
15440 * Returns true if this component is visible.
15442 isVisible : function(){
15443 return this.getActionEl().isVisible();
15446 cloneConfig : function(overrides){
15447 overrides = overrides || {};
15448 var id = overrides.id || Roo.id();
15449 var cfg = Roo.applyIf(overrides, this.initialConfig);
15450 cfg.id = id; // prevent dup id
15451 return new this.constructor(cfg);
15455 * Ext JS Library 1.1.1
15456 * Copyright(c) 2006-2007, Ext JS, LLC.
15458 * Originally Released Under LGPL - original licence link has changed is not relivant.
15461 * <script type="text/javascript">
15465 * @class Roo.BoxComponent
15466 * @extends Roo.Component
15467 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15468 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15469 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15470 * layout containers.
15472 * @param {Roo.Element/String/Object} config The configuration options.
15474 Roo.BoxComponent = function(config){
15475 Roo.Component.call(this, config);
15479 * Fires after the component is resized.
15480 * @param {Roo.Component} this
15481 * @param {Number} adjWidth The box-adjusted width that was set
15482 * @param {Number} adjHeight The box-adjusted height that was set
15483 * @param {Number} rawWidth The width that was originally specified
15484 * @param {Number} rawHeight The height that was originally specified
15489 * Fires after the component is moved.
15490 * @param {Roo.Component} this
15491 * @param {Number} x The new x position
15492 * @param {Number} y The new y position
15498 Roo.extend(Roo.BoxComponent, Roo.Component, {
15499 // private, set in afterRender to signify that the component has been rendered
15501 // private, used to defer height settings to subclasses
15502 deferHeight: false,
15503 /** @cfg {Number} width
15504 * width (optional) size of component
15506 /** @cfg {Number} height
15507 * height (optional) size of component
15511 * Sets the width and height of the component. This method fires the resize event. This method can accept
15512 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15513 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15514 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15515 * @return {Roo.BoxComponent} this
15517 setSize : function(w, h){
15518 // support for standard size objects
15519 if(typeof w == 'object'){
15524 if(!this.boxReady){
15530 // prevent recalcs when not needed
15531 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15534 this.lastSize = {width: w, height: h};
15536 var adj = this.adjustSize(w, h);
15537 var aw = adj.width, ah = adj.height;
15538 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15539 var rz = this.getResizeEl();
15540 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15541 rz.setSize(aw, ah);
15542 }else if(!this.deferHeight && ah !== undefined){
15544 }else if(aw !== undefined){
15547 this.onResize(aw, ah, w, h);
15548 this.fireEvent('resize', this, aw, ah, w, h);
15554 * Gets the current size of the component's underlying element.
15555 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15557 getSize : function(){
15558 return this.el.getSize();
15562 * Gets the current XY position of the component's underlying element.
15563 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15564 * @return {Array} The XY position of the element (e.g., [100, 200])
15566 getPosition : function(local){
15567 if(local === true){
15568 return [this.el.getLeft(true), this.el.getTop(true)];
15570 return this.xy || this.el.getXY();
15574 * Gets the current box measurements of the component's underlying element.
15575 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15576 * @returns {Object} box An object in the format {x, y, width, height}
15578 getBox : function(local){
15579 var s = this.el.getSize();
15581 s.x = this.el.getLeft(true);
15582 s.y = this.el.getTop(true);
15584 var xy = this.xy || this.el.getXY();
15592 * Sets the current box measurements of the component's underlying element.
15593 * @param {Object} box An object in the format {x, y, width, height}
15594 * @returns {Roo.BoxComponent} this
15596 updateBox : function(box){
15597 this.setSize(box.width, box.height);
15598 this.setPagePosition(box.x, box.y);
15603 getResizeEl : function(){
15604 return this.resizeEl || this.el;
15608 getPositionEl : function(){
15609 return this.positionEl || this.el;
15613 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15614 * This method fires the move event.
15615 * @param {Number} left The new left
15616 * @param {Number} top The new top
15617 * @returns {Roo.BoxComponent} this
15619 setPosition : function(x, y){
15622 if(!this.boxReady){
15625 var adj = this.adjustPosition(x, y);
15626 var ax = adj.x, ay = adj.y;
15628 var el = this.getPositionEl();
15629 if(ax !== undefined || ay !== undefined){
15630 if(ax !== undefined && ay !== undefined){
15631 el.setLeftTop(ax, ay);
15632 }else if(ax !== undefined){
15634 }else if(ay !== undefined){
15637 this.onPosition(ax, ay);
15638 this.fireEvent('move', this, ax, ay);
15644 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15645 * This method fires the move event.
15646 * @param {Number} x The new x position
15647 * @param {Number} y The new y position
15648 * @returns {Roo.BoxComponent} this
15650 setPagePosition : function(x, y){
15653 if(!this.boxReady){
15656 if(x === undefined || y === undefined){ // cannot translate undefined points
15659 var p = this.el.translatePoints(x, y);
15660 this.setPosition(p.left, p.top);
15665 onRender : function(ct, position){
15666 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15668 this.resizeEl = Roo.get(this.resizeEl);
15670 if(this.positionEl){
15671 this.positionEl = Roo.get(this.positionEl);
15676 afterRender : function(){
15677 Roo.BoxComponent.superclass.afterRender.call(this);
15678 this.boxReady = true;
15679 this.setSize(this.width, this.height);
15680 if(this.x || this.y){
15681 this.setPosition(this.x, this.y);
15683 if(this.pageX || this.pageY){
15684 this.setPagePosition(this.pageX, this.pageY);
15689 * Force the component's size to recalculate based on the underlying element's current height and width.
15690 * @returns {Roo.BoxComponent} this
15692 syncSize : function(){
15693 delete this.lastSize;
15694 this.setSize(this.el.getWidth(), this.el.getHeight());
15699 * Called after the component is resized, this method is empty by default but can be implemented by any
15700 * subclass that needs to perform custom logic after a resize occurs.
15701 * @param {Number} adjWidth The box-adjusted width that was set
15702 * @param {Number} adjHeight The box-adjusted height that was set
15703 * @param {Number} rawWidth The width that was originally specified
15704 * @param {Number} rawHeight The height that was originally specified
15706 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15711 * Called after the component is moved, this method is empty by default but can be implemented by any
15712 * subclass that needs to perform custom logic after a move occurs.
15713 * @param {Number} x The new x position
15714 * @param {Number} y The new y position
15716 onPosition : function(x, y){
15721 adjustSize : function(w, h){
15722 if(this.autoWidth){
15725 if(this.autoHeight){
15728 return {width : w, height: h};
15732 adjustPosition : function(x, y){
15733 return {x : x, y: y};
15736 * Original code for Roojs - LGPL
15737 * <script type="text/javascript">
15741 * @class Roo.XComponent
15742 * A delayed Element creator...
15743 * Or a way to group chunks of interface together.
15745 * Mypart.xyx = new Roo.XComponent({
15747 parent : 'Mypart.xyz', // empty == document.element.!!
15751 disabled : function() {}
15753 tree : function() { // return an tree of xtype declared components
15757 xtype : 'NestedLayoutPanel',
15764 * It can be used to build a big heiracy, with parent etc.
15765 * or you can just use this to render a single compoent to a dom element
15766 * MYPART.render(Roo.Element | String(id) | dom_element )
15768 * @extends Roo.util.Observable
15770 * @param cfg {Object} configuration of component
15773 Roo.XComponent = function(cfg) {
15774 Roo.apply(this, cfg);
15778 * Fires when this the componnt is built
15779 * @param {Roo.XComponent} c the component
15784 this.region = this.region || 'center'; // default..
15785 Roo.XComponent.register(this);
15786 this.modules = false;
15787 this.el = false; // where the layout goes..
15791 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15794 * The created element (with Roo.factory())
15795 * @type {Roo.Layout}
15801 * for BC - use el in new code
15802 * @type {Roo.Layout}
15808 * for BC - use el in new code
15809 * @type {Roo.Layout}
15814 * @cfg {Function|boolean} disabled
15815 * If this module is disabled by some rule, return true from the funtion
15820 * @cfg {String} parent
15821 * Name of parent element which it get xtype added to..
15826 * @cfg {String} order
15827 * Used to set the order in which elements are created (usefull for multiple tabs)
15832 * @cfg {String} name
15833 * String to display while loading.
15837 * @cfg {String} region
15838 * Region to render component to (defaults to center)
15843 * @cfg {Array} items
15844 * A single item array - the first element is the root of the tree..
15845 * It's done this way to stay compatible with the Xtype system...
15851 * The method that retuns the tree of parts that make up this compoennt
15858 * render element to dom or tree
15859 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15862 render : function(el)
15866 var hp = this.parent ? 1 : 0;
15868 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15869 // if parent is a '#.....' string, then let's use that..
15870 var ename = this.parent.substr(1)
15871 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
15872 el = Roo.get(ename);
15873 if (!el && !this.parent) {
15874 Roo.log("Warning - element can not be found :#" + ename );
15878 var tree = this._tree ? this._tree() : this.tree();
15880 // altertive root elements ??? - we need a better way to indicate these.
15881 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15882 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15884 if (!this.parent && is_alt) {
15885 //el = Roo.get(document.body);
15886 this.parent = { el : true };
15891 if (!this.parent) {
15893 Roo.log("no parent - creating one");
15895 el = el ? Roo.get(el) : false;
15897 // it's a top level one..
15899 el : new Roo.BorderLayout(el || document.body, {
15905 tabPosition: 'top',
15906 //resizeTabs: true,
15907 alwaysShowTabs: el && hp? false : true,
15908 hideTabs: el || !hp ? true : false,
15915 if (!this.parent.el) {
15916 // probably an old style ctor, which has been disabled.
15920 // The 'tree' method is '_tree now'
15922 tree.region = tree.region || this.region;
15924 if (this.parent.el === true) {
15925 // bootstrap... - body..
15926 this.parent.el = Roo.factory(tree);
15929 this.el = this.parent.el.addxtype(tree);
15930 this.fireEvent('built', this);
15932 this.panel = this.el;
15933 this.layout = this.panel.layout;
15934 this.parentLayout = this.parent.layout || false;
15940 Roo.apply(Roo.XComponent, {
15942 * @property hideProgress
15943 * true to disable the building progress bar.. usefull on single page renders.
15946 hideProgress : false,
15948 * @property buildCompleted
15949 * True when the builder has completed building the interface.
15952 buildCompleted : false,
15955 * @property topModule
15956 * the upper most module - uses document.element as it's constructor.
15963 * @property modules
15964 * array of modules to be created by registration system.
15965 * @type {Array} of Roo.XComponent
15970 * @property elmodules
15971 * array of modules to be created by which use #ID
15972 * @type {Array} of Roo.XComponent
15978 * @property build_from_html
15979 * Build elements from html - used by bootstrap HTML stuff
15980 * - this is cleared after build is completed
15981 * @type {boolean} true (default false)
15984 build_from_html : false,
15987 * Register components to be built later.
15989 * This solves the following issues
15990 * - Building is not done on page load, but after an authentication process has occured.
15991 * - Interface elements are registered on page load
15992 * - Parent Interface elements may not be loaded before child, so this handles that..
15999 module : 'Pman.Tab.projectMgr',
16001 parent : 'Pman.layout',
16002 disabled : false, // or use a function..
16005 * * @param {Object} details about module
16007 register : function(obj) {
16009 Roo.XComponent.event.fireEvent('register', obj);
16010 switch(typeof(obj.disabled) ) {
16016 if ( obj.disabled() ) {
16022 if (obj.disabled) {
16028 this.modules.push(obj);
16032 * convert a string to an object..
16033 * eg. 'AAA.BBB' -> finds AAA.BBB
16037 toObject : function(str)
16039 if (!str || typeof(str) == 'object') {
16042 if (str.substring(0,1) == '#') {
16046 var ar = str.split('.');
16051 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16053 throw "Module not found : " + str;
16057 throw "Module not found : " + str;
16059 Roo.each(ar, function(e) {
16060 if (typeof(o[e]) == 'undefined') {
16061 throw "Module not found : " + str;
16072 * move modules into their correct place in the tree..
16075 preBuild : function ()
16078 Roo.each(this.modules , function (obj)
16080 Roo.XComponent.event.fireEvent('beforebuild', obj);
16082 var opar = obj.parent;
16084 obj.parent = this.toObject(opar);
16086 Roo.log("parent:toObject failed: " + e.toString());
16091 Roo.debug && Roo.log("GOT top level module");
16092 Roo.debug && Roo.log(obj);
16093 obj.modules = new Roo.util.MixedCollection(false,
16094 function(o) { return o.order + '' }
16096 this.topModule = obj;
16099 // parent is a string (usually a dom element name..)
16100 if (typeof(obj.parent) == 'string') {
16101 this.elmodules.push(obj);
16104 if (obj.parent.constructor != Roo.XComponent) {
16105 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16107 if (!obj.parent.modules) {
16108 obj.parent.modules = new Roo.util.MixedCollection(false,
16109 function(o) { return o.order + '' }
16112 if (obj.parent.disabled) {
16113 obj.disabled = true;
16115 obj.parent.modules.add(obj);
16120 * make a list of modules to build.
16121 * @return {Array} list of modules.
16124 buildOrder : function()
16127 var cmp = function(a,b) {
16128 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16130 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16131 throw "No top level modules to build";
16134 // make a flat list in order of modules to build.
16135 var mods = this.topModule ? [ this.topModule ] : [];
16138 // elmodules (is a list of DOM based modules )
16139 Roo.each(this.elmodules, function(e) {
16141 if (!this.topModule &&
16142 typeof(e.parent) == 'string' &&
16143 e.parent.substring(0,1) == '#' &&
16144 Roo.get(e.parent.substr(1))
16147 _this.topModule = e;
16153 // add modules to their parents..
16154 var addMod = function(m) {
16155 Roo.debug && Roo.log("build Order: add: " + m.name);
16158 if (m.modules && !m.disabled) {
16159 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16160 m.modules.keySort('ASC', cmp );
16161 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16163 m.modules.each(addMod);
16165 Roo.debug && Roo.log("build Order: no child modules");
16167 // not sure if this is used any more..
16169 m.finalize.name = m.name + " (clean up) ";
16170 mods.push(m.finalize);
16174 if (this.topModule && this.topModule.modules) {
16175 this.topModule.modules.keySort('ASC', cmp );
16176 this.topModule.modules.each(addMod);
16182 * Build the registered modules.
16183 * @param {Object} parent element.
16184 * @param {Function} optional method to call after module has been added.
16188 build : function(opts)
16191 if (typeof(opts) != 'undefined') {
16192 Roo.apply(this,opts);
16196 var mods = this.buildOrder();
16198 //this.allmods = mods;
16199 //Roo.debug && Roo.log(mods);
16201 if (!mods.length) { // should not happen
16202 throw "NO modules!!!";
16206 var msg = "Building Interface...";
16207 // flash it up as modal - so we store the mask!?
16208 if (!this.hideProgress && Roo.MessageBox) {
16209 Roo.MessageBox.show({ title: 'loading' });
16210 Roo.MessageBox.show({
16211 title: "Please wait...",
16220 var total = mods.length;
16223 var progressRun = function() {
16224 if (!mods.length) {
16225 Roo.debug && Roo.log('hide?');
16226 if (!this.hideProgress && Roo.MessageBox) {
16227 Roo.MessageBox.hide();
16229 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16231 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16237 var m = mods.shift();
16240 Roo.debug && Roo.log(m);
16241 // not sure if this is supported any more.. - modules that are are just function
16242 if (typeof(m) == 'function') {
16244 return progressRun.defer(10, _this);
16248 msg = "Building Interface " + (total - mods.length) +
16250 (m.name ? (' - ' + m.name) : '');
16251 Roo.debug && Roo.log(msg);
16252 if (!this.hideProgress && Roo.MessageBox) {
16253 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16257 // is the module disabled?
16258 var disabled = (typeof(m.disabled) == 'function') ?
16259 m.disabled.call(m.module.disabled) : m.disabled;
16263 return progressRun(); // we do not update the display!
16271 // it's 10 on top level, and 1 on others??? why...
16272 return progressRun.defer(10, _this);
16275 progressRun.defer(1, _this);
16289 * wrapper for event.on - aliased later..
16290 * Typically use to register a event handler for register:
16292 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16301 Roo.XComponent.event = new Roo.util.Observable({
16305 * Fires when an Component is registered,
16306 * set the disable property on the Component to stop registration.
16307 * @param {Roo.XComponent} c the component being registerd.
16312 * @event beforebuild
16313 * Fires before each Component is built
16314 * can be used to apply permissions.
16315 * @param {Roo.XComponent} c the component being registerd.
16318 'beforebuild' : true,
16320 * @event buildcomplete
16321 * Fires on the top level element when all elements have been built
16322 * @param {Roo.XComponent} the top level component.
16324 'buildcomplete' : true
16329 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16332 * Ext JS Library 1.1.1
16333 * Copyright(c) 2006-2007, Ext JS, LLC.
16335 * Originally Released Under LGPL - original licence link has changed is not relivant.
16338 * <script type="text/javascript">
16344 * These classes are derivatives of the similarly named classes in the YUI Library.
16345 * The original license:
16346 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16347 * Code licensed under the BSD License:
16348 * http://developer.yahoo.net/yui/license.txt
16353 var Event=Roo.EventManager;
16354 var Dom=Roo.lib.Dom;
16357 * @class Roo.dd.DragDrop
16358 * @extends Roo.util.Observable
16359 * Defines the interface and base operation of items that that can be
16360 * dragged or can be drop targets. It was designed to be extended, overriding
16361 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16362 * Up to three html elements can be associated with a DragDrop instance:
16364 * <li>linked element: the element that is passed into the constructor.
16365 * This is the element which defines the boundaries for interaction with
16366 * other DragDrop objects.</li>
16367 * <li>handle element(s): The drag operation only occurs if the element that
16368 * was clicked matches a handle element. By default this is the linked
16369 * element, but there are times that you will want only a portion of the
16370 * linked element to initiate the drag operation, and the setHandleElId()
16371 * method provides a way to define this.</li>
16372 * <li>drag element: this represents the element that would be moved along
16373 * with the cursor during a drag operation. By default, this is the linked
16374 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16375 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16378 * This class should not be instantiated until the onload event to ensure that
16379 * the associated elements are available.
16380 * The following would define a DragDrop obj that would interact with any
16381 * other DragDrop obj in the "group1" group:
16383 * dd = new Roo.dd.DragDrop("div1", "group1");
16385 * Since none of the event handlers have been implemented, nothing would
16386 * actually happen if you were to run the code above. Normally you would
16387 * override this class or one of the default implementations, but you can
16388 * also override the methods you want on an instance of the class...
16390 * dd.onDragDrop = function(e, id) {
16391 * alert("dd was dropped on " + id);
16395 * @param {String} id of the element that is linked to this instance
16396 * @param {String} sGroup the group of related DragDrop objects
16397 * @param {object} config an object containing configurable attributes
16398 * Valid properties for DragDrop:
16399 * padding, isTarget, maintainOffset, primaryButtonOnly
16401 Roo.dd.DragDrop = function(id, sGroup, config) {
16403 this.init(id, sGroup, config);
16408 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16411 * The id of the element associated with this object. This is what we
16412 * refer to as the "linked element" because the size and position of
16413 * this element is used to determine when the drag and drop objects have
16421 * Configuration attributes passed into the constructor
16428 * The id of the element that will be dragged. By default this is same
16429 * as the linked element , but could be changed to another element. Ex:
16431 * @property dragElId
16438 * the id of the element that initiates the drag operation. By default
16439 * this is the linked element, but could be changed to be a child of this
16440 * element. This lets us do things like only starting the drag when the
16441 * header element within the linked html element is clicked.
16442 * @property handleElId
16449 * An associative array of HTML tags that will be ignored if clicked.
16450 * @property invalidHandleTypes
16451 * @type {string: string}
16453 invalidHandleTypes: null,
16456 * An associative array of ids for elements that will be ignored if clicked
16457 * @property invalidHandleIds
16458 * @type {string: string}
16460 invalidHandleIds: null,
16463 * An indexted array of css class names for elements that will be ignored
16465 * @property invalidHandleClasses
16468 invalidHandleClasses: null,
16471 * The linked element's absolute X position at the time the drag was
16473 * @property startPageX
16480 * The linked element's absolute X position at the time the drag was
16482 * @property startPageY
16489 * The group defines a logical collection of DragDrop objects that are
16490 * related. Instances only get events when interacting with other
16491 * DragDrop object in the same group. This lets us define multiple
16492 * groups using a single DragDrop subclass if we want.
16494 * @type {string: string}
16499 * Individual drag/drop instances can be locked. This will prevent
16500 * onmousedown start drag.
16508 * Lock this instance
16511 lock: function() { this.locked = true; },
16514 * Unlock this instace
16517 unlock: function() { this.locked = false; },
16520 * By default, all insances can be a drop target. This can be disabled by
16521 * setting isTarget to false.
16528 * The padding configured for this drag and drop object for calculating
16529 * the drop zone intersection with this object.
16536 * Cached reference to the linked element
16537 * @property _domRef
16543 * Internal typeof flag
16544 * @property __ygDragDrop
16547 __ygDragDrop: true,
16550 * Set to true when horizontal contraints are applied
16551 * @property constrainX
16558 * Set to true when vertical contraints are applied
16559 * @property constrainY
16566 * The left constraint
16574 * The right constraint
16582 * The up constraint
16591 * The down constraint
16599 * Maintain offsets when we resetconstraints. Set to true when you want
16600 * the position of the element relative to its parent to stay the same
16601 * when the page changes
16603 * @property maintainOffset
16606 maintainOffset: false,
16609 * Array of pixel locations the element will snap to if we specified a
16610 * horizontal graduation/interval. This array is generated automatically
16611 * when you define a tick interval.
16618 * Array of pixel locations the element will snap to if we specified a
16619 * vertical graduation/interval. This array is generated automatically
16620 * when you define a tick interval.
16627 * By default the drag and drop instance will only respond to the primary
16628 * button click (left button for a right-handed mouse). Set to true to
16629 * allow drag and drop to start with any mouse click that is propogated
16631 * @property primaryButtonOnly
16634 primaryButtonOnly: true,
16637 * The availabe property is false until the linked dom element is accessible.
16638 * @property available
16644 * By default, drags can only be initiated if the mousedown occurs in the
16645 * region the linked element is. This is done in part to work around a
16646 * bug in some browsers that mis-report the mousedown if the previous
16647 * mouseup happened outside of the window. This property is set to true
16648 * if outer handles are defined.
16650 * @property hasOuterHandles
16654 hasOuterHandles: false,
16657 * Code that executes immediately before the startDrag event
16658 * @method b4StartDrag
16661 b4StartDrag: function(x, y) { },
16664 * Abstract method called after a drag/drop object is clicked
16665 * and the drag or mousedown time thresholds have beeen met.
16666 * @method startDrag
16667 * @param {int} X click location
16668 * @param {int} Y click location
16670 startDrag: function(x, y) { /* override this */ },
16673 * Code that executes immediately before the onDrag event
16677 b4Drag: function(e) { },
16680 * Abstract method called during the onMouseMove event while dragging an
16683 * @param {Event} e the mousemove event
16685 onDrag: function(e) { /* override this */ },
16688 * Abstract method called when this element fist begins hovering over
16689 * another DragDrop obj
16690 * @method onDragEnter
16691 * @param {Event} e the mousemove event
16692 * @param {String|DragDrop[]} id In POINT mode, the element
16693 * id this is hovering over. In INTERSECT mode, an array of one or more
16694 * dragdrop items being hovered over.
16696 onDragEnter: function(e, id) { /* override this */ },
16699 * Code that executes immediately before the onDragOver event
16700 * @method b4DragOver
16703 b4DragOver: function(e) { },
16706 * Abstract method called when this element is hovering over another
16708 * @method onDragOver
16709 * @param {Event} e the mousemove event
16710 * @param {String|DragDrop[]} id In POINT mode, the element
16711 * id this is hovering over. In INTERSECT mode, an array of dd items
16712 * being hovered over.
16714 onDragOver: function(e, id) { /* override this */ },
16717 * Code that executes immediately before the onDragOut event
16718 * @method b4DragOut
16721 b4DragOut: function(e) { },
16724 * Abstract method called when we are no longer hovering over an element
16725 * @method onDragOut
16726 * @param {Event} e the mousemove event
16727 * @param {String|DragDrop[]} id In POINT mode, the element
16728 * id this was hovering over. In INTERSECT mode, an array of dd items
16729 * that the mouse is no longer over.
16731 onDragOut: function(e, id) { /* override this */ },
16734 * Code that executes immediately before the onDragDrop event
16735 * @method b4DragDrop
16738 b4DragDrop: function(e) { },
16741 * Abstract method called when this item is dropped on another DragDrop
16743 * @method onDragDrop
16744 * @param {Event} e the mouseup event
16745 * @param {String|DragDrop[]} id In POINT mode, the element
16746 * id this was dropped on. In INTERSECT mode, an array of dd items this
16749 onDragDrop: function(e, id) { /* override this */ },
16752 * Abstract method called when this item is dropped on an area with no
16754 * @method onInvalidDrop
16755 * @param {Event} e the mouseup event
16757 onInvalidDrop: function(e) { /* override this */ },
16760 * Code that executes immediately before the endDrag event
16761 * @method b4EndDrag
16764 b4EndDrag: function(e) { },
16767 * Fired when we are done dragging the object
16769 * @param {Event} e the mouseup event
16771 endDrag: function(e) { /* override this */ },
16774 * Code executed immediately before the onMouseDown event
16775 * @method b4MouseDown
16776 * @param {Event} e the mousedown event
16779 b4MouseDown: function(e) { },
16782 * Event handler that fires when a drag/drop obj gets a mousedown
16783 * @method onMouseDown
16784 * @param {Event} e the mousedown event
16786 onMouseDown: function(e) { /* override this */ },
16789 * Event handler that fires when a drag/drop obj gets a mouseup
16790 * @method onMouseUp
16791 * @param {Event} e the mouseup event
16793 onMouseUp: function(e) { /* override this */ },
16796 * Override the onAvailable method to do what is needed after the initial
16797 * position was determined.
16798 * @method onAvailable
16800 onAvailable: function () {
16804 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16807 defaultPadding : {left:0, right:0, top:0, bottom:0},
16810 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16814 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16815 { dragElId: "existingProxyDiv" });
16816 dd.startDrag = function(){
16817 this.constrainTo("parent-id");
16820 * Or you can initalize it using the {@link Roo.Element} object:
16822 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16823 startDrag : function(){
16824 this.constrainTo("parent-id");
16828 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16829 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16830 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16831 * an object containing the sides to pad. For example: {right:10, bottom:10}
16832 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16834 constrainTo : function(constrainTo, pad, inContent){
16835 if(typeof pad == "number"){
16836 pad = {left: pad, right:pad, top:pad, bottom:pad};
16838 pad = pad || this.defaultPadding;
16839 var b = Roo.get(this.getEl()).getBox();
16840 var ce = Roo.get(constrainTo);
16841 var s = ce.getScroll();
16842 var c, cd = ce.dom;
16843 if(cd == document.body){
16844 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16847 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16851 var topSpace = b.y - c.y;
16852 var leftSpace = b.x - c.x;
16854 this.resetConstraints();
16855 this.setXConstraint(leftSpace - (pad.left||0), // left
16856 c.width - leftSpace - b.width - (pad.right||0) //right
16858 this.setYConstraint(topSpace - (pad.top||0), //top
16859 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16864 * Returns a reference to the linked element
16866 * @return {HTMLElement} the html element
16868 getEl: function() {
16869 if (!this._domRef) {
16870 this._domRef = Roo.getDom(this.id);
16873 return this._domRef;
16877 * Returns a reference to the actual element to drag. By default this is
16878 * the same as the html element, but it can be assigned to another
16879 * element. An example of this can be found in Roo.dd.DDProxy
16880 * @method getDragEl
16881 * @return {HTMLElement} the html element
16883 getDragEl: function() {
16884 return Roo.getDom(this.dragElId);
16888 * Sets up the DragDrop object. Must be called in the constructor of any
16889 * Roo.dd.DragDrop subclass
16891 * @param id the id of the linked element
16892 * @param {String} sGroup the group of related items
16893 * @param {object} config configuration attributes
16895 init: function(id, sGroup, config) {
16896 this.initTarget(id, sGroup, config);
16897 if (!Roo.isTouch) {
16898 Event.on(this.id, "mousedown", this.handleMouseDown, this);
16900 Event.on(this.id, "touchstart", this.handleMouseDown, this);
16901 // Event.on(this.id, "selectstart", Event.preventDefault);
16905 * Initializes Targeting functionality only... the object does not
16906 * get a mousedown handler.
16907 * @method initTarget
16908 * @param id the id of the linked element
16909 * @param {String} sGroup the group of related items
16910 * @param {object} config configuration attributes
16912 initTarget: function(id, sGroup, config) {
16914 // configuration attributes
16915 this.config = config || {};
16917 // create a local reference to the drag and drop manager
16918 this.DDM = Roo.dd.DDM;
16919 // initialize the groups array
16922 // assume that we have an element reference instead of an id if the
16923 // parameter is not a string
16924 if (typeof id !== "string") {
16931 // add to an interaction group
16932 this.addToGroup((sGroup) ? sGroup : "default");
16934 // We don't want to register this as the handle with the manager
16935 // so we just set the id rather than calling the setter.
16936 this.handleElId = id;
16938 // the linked element is the element that gets dragged by default
16939 this.setDragElId(id);
16941 // by default, clicked anchors will not start drag operations.
16942 this.invalidHandleTypes = { A: "A" };
16943 this.invalidHandleIds = {};
16944 this.invalidHandleClasses = [];
16946 this.applyConfig();
16948 this.handleOnAvailable();
16952 * Applies the configuration parameters that were passed into the constructor.
16953 * This is supposed to happen at each level through the inheritance chain. So
16954 * a DDProxy implentation will execute apply config on DDProxy, DD, and
16955 * DragDrop in order to get all of the parameters that are available in
16957 * @method applyConfig
16959 applyConfig: function() {
16961 // configurable properties:
16962 // padding, isTarget, maintainOffset, primaryButtonOnly
16963 this.padding = this.config.padding || [0, 0, 0, 0];
16964 this.isTarget = (this.config.isTarget !== false);
16965 this.maintainOffset = (this.config.maintainOffset);
16966 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
16971 * Executed when the linked element is available
16972 * @method handleOnAvailable
16975 handleOnAvailable: function() {
16976 this.available = true;
16977 this.resetConstraints();
16978 this.onAvailable();
16982 * Configures the padding for the target zone in px. Effectively expands
16983 * (or reduces) the virtual object size for targeting calculations.
16984 * Supports css-style shorthand; if only one parameter is passed, all sides
16985 * will have that padding, and if only two are passed, the top and bottom
16986 * will have the first param, the left and right the second.
16987 * @method setPadding
16988 * @param {int} iTop Top pad
16989 * @param {int} iRight Right pad
16990 * @param {int} iBot Bot pad
16991 * @param {int} iLeft Left pad
16993 setPadding: function(iTop, iRight, iBot, iLeft) {
16994 // this.padding = [iLeft, iRight, iTop, iBot];
16995 if (!iRight && 0 !== iRight) {
16996 this.padding = [iTop, iTop, iTop, iTop];
16997 } else if (!iBot && 0 !== iBot) {
16998 this.padding = [iTop, iRight, iTop, iRight];
17000 this.padding = [iTop, iRight, iBot, iLeft];
17005 * Stores the initial placement of the linked element.
17006 * @method setInitialPosition
17007 * @param {int} diffX the X offset, default 0
17008 * @param {int} diffY the Y offset, default 0
17010 setInitPosition: function(diffX, diffY) {
17011 var el = this.getEl();
17013 if (!this.DDM.verifyEl(el)) {
17017 var dx = diffX || 0;
17018 var dy = diffY || 0;
17020 var p = Dom.getXY( el );
17022 this.initPageX = p[0] - dx;
17023 this.initPageY = p[1] - dy;
17025 this.lastPageX = p[0];
17026 this.lastPageY = p[1];
17029 this.setStartPosition(p);
17033 * Sets the start position of the element. This is set when the obj
17034 * is initialized, the reset when a drag is started.
17035 * @method setStartPosition
17036 * @param pos current position (from previous lookup)
17039 setStartPosition: function(pos) {
17040 var p = pos || Dom.getXY( this.getEl() );
17041 this.deltaSetXY = null;
17043 this.startPageX = p[0];
17044 this.startPageY = p[1];
17048 * Add this instance to a group of related drag/drop objects. All
17049 * instances belong to at least one group, and can belong to as many
17050 * groups as needed.
17051 * @method addToGroup
17052 * @param sGroup {string} the name of the group
17054 addToGroup: function(sGroup) {
17055 this.groups[sGroup] = true;
17056 this.DDM.regDragDrop(this, sGroup);
17060 * Remove's this instance from the supplied interaction group
17061 * @method removeFromGroup
17062 * @param {string} sGroup The group to drop
17064 removeFromGroup: function(sGroup) {
17065 if (this.groups[sGroup]) {
17066 delete this.groups[sGroup];
17069 this.DDM.removeDDFromGroup(this, sGroup);
17073 * Allows you to specify that an element other than the linked element
17074 * will be moved with the cursor during a drag
17075 * @method setDragElId
17076 * @param id {string} the id of the element that will be used to initiate the drag
17078 setDragElId: function(id) {
17079 this.dragElId = id;
17083 * Allows you to specify a child of the linked element that should be
17084 * used to initiate the drag operation. An example of this would be if
17085 * you have a content div with text and links. Clicking anywhere in the
17086 * content area would normally start the drag operation. Use this method
17087 * to specify that an element inside of the content div is the element
17088 * that starts the drag operation.
17089 * @method setHandleElId
17090 * @param id {string} the id of the element that will be used to
17091 * initiate the drag.
17093 setHandleElId: function(id) {
17094 if (typeof id !== "string") {
17097 this.handleElId = id;
17098 this.DDM.regHandle(this.id, id);
17102 * Allows you to set an element outside of the linked element as a drag
17104 * @method setOuterHandleElId
17105 * @param id the id of the element that will be used to initiate the drag
17107 setOuterHandleElId: function(id) {
17108 if (typeof id !== "string") {
17111 Event.on(id, "mousedown",
17112 this.handleMouseDown, this);
17113 this.setHandleElId(id);
17115 this.hasOuterHandles = true;
17119 * Remove all drag and drop hooks for this element
17122 unreg: function() {
17123 Event.un(this.id, "mousedown",
17124 this.handleMouseDown);
17125 Event.un(this.id, "touchstart",
17126 this.handleMouseDown);
17127 this._domRef = null;
17128 this.DDM._remove(this);
17131 destroy : function(){
17136 * Returns true if this instance is locked, or the drag drop mgr is locked
17137 * (meaning that all drag/drop is disabled on the page.)
17139 * @return {boolean} true if this obj or all drag/drop is locked, else
17142 isLocked: function() {
17143 return (this.DDM.isLocked() || this.locked);
17147 * Fired when this object is clicked
17148 * @method handleMouseDown
17150 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17153 handleMouseDown: function(e, oDD){
17155 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17156 //Roo.log('not touch/ button !=0');
17159 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17160 return; // double touch..
17164 if (this.isLocked()) {
17165 //Roo.log('locked');
17169 this.DDM.refreshCache(this.groups);
17170 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17171 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17172 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17173 //Roo.log('no outer handes or not over target');
17176 // Roo.log('check validator');
17177 if (this.clickValidator(e)) {
17178 // Roo.log('validate success');
17179 // set the initial element position
17180 this.setStartPosition();
17183 this.b4MouseDown(e);
17184 this.onMouseDown(e);
17186 this.DDM.handleMouseDown(e, this);
17188 this.DDM.stopEvent(e);
17196 clickValidator: function(e) {
17197 var target = e.getTarget();
17198 return ( this.isValidHandleChild(target) &&
17199 (this.id == this.handleElId ||
17200 this.DDM.handleWasClicked(target, this.id)) );
17204 * Allows you to specify a tag name that should not start a drag operation
17205 * when clicked. This is designed to facilitate embedding links within a
17206 * drag handle that do something other than start the drag.
17207 * @method addInvalidHandleType
17208 * @param {string} tagName the type of element to exclude
17210 addInvalidHandleType: function(tagName) {
17211 var type = tagName.toUpperCase();
17212 this.invalidHandleTypes[type] = type;
17216 * Lets you to specify an element id for a child of a drag handle
17217 * that should not initiate a drag
17218 * @method addInvalidHandleId
17219 * @param {string} id the element id of the element you wish to ignore
17221 addInvalidHandleId: function(id) {
17222 if (typeof id !== "string") {
17225 this.invalidHandleIds[id] = id;
17229 * Lets you specify a css class of elements that will not initiate a drag
17230 * @method addInvalidHandleClass
17231 * @param {string} cssClass the class of the elements you wish to ignore
17233 addInvalidHandleClass: function(cssClass) {
17234 this.invalidHandleClasses.push(cssClass);
17238 * Unsets an excluded tag name set by addInvalidHandleType
17239 * @method removeInvalidHandleType
17240 * @param {string} tagName the type of element to unexclude
17242 removeInvalidHandleType: function(tagName) {
17243 var type = tagName.toUpperCase();
17244 // this.invalidHandleTypes[type] = null;
17245 delete this.invalidHandleTypes[type];
17249 * Unsets an invalid handle id
17250 * @method removeInvalidHandleId
17251 * @param {string} id the id of the element to re-enable
17253 removeInvalidHandleId: function(id) {
17254 if (typeof id !== "string") {
17257 delete this.invalidHandleIds[id];
17261 * Unsets an invalid css class
17262 * @method removeInvalidHandleClass
17263 * @param {string} cssClass the class of the element(s) you wish to
17266 removeInvalidHandleClass: function(cssClass) {
17267 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17268 if (this.invalidHandleClasses[i] == cssClass) {
17269 delete this.invalidHandleClasses[i];
17275 * Checks the tag exclusion list to see if this click should be ignored
17276 * @method isValidHandleChild
17277 * @param {HTMLElement} node the HTMLElement to evaluate
17278 * @return {boolean} true if this is a valid tag type, false if not
17280 isValidHandleChild: function(node) {
17283 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17286 nodeName = node.nodeName.toUpperCase();
17288 nodeName = node.nodeName;
17290 valid = valid && !this.invalidHandleTypes[nodeName];
17291 valid = valid && !this.invalidHandleIds[node.id];
17293 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17294 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17303 * Create the array of horizontal tick marks if an interval was specified
17304 * in setXConstraint().
17305 * @method setXTicks
17308 setXTicks: function(iStartX, iTickSize) {
17310 this.xTickSize = iTickSize;
17314 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17316 this.xTicks[this.xTicks.length] = i;
17321 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17323 this.xTicks[this.xTicks.length] = i;
17328 this.xTicks.sort(this.DDM.numericSort) ;
17332 * Create the array of vertical tick marks if an interval was specified in
17333 * setYConstraint().
17334 * @method setYTicks
17337 setYTicks: function(iStartY, iTickSize) {
17339 this.yTickSize = iTickSize;
17343 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17345 this.yTicks[this.yTicks.length] = i;
17350 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17352 this.yTicks[this.yTicks.length] = i;
17357 this.yTicks.sort(this.DDM.numericSort) ;
17361 * By default, the element can be dragged any place on the screen. Use
17362 * this method to limit the horizontal travel of the element. Pass in
17363 * 0,0 for the parameters if you want to lock the drag to the y axis.
17364 * @method setXConstraint
17365 * @param {int} iLeft the number of pixels the element can move to the left
17366 * @param {int} iRight the number of pixels the element can move to the
17368 * @param {int} iTickSize optional parameter for specifying that the
17370 * should move iTickSize pixels at a time.
17372 setXConstraint: function(iLeft, iRight, iTickSize) {
17373 this.leftConstraint = iLeft;
17374 this.rightConstraint = iRight;
17376 this.minX = this.initPageX - iLeft;
17377 this.maxX = this.initPageX + iRight;
17378 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17380 this.constrainX = true;
17384 * Clears any constraints applied to this instance. Also clears ticks
17385 * since they can't exist independent of a constraint at this time.
17386 * @method clearConstraints
17388 clearConstraints: function() {
17389 this.constrainX = false;
17390 this.constrainY = false;
17395 * Clears any tick interval defined for this instance
17396 * @method clearTicks
17398 clearTicks: function() {
17399 this.xTicks = null;
17400 this.yTicks = null;
17401 this.xTickSize = 0;
17402 this.yTickSize = 0;
17406 * By default, the element can be dragged any place on the screen. Set
17407 * this to limit the vertical travel of the element. Pass in 0,0 for the
17408 * parameters if you want to lock the drag to the x axis.
17409 * @method setYConstraint
17410 * @param {int} iUp the number of pixels the element can move up
17411 * @param {int} iDown the number of pixels the element can move down
17412 * @param {int} iTickSize optional parameter for specifying that the
17413 * element should move iTickSize pixels at a time.
17415 setYConstraint: function(iUp, iDown, iTickSize) {
17416 this.topConstraint = iUp;
17417 this.bottomConstraint = iDown;
17419 this.minY = this.initPageY - iUp;
17420 this.maxY = this.initPageY + iDown;
17421 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17423 this.constrainY = true;
17428 * resetConstraints must be called if you manually reposition a dd element.
17429 * @method resetConstraints
17430 * @param {boolean} maintainOffset
17432 resetConstraints: function() {
17435 // Maintain offsets if necessary
17436 if (this.initPageX || this.initPageX === 0) {
17437 // figure out how much this thing has moved
17438 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17439 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17441 this.setInitPosition(dx, dy);
17443 // This is the first time we have detected the element's position
17445 this.setInitPosition();
17448 if (this.constrainX) {
17449 this.setXConstraint( this.leftConstraint,
17450 this.rightConstraint,
17454 if (this.constrainY) {
17455 this.setYConstraint( this.topConstraint,
17456 this.bottomConstraint,
17462 * Normally the drag element is moved pixel by pixel, but we can specify
17463 * that it move a number of pixels at a time. This method resolves the
17464 * location when we have it set up like this.
17466 * @param {int} val where we want to place the object
17467 * @param {int[]} tickArray sorted array of valid points
17468 * @return {int} the closest tick
17471 getTick: function(val, tickArray) {
17474 // If tick interval is not defined, it is effectively 1 pixel,
17475 // so we return the value passed to us.
17477 } else if (tickArray[0] >= val) {
17478 // The value is lower than the first tick, so we return the first
17480 return tickArray[0];
17482 for (var i=0, len=tickArray.length; i<len; ++i) {
17484 if (tickArray[next] && tickArray[next] >= val) {
17485 var diff1 = val - tickArray[i];
17486 var diff2 = tickArray[next] - val;
17487 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17491 // The value is larger than the last tick, so we return the last
17493 return tickArray[tickArray.length - 1];
17500 * @return {string} string representation of the dd obj
17502 toString: function() {
17503 return ("DragDrop " + this.id);
17511 * Ext JS Library 1.1.1
17512 * Copyright(c) 2006-2007, Ext JS, LLC.
17514 * Originally Released Under LGPL - original licence link has changed is not relivant.
17517 * <script type="text/javascript">
17522 * The drag and drop utility provides a framework for building drag and drop
17523 * applications. In addition to enabling drag and drop for specific elements,
17524 * the drag and drop elements are tracked by the manager class, and the
17525 * interactions between the various elements are tracked during the drag and
17526 * the implementing code is notified about these important moments.
17529 // Only load the library once. Rewriting the manager class would orphan
17530 // existing drag and drop instances.
17531 if (!Roo.dd.DragDropMgr) {
17534 * @class Roo.dd.DragDropMgr
17535 * DragDropMgr is a singleton that tracks the element interaction for
17536 * all DragDrop items in the window. Generally, you will not call
17537 * this class directly, but it does have helper methods that could
17538 * be useful in your DragDrop implementations.
17541 Roo.dd.DragDropMgr = function() {
17543 var Event = Roo.EventManager;
17548 * Two dimensional Array of registered DragDrop objects. The first
17549 * dimension is the DragDrop item group, the second the DragDrop
17552 * @type {string: string}
17559 * Array of element ids defined as drag handles. Used to determine
17560 * if the element that generated the mousedown event is actually the
17561 * handle and not the html element itself.
17562 * @property handleIds
17563 * @type {string: string}
17570 * the DragDrop object that is currently being dragged
17571 * @property dragCurrent
17579 * the DragDrop object(s) that are being hovered over
17580 * @property dragOvers
17588 * the X distance between the cursor and the object being dragged
17597 * the Y distance between the cursor and the object being dragged
17606 * Flag to determine if we should prevent the default behavior of the
17607 * events we define. By default this is true, but this can be set to
17608 * false if you need the default behavior (not recommended)
17609 * @property preventDefault
17613 preventDefault: true,
17616 * Flag to determine if we should stop the propagation of the events
17617 * we generate. This is true by default but you may want to set it to
17618 * false if the html element contains other features that require the
17620 * @property stopPropagation
17624 stopPropagation: true,
17627 * Internal flag that is set to true when drag and drop has been
17629 * @property initialized
17636 * All drag and drop can be disabled.
17644 * Called the first time an element is registered.
17650 this.initialized = true;
17654 * In point mode, drag and drop interaction is defined by the
17655 * location of the cursor during the drag/drop
17663 * In intersect mode, drag and drop interactio nis defined by the
17664 * overlap of two or more drag and drop objects.
17665 * @property INTERSECT
17672 * The current drag and drop mode. Default: POINT
17680 * Runs method on all drag and drop objects
17681 * @method _execOnAll
17685 _execOnAll: function(sMethod, args) {
17686 for (var i in this.ids) {
17687 for (var j in this.ids[i]) {
17688 var oDD = this.ids[i][j];
17689 if (! this.isTypeOfDD(oDD)) {
17692 oDD[sMethod].apply(oDD, args);
17698 * Drag and drop initialization. Sets up the global event handlers
17703 _onLoad: function() {
17707 if (!Roo.isTouch) {
17708 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17709 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17711 Event.on(document, "touchend", this.handleMouseUp, this, true);
17712 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17714 Event.on(window, "unload", this._onUnload, this, true);
17715 Event.on(window, "resize", this._onResize, this, true);
17716 // Event.on(window, "mouseout", this._test);
17721 * Reset constraints on all drag and drop objs
17722 * @method _onResize
17726 _onResize: function(e) {
17727 this._execOnAll("resetConstraints", []);
17731 * Lock all drag and drop functionality
17735 lock: function() { this.locked = true; },
17738 * Unlock all drag and drop functionality
17742 unlock: function() { this.locked = false; },
17745 * Is drag and drop locked?
17747 * @return {boolean} True if drag and drop is locked, false otherwise.
17750 isLocked: function() { return this.locked; },
17753 * Location cache that is set for all drag drop objects when a drag is
17754 * initiated, cleared when the drag is finished.
17755 * @property locationCache
17762 * Set useCache to false if you want to force object the lookup of each
17763 * drag and drop linked element constantly during a drag.
17764 * @property useCache
17771 * The number of pixels that the mouse needs to move after the
17772 * mousedown before the drag is initiated. Default=3;
17773 * @property clickPixelThresh
17777 clickPixelThresh: 3,
17780 * The number of milliseconds after the mousedown event to initiate the
17781 * drag if we don't get a mouseup event. Default=1000
17782 * @property clickTimeThresh
17786 clickTimeThresh: 350,
17789 * Flag that indicates that either the drag pixel threshold or the
17790 * mousdown time threshold has been met
17791 * @property dragThreshMet
17796 dragThreshMet: false,
17799 * Timeout used for the click time threshold
17800 * @property clickTimeout
17805 clickTimeout: null,
17808 * The X position of the mousedown event stored for later use when a
17809 * drag threshold is met.
17818 * The Y position of the mousedown event stored for later use when a
17819 * drag threshold is met.
17828 * Each DragDrop instance must be registered with the DragDropMgr.
17829 * This is executed in DragDrop.init()
17830 * @method regDragDrop
17831 * @param {DragDrop} oDD the DragDrop object to register
17832 * @param {String} sGroup the name of the group this element belongs to
17835 regDragDrop: function(oDD, sGroup) {
17836 if (!this.initialized) { this.init(); }
17838 if (!this.ids[sGroup]) {
17839 this.ids[sGroup] = {};
17841 this.ids[sGroup][oDD.id] = oDD;
17845 * Removes the supplied dd instance from the supplied group. Executed
17846 * by DragDrop.removeFromGroup, so don't call this function directly.
17847 * @method removeDDFromGroup
17851 removeDDFromGroup: function(oDD, sGroup) {
17852 if (!this.ids[sGroup]) {
17853 this.ids[sGroup] = {};
17856 var obj = this.ids[sGroup];
17857 if (obj && obj[oDD.id]) {
17858 delete obj[oDD.id];
17863 * Unregisters a drag and drop item. This is executed in
17864 * DragDrop.unreg, use that method instead of calling this directly.
17869 _remove: function(oDD) {
17870 for (var g in oDD.groups) {
17871 if (g && this.ids[g][oDD.id]) {
17872 delete this.ids[g][oDD.id];
17875 delete this.handleIds[oDD.id];
17879 * Each DragDrop handle element must be registered. This is done
17880 * automatically when executing DragDrop.setHandleElId()
17881 * @method regHandle
17882 * @param {String} sDDId the DragDrop id this element is a handle for
17883 * @param {String} sHandleId the id of the element that is the drag
17887 regHandle: function(sDDId, sHandleId) {
17888 if (!this.handleIds[sDDId]) {
17889 this.handleIds[sDDId] = {};
17891 this.handleIds[sDDId][sHandleId] = sHandleId;
17895 * Utility function to determine if a given element has been
17896 * registered as a drag drop item.
17897 * @method isDragDrop
17898 * @param {String} id the element id to check
17899 * @return {boolean} true if this element is a DragDrop item,
17903 isDragDrop: function(id) {
17904 return ( this.getDDById(id) ) ? true : false;
17908 * Returns the drag and drop instances that are in all groups the
17909 * passed in instance belongs to.
17910 * @method getRelated
17911 * @param {DragDrop} p_oDD the obj to get related data for
17912 * @param {boolean} bTargetsOnly if true, only return targetable objs
17913 * @return {DragDrop[]} the related instances
17916 getRelated: function(p_oDD, bTargetsOnly) {
17918 for (var i in p_oDD.groups) {
17919 for (j in this.ids[i]) {
17920 var dd = this.ids[i][j];
17921 if (! this.isTypeOfDD(dd)) {
17924 if (!bTargetsOnly || dd.isTarget) {
17925 oDDs[oDDs.length] = dd;
17934 * Returns true if the specified dd target is a legal target for
17935 * the specifice drag obj
17936 * @method isLegalTarget
17937 * @param {DragDrop} the drag obj
17938 * @param {DragDrop} the target
17939 * @return {boolean} true if the target is a legal target for the
17943 isLegalTarget: function (oDD, oTargetDD) {
17944 var targets = this.getRelated(oDD, true);
17945 for (var i=0, len=targets.length;i<len;++i) {
17946 if (targets[i].id == oTargetDD.id) {
17955 * My goal is to be able to transparently determine if an object is
17956 * typeof DragDrop, and the exact subclass of DragDrop. typeof
17957 * returns "object", oDD.constructor.toString() always returns
17958 * "DragDrop" and not the name of the subclass. So for now it just
17959 * evaluates a well-known variable in DragDrop.
17960 * @method isTypeOfDD
17961 * @param {Object} the object to evaluate
17962 * @return {boolean} true if typeof oDD = DragDrop
17965 isTypeOfDD: function (oDD) {
17966 return (oDD && oDD.__ygDragDrop);
17970 * Utility function to determine if a given element has been
17971 * registered as a drag drop handle for the given Drag Drop object.
17973 * @param {String} id the element id to check
17974 * @return {boolean} true if this element is a DragDrop handle, false
17978 isHandle: function(sDDId, sHandleId) {
17979 return ( this.handleIds[sDDId] &&
17980 this.handleIds[sDDId][sHandleId] );
17984 * Returns the DragDrop instance for a given id
17985 * @method getDDById
17986 * @param {String} id the id of the DragDrop object
17987 * @return {DragDrop} the drag drop object, null if it is not found
17990 getDDById: function(id) {
17991 for (var i in this.ids) {
17992 if (this.ids[i][id]) {
17993 return this.ids[i][id];
18000 * Fired after a registered DragDrop object gets the mousedown event.
18001 * Sets up the events required to track the object being dragged
18002 * @method handleMouseDown
18003 * @param {Event} e the event
18004 * @param oDD the DragDrop object being dragged
18008 handleMouseDown: function(e, oDD) {
18010 Roo.QuickTips.disable();
18012 this.currentTarget = e.getTarget();
18014 this.dragCurrent = oDD;
18016 var el = oDD.getEl();
18018 // track start position
18019 this.startX = e.getPageX();
18020 this.startY = e.getPageY();
18022 this.deltaX = this.startX - el.offsetLeft;
18023 this.deltaY = this.startY - el.offsetTop;
18025 this.dragThreshMet = false;
18027 this.clickTimeout = setTimeout(
18029 var DDM = Roo.dd.DDM;
18030 DDM.startDrag(DDM.startX, DDM.startY);
18032 this.clickTimeThresh );
18036 * Fired when either the drag pixel threshol or the mousedown hold
18037 * time threshold has been met.
18038 * @method startDrag
18039 * @param x {int} the X position of the original mousedown
18040 * @param y {int} the Y position of the original mousedown
18043 startDrag: function(x, y) {
18044 clearTimeout(this.clickTimeout);
18045 if (this.dragCurrent) {
18046 this.dragCurrent.b4StartDrag(x, y);
18047 this.dragCurrent.startDrag(x, y);
18049 this.dragThreshMet = true;
18053 * Internal function to handle the mouseup event. Will be invoked
18054 * from the context of the document.
18055 * @method handleMouseUp
18056 * @param {Event} e the event
18060 handleMouseUp: function(e) {
18063 Roo.QuickTips.enable();
18065 if (! this.dragCurrent) {
18069 clearTimeout(this.clickTimeout);
18071 if (this.dragThreshMet) {
18072 this.fireEvents(e, true);
18082 * Utility to stop event propagation and event default, if these
18083 * features are turned on.
18084 * @method stopEvent
18085 * @param {Event} e the event as returned by this.getEvent()
18088 stopEvent: function(e){
18089 if(this.stopPropagation) {
18090 e.stopPropagation();
18093 if (this.preventDefault) {
18094 e.preventDefault();
18099 * Internal function to clean up event handlers after the drag
18100 * operation is complete
18102 * @param {Event} e the event
18106 stopDrag: function(e) {
18107 // Fire the drag end event for the item that was dragged
18108 if (this.dragCurrent) {
18109 if (this.dragThreshMet) {
18110 this.dragCurrent.b4EndDrag(e);
18111 this.dragCurrent.endDrag(e);
18114 this.dragCurrent.onMouseUp(e);
18117 this.dragCurrent = null;
18118 this.dragOvers = {};
18122 * Internal function to handle the mousemove event. Will be invoked
18123 * from the context of the html element.
18125 * @TODO figure out what we can do about mouse events lost when the
18126 * user drags objects beyond the window boundary. Currently we can
18127 * detect this in internet explorer by verifying that the mouse is
18128 * down during the mousemove event. Firefox doesn't give us the
18129 * button state on the mousemove event.
18130 * @method handleMouseMove
18131 * @param {Event} e the event
18135 handleMouseMove: function(e) {
18136 if (! this.dragCurrent) {
18140 // var button = e.which || e.button;
18142 // check for IE mouseup outside of page boundary
18143 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18145 return this.handleMouseUp(e);
18148 if (!this.dragThreshMet) {
18149 var diffX = Math.abs(this.startX - e.getPageX());
18150 var diffY = Math.abs(this.startY - e.getPageY());
18151 if (diffX > this.clickPixelThresh ||
18152 diffY > this.clickPixelThresh) {
18153 this.startDrag(this.startX, this.startY);
18157 if (this.dragThreshMet) {
18158 this.dragCurrent.b4Drag(e);
18159 this.dragCurrent.onDrag(e);
18160 if(!this.dragCurrent.moveOnly){
18161 this.fireEvents(e, false);
18171 * Iterates over all of the DragDrop elements to find ones we are
18172 * hovering over or dropping on
18173 * @method fireEvents
18174 * @param {Event} e the event
18175 * @param {boolean} isDrop is this a drop op or a mouseover op?
18179 fireEvents: function(e, isDrop) {
18180 var dc = this.dragCurrent;
18182 // If the user did the mouse up outside of the window, we could
18183 // get here even though we have ended the drag.
18184 if (!dc || dc.isLocked()) {
18188 var pt = e.getPoint();
18190 // cache the previous dragOver array
18196 var enterEvts = [];
18198 // Check to see if the object(s) we were hovering over is no longer
18199 // being hovered over so we can fire the onDragOut event
18200 for (var i in this.dragOvers) {
18202 var ddo = this.dragOvers[i];
18204 if (! this.isTypeOfDD(ddo)) {
18208 if (! this.isOverTarget(pt, ddo, this.mode)) {
18209 outEvts.push( ddo );
18212 oldOvers[i] = true;
18213 delete this.dragOvers[i];
18216 for (var sGroup in dc.groups) {
18218 if ("string" != typeof sGroup) {
18222 for (i in this.ids[sGroup]) {
18223 var oDD = this.ids[sGroup][i];
18224 if (! this.isTypeOfDD(oDD)) {
18228 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18229 if (this.isOverTarget(pt, oDD, this.mode)) {
18230 // look for drop interactions
18232 dropEvts.push( oDD );
18233 // look for drag enter and drag over interactions
18236 // initial drag over: dragEnter fires
18237 if (!oldOvers[oDD.id]) {
18238 enterEvts.push( oDD );
18239 // subsequent drag overs: dragOver fires
18241 overEvts.push( oDD );
18244 this.dragOvers[oDD.id] = oDD;
18252 if (outEvts.length) {
18253 dc.b4DragOut(e, outEvts);
18254 dc.onDragOut(e, outEvts);
18257 if (enterEvts.length) {
18258 dc.onDragEnter(e, enterEvts);
18261 if (overEvts.length) {
18262 dc.b4DragOver(e, overEvts);
18263 dc.onDragOver(e, overEvts);
18266 if (dropEvts.length) {
18267 dc.b4DragDrop(e, dropEvts);
18268 dc.onDragDrop(e, dropEvts);
18272 // fire dragout events
18274 for (i=0, len=outEvts.length; i<len; ++i) {
18275 dc.b4DragOut(e, outEvts[i].id);
18276 dc.onDragOut(e, outEvts[i].id);
18279 // fire enter events
18280 for (i=0,len=enterEvts.length; i<len; ++i) {
18281 // dc.b4DragEnter(e, oDD.id);
18282 dc.onDragEnter(e, enterEvts[i].id);
18285 // fire over events
18286 for (i=0,len=overEvts.length; i<len; ++i) {
18287 dc.b4DragOver(e, overEvts[i].id);
18288 dc.onDragOver(e, overEvts[i].id);
18291 // fire drop events
18292 for (i=0, len=dropEvts.length; i<len; ++i) {
18293 dc.b4DragDrop(e, dropEvts[i].id);
18294 dc.onDragDrop(e, dropEvts[i].id);
18299 // notify about a drop that did not find a target
18300 if (isDrop && !dropEvts.length) {
18301 dc.onInvalidDrop(e);
18307 * Helper function for getting the best match from the list of drag
18308 * and drop objects returned by the drag and drop events when we are
18309 * in INTERSECT mode. It returns either the first object that the
18310 * cursor is over, or the object that has the greatest overlap with
18311 * the dragged element.
18312 * @method getBestMatch
18313 * @param {DragDrop[]} dds The array of drag and drop objects
18315 * @return {DragDrop} The best single match
18318 getBestMatch: function(dds) {
18320 // Return null if the input is not what we expect
18321 //if (!dds || !dds.length || dds.length == 0) {
18323 // If there is only one item, it wins
18324 //} else if (dds.length == 1) {
18326 var len = dds.length;
18331 // Loop through the targeted items
18332 for (var i=0; i<len; ++i) {
18334 // If the cursor is over the object, it wins. If the
18335 // cursor is over multiple matches, the first one we come
18337 if (dd.cursorIsOver) {
18340 // Otherwise the object with the most overlap wins
18343 winner.overlap.getArea() < dd.overlap.getArea()) {
18354 * Refreshes the cache of the top-left and bottom-right points of the
18355 * drag and drop objects in the specified group(s). This is in the
18356 * format that is stored in the drag and drop instance, so typical
18359 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18363 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18365 * @TODO this really should be an indexed array. Alternatively this
18366 * method could accept both.
18367 * @method refreshCache
18368 * @param {Object} groups an associative array of groups to refresh
18371 refreshCache: function(groups) {
18372 for (var sGroup in groups) {
18373 if ("string" != typeof sGroup) {
18376 for (var i in this.ids[sGroup]) {
18377 var oDD = this.ids[sGroup][i];
18379 if (this.isTypeOfDD(oDD)) {
18380 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18381 var loc = this.getLocation(oDD);
18383 this.locationCache[oDD.id] = loc;
18385 delete this.locationCache[oDD.id];
18386 // this will unregister the drag and drop object if
18387 // the element is not in a usable state
18396 * This checks to make sure an element exists and is in the DOM. The
18397 * main purpose is to handle cases where innerHTML is used to remove
18398 * drag and drop objects from the DOM. IE provides an 'unspecified
18399 * error' when trying to access the offsetParent of such an element
18401 * @param {HTMLElement} el the element to check
18402 * @return {boolean} true if the element looks usable
18405 verifyEl: function(el) {
18410 parent = el.offsetParent;
18413 parent = el.offsetParent;
18424 * Returns a Region object containing the drag and drop element's position
18425 * and size, including the padding configured for it
18426 * @method getLocation
18427 * @param {DragDrop} oDD the drag and drop object to get the
18429 * @return {Roo.lib.Region} a Region object representing the total area
18430 * the element occupies, including any padding
18431 * the instance is configured for.
18434 getLocation: function(oDD) {
18435 if (! this.isTypeOfDD(oDD)) {
18439 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18442 pos= Roo.lib.Dom.getXY(el);
18450 x2 = x1 + el.offsetWidth;
18452 y2 = y1 + el.offsetHeight;
18454 t = y1 - oDD.padding[0];
18455 r = x2 + oDD.padding[1];
18456 b = y2 + oDD.padding[2];
18457 l = x1 - oDD.padding[3];
18459 return new Roo.lib.Region( t, r, b, l );
18463 * Checks the cursor location to see if it over the target
18464 * @method isOverTarget
18465 * @param {Roo.lib.Point} pt The point to evaluate
18466 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18467 * @return {boolean} true if the mouse is over the target
18471 isOverTarget: function(pt, oTarget, intersect) {
18472 // use cache if available
18473 var loc = this.locationCache[oTarget.id];
18474 if (!loc || !this.useCache) {
18475 loc = this.getLocation(oTarget);
18476 this.locationCache[oTarget.id] = loc;
18484 oTarget.cursorIsOver = loc.contains( pt );
18486 // DragDrop is using this as a sanity check for the initial mousedown
18487 // in this case we are done. In POINT mode, if the drag obj has no
18488 // contraints, we are also done. Otherwise we need to evaluate the
18489 // location of the target as related to the actual location of the
18490 // dragged element.
18491 var dc = this.dragCurrent;
18492 if (!dc || !dc.getTargetCoord ||
18493 (!intersect && !dc.constrainX && !dc.constrainY)) {
18494 return oTarget.cursorIsOver;
18497 oTarget.overlap = null;
18499 // Get the current location of the drag element, this is the
18500 // location of the mouse event less the delta that represents
18501 // where the original mousedown happened on the element. We
18502 // need to consider constraints and ticks as well.
18503 var pos = dc.getTargetCoord(pt.x, pt.y);
18505 var el = dc.getDragEl();
18506 var curRegion = new Roo.lib.Region( pos.y,
18507 pos.x + el.offsetWidth,
18508 pos.y + el.offsetHeight,
18511 var overlap = curRegion.intersect(loc);
18514 oTarget.overlap = overlap;
18515 return (intersect) ? true : oTarget.cursorIsOver;
18522 * unload event handler
18523 * @method _onUnload
18527 _onUnload: function(e, me) {
18528 Roo.dd.DragDropMgr.unregAll();
18532 * Cleans up the drag and drop events and objects.
18537 unregAll: function() {
18539 if (this.dragCurrent) {
18541 this.dragCurrent = null;
18544 this._execOnAll("unreg", []);
18546 for (i in this.elementCache) {
18547 delete this.elementCache[i];
18550 this.elementCache = {};
18555 * A cache of DOM elements
18556 * @property elementCache
18563 * Get the wrapper for the DOM element specified
18564 * @method getElWrapper
18565 * @param {String} id the id of the element to get
18566 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18568 * @deprecated This wrapper isn't that useful
18571 getElWrapper: function(id) {
18572 var oWrapper = this.elementCache[id];
18573 if (!oWrapper || !oWrapper.el) {
18574 oWrapper = this.elementCache[id] =
18575 new this.ElementWrapper(Roo.getDom(id));
18581 * Returns the actual DOM element
18582 * @method getElement
18583 * @param {String} id the id of the elment to get
18584 * @return {Object} The element
18585 * @deprecated use Roo.getDom instead
18588 getElement: function(id) {
18589 return Roo.getDom(id);
18593 * Returns the style property for the DOM element (i.e.,
18594 * document.getElById(id).style)
18596 * @param {String} id the id of the elment to get
18597 * @return {Object} The style property of the element
18598 * @deprecated use Roo.getDom instead
18601 getCss: function(id) {
18602 var el = Roo.getDom(id);
18603 return (el) ? el.style : null;
18607 * Inner class for cached elements
18608 * @class DragDropMgr.ElementWrapper
18613 ElementWrapper: function(el) {
18618 this.el = el || null;
18623 this.id = this.el && el.id;
18625 * A reference to the style property
18628 this.css = this.el && el.style;
18632 * Returns the X position of an html element
18634 * @param el the element for which to get the position
18635 * @return {int} the X coordinate
18637 * @deprecated use Roo.lib.Dom.getX instead
18640 getPosX: function(el) {
18641 return Roo.lib.Dom.getX(el);
18645 * Returns the Y position of an html element
18647 * @param el the element for which to get the position
18648 * @return {int} the Y coordinate
18649 * @deprecated use Roo.lib.Dom.getY instead
18652 getPosY: function(el) {
18653 return Roo.lib.Dom.getY(el);
18657 * Swap two nodes. In IE, we use the native method, for others we
18658 * emulate the IE behavior
18660 * @param n1 the first node to swap
18661 * @param n2 the other node to swap
18664 swapNode: function(n1, n2) {
18668 var p = n2.parentNode;
18669 var s = n2.nextSibling;
18672 p.insertBefore(n1, n2);
18673 } else if (n2 == n1.nextSibling) {
18674 p.insertBefore(n2, n1);
18676 n1.parentNode.replaceChild(n2, n1);
18677 p.insertBefore(n1, s);
18683 * Returns the current scroll position
18684 * @method getScroll
18688 getScroll: function () {
18689 var t, l, dde=document.documentElement, db=document.body;
18690 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18692 l = dde.scrollLeft;
18699 return { top: t, left: l };
18703 * Returns the specified element style property
18705 * @param {HTMLElement} el the element
18706 * @param {string} styleProp the style property
18707 * @return {string} The value of the style property
18708 * @deprecated use Roo.lib.Dom.getStyle
18711 getStyle: function(el, styleProp) {
18712 return Roo.fly(el).getStyle(styleProp);
18716 * Gets the scrollTop
18717 * @method getScrollTop
18718 * @return {int} the document's scrollTop
18721 getScrollTop: function () { return this.getScroll().top; },
18724 * Gets the scrollLeft
18725 * @method getScrollLeft
18726 * @return {int} the document's scrollTop
18729 getScrollLeft: function () { return this.getScroll().left; },
18732 * Sets the x/y position of an element to the location of the
18735 * @param {HTMLElement} moveEl The element to move
18736 * @param {HTMLElement} targetEl The position reference element
18739 moveToEl: function (moveEl, targetEl) {
18740 var aCoord = Roo.lib.Dom.getXY(targetEl);
18741 Roo.lib.Dom.setXY(moveEl, aCoord);
18745 * Numeric array sort function
18746 * @method numericSort
18749 numericSort: function(a, b) { return (a - b); },
18753 * @property _timeoutCount
18760 * Trying to make the load order less important. Without this we get
18761 * an error if this file is loaded before the Event Utility.
18762 * @method _addListeners
18766 _addListeners: function() {
18767 var DDM = Roo.dd.DDM;
18768 if ( Roo.lib.Event && document ) {
18771 if (DDM._timeoutCount > 2000) {
18773 setTimeout(DDM._addListeners, 10);
18774 if (document && document.body) {
18775 DDM._timeoutCount += 1;
18782 * Recursively searches the immediate parent and all child nodes for
18783 * the handle element in order to determine wheter or not it was
18785 * @method handleWasClicked
18786 * @param node the html element to inspect
18789 handleWasClicked: function(node, id) {
18790 if (this.isHandle(id, node.id)) {
18793 // check to see if this is a text node child of the one we want
18794 var p = node.parentNode;
18797 if (this.isHandle(id, p.id)) {
18812 // shorter alias, save a few bytes
18813 Roo.dd.DDM = Roo.dd.DragDropMgr;
18814 Roo.dd.DDM._addListeners();
18818 * Ext JS Library 1.1.1
18819 * Copyright(c) 2006-2007, Ext JS, LLC.
18821 * Originally Released Under LGPL - original licence link has changed is not relivant.
18824 * <script type="text/javascript">
18829 * A DragDrop implementation where the linked element follows the
18830 * mouse cursor during a drag.
18831 * @extends Roo.dd.DragDrop
18833 * @param {String} id the id of the linked element
18834 * @param {String} sGroup the group of related DragDrop items
18835 * @param {object} config an object containing configurable attributes
18836 * Valid properties for DD:
18839 Roo.dd.DD = function(id, sGroup, config) {
18841 this.init(id, sGroup, config);
18845 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18848 * When set to true, the utility automatically tries to scroll the browser
18849 * window wehn a drag and drop element is dragged near the viewport boundary.
18850 * Defaults to true.
18857 * Sets the pointer offset to the distance between the linked element's top
18858 * left corner and the location the element was clicked
18859 * @method autoOffset
18860 * @param {int} iPageX the X coordinate of the click
18861 * @param {int} iPageY the Y coordinate of the click
18863 autoOffset: function(iPageX, iPageY) {
18864 var x = iPageX - this.startPageX;
18865 var y = iPageY - this.startPageY;
18866 this.setDelta(x, y);
18870 * Sets the pointer offset. You can call this directly to force the
18871 * offset to be in a particular location (e.g., pass in 0,0 to set it
18872 * to the center of the object)
18874 * @param {int} iDeltaX the distance from the left
18875 * @param {int} iDeltaY the distance from the top
18877 setDelta: function(iDeltaX, iDeltaY) {
18878 this.deltaX = iDeltaX;
18879 this.deltaY = iDeltaY;
18883 * Sets the drag element to the location of the mousedown or click event,
18884 * maintaining the cursor location relative to the location on the element
18885 * that was clicked. Override this if you want to place the element in a
18886 * location other than where the cursor is.
18887 * @method setDragElPos
18888 * @param {int} iPageX the X coordinate of the mousedown or drag event
18889 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18891 setDragElPos: function(iPageX, iPageY) {
18892 // the first time we do this, we are going to check to make sure
18893 // the element has css positioning
18895 var el = this.getDragEl();
18896 this.alignElWithMouse(el, iPageX, iPageY);
18900 * Sets the element to the location of the mousedown or click event,
18901 * maintaining the cursor location relative to the location on the element
18902 * that was clicked. Override this if you want to place the element in a
18903 * location other than where the cursor is.
18904 * @method alignElWithMouse
18905 * @param {HTMLElement} el the element to move
18906 * @param {int} iPageX the X coordinate of the mousedown or drag event
18907 * @param {int} iPageY the Y coordinate of the mousedown or drag event
18909 alignElWithMouse: function(el, iPageX, iPageY) {
18910 var oCoord = this.getTargetCoord(iPageX, iPageY);
18911 var fly = el.dom ? el : Roo.fly(el);
18912 if (!this.deltaSetXY) {
18913 var aCoord = [oCoord.x, oCoord.y];
18915 var newLeft = fly.getLeft(true);
18916 var newTop = fly.getTop(true);
18917 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
18919 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
18922 this.cachePosition(oCoord.x, oCoord.y);
18923 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
18928 * Saves the most recent position so that we can reset the constraints and
18929 * tick marks on-demand. We need to know this so that we can calculate the
18930 * number of pixels the element is offset from its original position.
18931 * @method cachePosition
18932 * @param iPageX the current x position (optional, this just makes it so we
18933 * don't have to look it up again)
18934 * @param iPageY the current y position (optional, this just makes it so we
18935 * don't have to look it up again)
18937 cachePosition: function(iPageX, iPageY) {
18939 this.lastPageX = iPageX;
18940 this.lastPageY = iPageY;
18942 var aCoord = Roo.lib.Dom.getXY(this.getEl());
18943 this.lastPageX = aCoord[0];
18944 this.lastPageY = aCoord[1];
18949 * Auto-scroll the window if the dragged object has been moved beyond the
18950 * visible window boundary.
18951 * @method autoScroll
18952 * @param {int} x the drag element's x position
18953 * @param {int} y the drag element's y position
18954 * @param {int} h the height of the drag element
18955 * @param {int} w the width of the drag element
18958 autoScroll: function(x, y, h, w) {
18961 // The client height
18962 var clientH = Roo.lib.Dom.getViewWidth();
18964 // The client width
18965 var clientW = Roo.lib.Dom.getViewHeight();
18967 // The amt scrolled down
18968 var st = this.DDM.getScrollTop();
18970 // The amt scrolled right
18971 var sl = this.DDM.getScrollLeft();
18973 // Location of the bottom of the element
18976 // Location of the right of the element
18979 // The distance from the cursor to the bottom of the visible area,
18980 // adjusted so that we don't scroll if the cursor is beyond the
18981 // element drag constraints
18982 var toBot = (clientH + st - y - this.deltaY);
18984 // The distance from the cursor to the right of the visible area
18985 var toRight = (clientW + sl - x - this.deltaX);
18988 // How close to the edge the cursor must be before we scroll
18989 // var thresh = (document.all) ? 100 : 40;
18992 // How many pixels to scroll per autoscroll op. This helps to reduce
18993 // clunky scrolling. IE is more sensitive about this ... it needs this
18994 // value to be higher.
18995 var scrAmt = (document.all) ? 80 : 30;
18997 // Scroll down if we are near the bottom of the visible page and the
18998 // obj extends below the crease
18999 if ( bot > clientH && toBot < thresh ) {
19000 window.scrollTo(sl, st + scrAmt);
19003 // Scroll up if the window is scrolled down and the top of the object
19004 // goes above the top border
19005 if ( y < st && st > 0 && y - st < thresh ) {
19006 window.scrollTo(sl, st - scrAmt);
19009 // Scroll right if the obj is beyond the right border and the cursor is
19010 // near the border.
19011 if ( right > clientW && toRight < thresh ) {
19012 window.scrollTo(sl + scrAmt, st);
19015 // Scroll left if the window has been scrolled to the right and the obj
19016 // extends past the left border
19017 if ( x < sl && sl > 0 && x - sl < thresh ) {
19018 window.scrollTo(sl - scrAmt, st);
19024 * Finds the location the element should be placed if we want to move
19025 * it to where the mouse location less the click offset would place us.
19026 * @method getTargetCoord
19027 * @param {int} iPageX the X coordinate of the click
19028 * @param {int} iPageY the Y coordinate of the click
19029 * @return an object that contains the coordinates (Object.x and Object.y)
19032 getTargetCoord: function(iPageX, iPageY) {
19035 var x = iPageX - this.deltaX;
19036 var y = iPageY - this.deltaY;
19038 if (this.constrainX) {
19039 if (x < this.minX) { x = this.minX; }
19040 if (x > this.maxX) { x = this.maxX; }
19043 if (this.constrainY) {
19044 if (y < this.minY) { y = this.minY; }
19045 if (y > this.maxY) { y = this.maxY; }
19048 x = this.getTick(x, this.xTicks);
19049 y = this.getTick(y, this.yTicks);
19056 * Sets up config options specific to this class. Overrides
19057 * Roo.dd.DragDrop, but all versions of this method through the
19058 * inheritance chain are called
19060 applyConfig: function() {
19061 Roo.dd.DD.superclass.applyConfig.call(this);
19062 this.scroll = (this.config.scroll !== false);
19066 * Event that fires prior to the onMouseDown event. Overrides
19069 b4MouseDown: function(e) {
19070 // this.resetConstraints();
19071 this.autoOffset(e.getPageX(),
19076 * Event that fires prior to the onDrag event. Overrides
19079 b4Drag: function(e) {
19080 this.setDragElPos(e.getPageX(),
19084 toString: function() {
19085 return ("DD " + this.id);
19088 //////////////////////////////////////////////////////////////////////////
19089 // Debugging ygDragDrop events that can be overridden
19090 //////////////////////////////////////////////////////////////////////////
19092 startDrag: function(x, y) {
19095 onDrag: function(e) {
19098 onDragEnter: function(e, id) {
19101 onDragOver: function(e, id) {
19104 onDragOut: function(e, id) {
19107 onDragDrop: function(e, id) {
19110 endDrag: function(e) {
19117 * Ext JS Library 1.1.1
19118 * Copyright(c) 2006-2007, Ext JS, LLC.
19120 * Originally Released Under LGPL - original licence link has changed is not relivant.
19123 * <script type="text/javascript">
19127 * @class Roo.dd.DDProxy
19128 * A DragDrop implementation that inserts an empty, bordered div into
19129 * the document that follows the cursor during drag operations. At the time of
19130 * the click, the frame div is resized to the dimensions of the linked html
19131 * element, and moved to the exact location of the linked element.
19133 * References to the "frame" element refer to the single proxy element that
19134 * was created to be dragged in place of all DDProxy elements on the
19137 * @extends Roo.dd.DD
19139 * @param {String} id the id of the linked html element
19140 * @param {String} sGroup the group of related DragDrop objects
19141 * @param {object} config an object containing configurable attributes
19142 * Valid properties for DDProxy in addition to those in DragDrop:
19143 * resizeFrame, centerFrame, dragElId
19145 Roo.dd.DDProxy = function(id, sGroup, config) {
19147 this.init(id, sGroup, config);
19153 * The default drag frame div id
19154 * @property Roo.dd.DDProxy.dragElId
19158 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19160 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19163 * By default we resize the drag frame to be the same size as the element
19164 * we want to drag (this is to get the frame effect). We can turn it off
19165 * if we want a different behavior.
19166 * @property resizeFrame
19172 * By default the frame is positioned exactly where the drag element is, so
19173 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19174 * you do not have constraints on the obj is to have the drag frame centered
19175 * around the cursor. Set centerFrame to true for this effect.
19176 * @property centerFrame
19179 centerFrame: false,
19182 * Creates the proxy element if it does not yet exist
19183 * @method createFrame
19185 createFrame: function() {
19187 var body = document.body;
19189 if (!body || !body.firstChild) {
19190 setTimeout( function() { self.createFrame(); }, 50 );
19194 var div = this.getDragEl();
19197 div = document.createElement("div");
19198 div.id = this.dragElId;
19201 s.position = "absolute";
19202 s.visibility = "hidden";
19204 s.border = "2px solid #aaa";
19207 // appendChild can blow up IE if invoked prior to the window load event
19208 // while rendering a table. It is possible there are other scenarios
19209 // that would cause this to happen as well.
19210 body.insertBefore(div, body.firstChild);
19215 * Initialization for the drag frame element. Must be called in the
19216 * constructor of all subclasses
19217 * @method initFrame
19219 initFrame: function() {
19220 this.createFrame();
19223 applyConfig: function() {
19224 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19226 this.resizeFrame = (this.config.resizeFrame !== false);
19227 this.centerFrame = (this.config.centerFrame);
19228 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19232 * Resizes the drag frame to the dimensions of the clicked object, positions
19233 * it over the object, and finally displays it
19234 * @method showFrame
19235 * @param {int} iPageX X click position
19236 * @param {int} iPageY Y click position
19239 showFrame: function(iPageX, iPageY) {
19240 var el = this.getEl();
19241 var dragEl = this.getDragEl();
19242 var s = dragEl.style;
19244 this._resizeProxy();
19246 if (this.centerFrame) {
19247 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19248 Math.round(parseInt(s.height, 10)/2) );
19251 this.setDragElPos(iPageX, iPageY);
19253 Roo.fly(dragEl).show();
19257 * The proxy is automatically resized to the dimensions of the linked
19258 * element when a drag is initiated, unless resizeFrame is set to false
19259 * @method _resizeProxy
19262 _resizeProxy: function() {
19263 if (this.resizeFrame) {
19264 var el = this.getEl();
19265 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19269 // overrides Roo.dd.DragDrop
19270 b4MouseDown: function(e) {
19271 var x = e.getPageX();
19272 var y = e.getPageY();
19273 this.autoOffset(x, y);
19274 this.setDragElPos(x, y);
19277 // overrides Roo.dd.DragDrop
19278 b4StartDrag: function(x, y) {
19279 // show the drag frame
19280 this.showFrame(x, y);
19283 // overrides Roo.dd.DragDrop
19284 b4EndDrag: function(e) {
19285 Roo.fly(this.getDragEl()).hide();
19288 // overrides Roo.dd.DragDrop
19289 // By default we try to move the element to the last location of the frame.
19290 // This is so that the default behavior mirrors that of Roo.dd.DD.
19291 endDrag: function(e) {
19293 var lel = this.getEl();
19294 var del = this.getDragEl();
19296 // Show the drag frame briefly so we can get its position
19297 del.style.visibility = "";
19300 // Hide the linked element before the move to get around a Safari
19302 lel.style.visibility = "hidden";
19303 Roo.dd.DDM.moveToEl(lel, del);
19304 del.style.visibility = "hidden";
19305 lel.style.visibility = "";
19310 beforeMove : function(){
19314 afterDrag : function(){
19318 toString: function() {
19319 return ("DDProxy " + this.id);
19325 * Ext JS Library 1.1.1
19326 * Copyright(c) 2006-2007, Ext JS, LLC.
19328 * Originally Released Under LGPL - original licence link has changed is not relivant.
19331 * <script type="text/javascript">
19335 * @class Roo.dd.DDTarget
19336 * A DragDrop implementation that does not move, but can be a drop
19337 * target. You would get the same result by simply omitting implementation
19338 * for the event callbacks, but this way we reduce the processing cost of the
19339 * event listener and the callbacks.
19340 * @extends Roo.dd.DragDrop
19342 * @param {String} id the id of the element that is a drop target
19343 * @param {String} sGroup the group of related DragDrop objects
19344 * @param {object} config an object containing configurable attributes
19345 * Valid properties for DDTarget in addition to those in
19349 Roo.dd.DDTarget = function(id, sGroup, config) {
19351 this.initTarget(id, sGroup, config);
19353 if (config.listeners || config.events) {
19354 Roo.dd.DragDrop.superclass.constructor.call(this, {
19355 listeners : config.listeners || {},
19356 events : config.events || {}
19361 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19362 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19363 toString: function() {
19364 return ("DDTarget " + this.id);
19369 * Ext JS Library 1.1.1
19370 * Copyright(c) 2006-2007, Ext JS, LLC.
19372 * Originally Released Under LGPL - original licence link has changed is not relivant.
19375 * <script type="text/javascript">
19380 * @class Roo.dd.ScrollManager
19381 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19382 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19385 Roo.dd.ScrollManager = function(){
19386 var ddm = Roo.dd.DragDropMgr;
19393 var onStop = function(e){
19398 var triggerRefresh = function(){
19399 if(ddm.dragCurrent){
19400 ddm.refreshCache(ddm.dragCurrent.groups);
19404 var doScroll = function(){
19405 if(ddm.dragCurrent){
19406 var dds = Roo.dd.ScrollManager;
19408 if(proc.el.scroll(proc.dir, dds.increment)){
19412 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19417 var clearProc = function(){
19419 clearInterval(proc.id);
19426 var startProc = function(el, dir){
19427 Roo.log('scroll startproc');
19431 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19434 var onFire = function(e, isDrop){
19436 if(isDrop || !ddm.dragCurrent){ return; }
19437 var dds = Roo.dd.ScrollManager;
19438 if(!dragEl || dragEl != ddm.dragCurrent){
19439 dragEl = ddm.dragCurrent;
19440 // refresh regions on drag start
19441 dds.refreshCache();
19444 var xy = Roo.lib.Event.getXY(e);
19445 var pt = new Roo.lib.Point(xy[0], xy[1]);
19446 for(var id in els){
19447 var el = els[id], r = el._region;
19448 if(r && r.contains(pt) && el.isScrollable()){
19449 if(r.bottom - pt.y <= dds.thresh){
19451 startProc(el, "down");
19454 }else if(r.right - pt.x <= dds.thresh){
19456 startProc(el, "left");
19459 }else if(pt.y - r.top <= dds.thresh){
19461 startProc(el, "up");
19464 }else if(pt.x - r.left <= dds.thresh){
19466 startProc(el, "right");
19475 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19476 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19480 * Registers new overflow element(s) to auto scroll
19481 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19483 register : function(el){
19484 if(el instanceof Array){
19485 for(var i = 0, len = el.length; i < len; i++) {
19486 this.register(el[i]);
19492 Roo.dd.ScrollManager.els = els;
19496 * Unregisters overflow element(s) so they are no longer scrolled
19497 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19499 unregister : function(el){
19500 if(el instanceof Array){
19501 for(var i = 0, len = el.length; i < len; i++) {
19502 this.unregister(el[i]);
19511 * The number of pixels from the edge of a container the pointer needs to be to
19512 * trigger scrolling (defaults to 25)
19518 * The number of pixels to scroll in each scroll increment (defaults to 50)
19524 * The frequency of scrolls in milliseconds (defaults to 500)
19530 * True to animate the scroll (defaults to true)
19536 * The animation duration in seconds -
19537 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19543 * Manually trigger a cache refresh.
19545 refreshCache : function(){
19546 for(var id in els){
19547 if(typeof els[id] == 'object'){ // for people extending the object prototype
19548 els[id]._region = els[id].getRegion();
19555 * Ext JS Library 1.1.1
19556 * Copyright(c) 2006-2007, Ext JS, LLC.
19558 * Originally Released Under LGPL - original licence link has changed is not relivant.
19561 * <script type="text/javascript">
19566 * @class Roo.dd.Registry
19567 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19568 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19571 Roo.dd.Registry = function(){
19574 var autoIdSeed = 0;
19576 var getId = function(el, autogen){
19577 if(typeof el == "string"){
19581 if(!id && autogen !== false){
19582 id = "roodd-" + (++autoIdSeed);
19590 * Register a drag drop element
19591 * @param {String|HTMLElement} element The id or DOM node to register
19592 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19593 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19594 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19595 * populated in the data object (if applicable):
19597 Value Description<br />
19598 --------- ------------------------------------------<br />
19599 handles Array of DOM nodes that trigger dragging<br />
19600 for the element being registered<br />
19601 isHandle True if the element passed in triggers<br />
19602 dragging itself, else false
19605 register : function(el, data){
19607 if(typeof el == "string"){
19608 el = document.getElementById(el);
19611 elements[getId(el)] = data;
19612 if(data.isHandle !== false){
19613 handles[data.ddel.id] = data;
19616 var hs = data.handles;
19617 for(var i = 0, len = hs.length; i < len; i++){
19618 handles[getId(hs[i])] = data;
19624 * Unregister a drag drop element
19625 * @param {String|HTMLElement} element The id or DOM node to unregister
19627 unregister : function(el){
19628 var id = getId(el, false);
19629 var data = elements[id];
19631 delete elements[id];
19633 var hs = data.handles;
19634 for(var i = 0, len = hs.length; i < len; i++){
19635 delete handles[getId(hs[i], false)];
19642 * Returns the handle registered for a DOM Node by id
19643 * @param {String|HTMLElement} id The DOM node or id to look up
19644 * @return {Object} handle The custom handle data
19646 getHandle : function(id){
19647 if(typeof id != "string"){ // must be element?
19650 return handles[id];
19654 * Returns the handle that is registered for the DOM node that is the target of the event
19655 * @param {Event} e The event
19656 * @return {Object} handle The custom handle data
19658 getHandleFromEvent : function(e){
19659 var t = Roo.lib.Event.getTarget(e);
19660 return t ? handles[t.id] : null;
19664 * Returns a custom data object that is registered for a DOM node by id
19665 * @param {String|HTMLElement} id The DOM node or id to look up
19666 * @return {Object} data The custom data
19668 getTarget : function(id){
19669 if(typeof id != "string"){ // must be element?
19672 return elements[id];
19676 * Returns a custom data object that is registered for the DOM node that is the target of the event
19677 * @param {Event} e The event
19678 * @return {Object} data The custom data
19680 getTargetFromEvent : function(e){
19681 var t = Roo.lib.Event.getTarget(e);
19682 return t ? elements[t.id] || handles[t.id] : null;
19687 * Ext JS Library 1.1.1
19688 * Copyright(c) 2006-2007, Ext JS, LLC.
19690 * Originally Released Under LGPL - original licence link has changed is not relivant.
19693 * <script type="text/javascript">
19698 * @class Roo.dd.StatusProxy
19699 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19700 * default drag proxy used by all Roo.dd components.
19702 * @param {Object} config
19704 Roo.dd.StatusProxy = function(config){
19705 Roo.apply(this, config);
19706 this.id = this.id || Roo.id();
19707 this.el = new Roo.Layer({
19709 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19710 {tag: "div", cls: "x-dd-drop-icon"},
19711 {tag: "div", cls: "x-dd-drag-ghost"}
19714 shadow: !config || config.shadow !== false
19716 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19717 this.dropStatus = this.dropNotAllowed;
19720 Roo.dd.StatusProxy.prototype = {
19722 * @cfg {String} dropAllowed
19723 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19725 dropAllowed : "x-dd-drop-ok",
19727 * @cfg {String} dropNotAllowed
19728 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19730 dropNotAllowed : "x-dd-drop-nodrop",
19733 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19734 * over the current target element.
19735 * @param {String} cssClass The css class for the new drop status indicator image
19737 setStatus : function(cssClass){
19738 cssClass = cssClass || this.dropNotAllowed;
19739 if(this.dropStatus != cssClass){
19740 this.el.replaceClass(this.dropStatus, cssClass);
19741 this.dropStatus = cssClass;
19746 * Resets the status indicator to the default dropNotAllowed value
19747 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19749 reset : function(clearGhost){
19750 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19751 this.dropStatus = this.dropNotAllowed;
19753 this.ghost.update("");
19758 * Updates the contents of the ghost element
19759 * @param {String} html The html that will replace the current innerHTML of the ghost element
19761 update : function(html){
19762 if(typeof html == "string"){
19763 this.ghost.update(html);
19765 this.ghost.update("");
19766 html.style.margin = "0";
19767 this.ghost.dom.appendChild(html);
19769 // ensure float = none set?? cant remember why though.
19770 var el = this.ghost.dom.firstChild;
19772 Roo.fly(el).setStyle('float', 'none');
19777 * Returns the underlying proxy {@link Roo.Layer}
19778 * @return {Roo.Layer} el
19780 getEl : function(){
19785 * Returns the ghost element
19786 * @return {Roo.Element} el
19788 getGhost : function(){
19794 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19796 hide : function(clear){
19804 * Stops the repair animation if it's currently running
19807 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19813 * Displays this proxy
19820 * Force the Layer to sync its shadow and shim positions to the element
19827 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19828 * invalid drop operation by the item being dragged.
19829 * @param {Array} xy The XY position of the element ([x, y])
19830 * @param {Function} callback The function to call after the repair is complete
19831 * @param {Object} scope The scope in which to execute the callback
19833 repair : function(xy, callback, scope){
19834 this.callback = callback;
19835 this.scope = scope;
19836 if(xy && this.animRepair !== false){
19837 this.el.addClass("x-dd-drag-repair");
19838 this.el.hideUnders(true);
19839 this.anim = this.el.shift({
19840 duration: this.repairDuration || .5,
19844 callback: this.afterRepair,
19848 this.afterRepair();
19853 afterRepair : function(){
19855 if(typeof this.callback == "function"){
19856 this.callback.call(this.scope || this);
19858 this.callback = null;
19863 * Ext JS Library 1.1.1
19864 * Copyright(c) 2006-2007, Ext JS, LLC.
19866 * Originally Released Under LGPL - original licence link has changed is not relivant.
19869 * <script type="text/javascript">
19873 * @class Roo.dd.DragSource
19874 * @extends Roo.dd.DDProxy
19875 * A simple class that provides the basic implementation needed to make any element draggable.
19877 * @param {String/HTMLElement/Element} el The container element
19878 * @param {Object} config
19880 Roo.dd.DragSource = function(el, config){
19881 this.el = Roo.get(el);
19882 this.dragData = {};
19884 Roo.apply(this, config);
19887 this.proxy = new Roo.dd.StatusProxy();
19890 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
19891 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
19893 this.dragging = false;
19896 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
19898 * @cfg {String} dropAllowed
19899 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
19901 dropAllowed : "x-dd-drop-ok",
19903 * @cfg {String} dropNotAllowed
19904 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
19906 dropNotAllowed : "x-dd-drop-nodrop",
19909 * Returns the data object associated with this drag source
19910 * @return {Object} data An object containing arbitrary data
19912 getDragData : function(e){
19913 return this.dragData;
19917 onDragEnter : function(e, id){
19918 var target = Roo.dd.DragDropMgr.getDDById(id);
19919 this.cachedTarget = target;
19920 if(this.beforeDragEnter(target, e, id) !== false){
19921 if(target.isNotifyTarget){
19922 var status = target.notifyEnter(this, e, this.dragData);
19923 this.proxy.setStatus(status);
19925 this.proxy.setStatus(this.dropAllowed);
19928 if(this.afterDragEnter){
19930 * An empty function by default, but provided so that you can perform a custom action
19931 * when the dragged item enters the drop target by providing an implementation.
19932 * @param {Roo.dd.DragDrop} target The drop target
19933 * @param {Event} e The event object
19934 * @param {String} id The id of the dragged element
19935 * @method afterDragEnter
19937 this.afterDragEnter(target, e, id);
19943 * An empty function by default, but provided so that you can perform a custom action
19944 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
19945 * @param {Roo.dd.DragDrop} target The drop target
19946 * @param {Event} e The event object
19947 * @param {String} id The id of the dragged element
19948 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19950 beforeDragEnter : function(target, e, id){
19955 alignElWithMouse: function() {
19956 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
19961 onDragOver : function(e, id){
19962 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19963 if(this.beforeDragOver(target, e, id) !== false){
19964 if(target.isNotifyTarget){
19965 var status = target.notifyOver(this, e, this.dragData);
19966 this.proxy.setStatus(status);
19969 if(this.afterDragOver){
19971 * An empty function by default, but provided so that you can perform a custom action
19972 * while the dragged item is over the drop target by providing an implementation.
19973 * @param {Roo.dd.DragDrop} target The drop target
19974 * @param {Event} e The event object
19975 * @param {String} id The id of the dragged element
19976 * @method afterDragOver
19978 this.afterDragOver(target, e, id);
19984 * An empty function by default, but provided so that you can perform a custom action
19985 * while the dragged item is over the drop target and optionally cancel the onDragOver.
19986 * @param {Roo.dd.DragDrop} target The drop target
19987 * @param {Event} e The event object
19988 * @param {String} id The id of the dragged element
19989 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
19991 beforeDragOver : function(target, e, id){
19996 onDragOut : function(e, id){
19997 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
19998 if(this.beforeDragOut(target, e, id) !== false){
19999 if(target.isNotifyTarget){
20000 target.notifyOut(this, e, this.dragData);
20002 this.proxy.reset();
20003 if(this.afterDragOut){
20005 * An empty function by default, but provided so that you can perform a custom action
20006 * after the dragged item is dragged out of the target without dropping.
20007 * @param {Roo.dd.DragDrop} target The drop target
20008 * @param {Event} e The event object
20009 * @param {String} id The id of the dragged element
20010 * @method afterDragOut
20012 this.afterDragOut(target, e, id);
20015 this.cachedTarget = null;
20019 * An empty function by default, but provided so that you can perform a custom action before the dragged
20020 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20021 * @param {Roo.dd.DragDrop} target The drop target
20022 * @param {Event} e The event object
20023 * @param {String} id The id of the dragged element
20024 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20026 beforeDragOut : function(target, e, id){
20031 onDragDrop : function(e, id){
20032 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20033 if(this.beforeDragDrop(target, e, id) !== false){
20034 if(target.isNotifyTarget){
20035 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20036 this.onValidDrop(target, e, id);
20038 this.onInvalidDrop(target, e, id);
20041 this.onValidDrop(target, e, id);
20044 if(this.afterDragDrop){
20046 * An empty function by default, but provided so that you can perform a custom action
20047 * after a valid drag drop has occurred by providing an implementation.
20048 * @param {Roo.dd.DragDrop} target The drop target
20049 * @param {Event} e The event object
20050 * @param {String} id The id of the dropped element
20051 * @method afterDragDrop
20053 this.afterDragDrop(target, e, id);
20056 delete this.cachedTarget;
20060 * An empty function by default, but provided so that you can perform a custom action before the dragged
20061 * item is dropped onto the target and optionally cancel the onDragDrop.
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 drop event is valid, else false to cancel
20067 beforeDragDrop : function(target, e, id){
20072 onValidDrop : function(target, e, id){
20074 if(this.afterValidDrop){
20076 * An empty function by default, but provided so that you can perform a custom action
20077 * after a valid drop has occurred by providing an implementation.
20078 * @param {Object} target The target DD
20079 * @param {Event} e The event object
20080 * @param {String} id The id of the dropped element
20081 * @method afterInvalidDrop
20083 this.afterValidDrop(target, e, id);
20088 getRepairXY : function(e, data){
20089 return this.el.getXY();
20093 onInvalidDrop : function(target, e, id){
20094 this.beforeInvalidDrop(target, e, id);
20095 if(this.cachedTarget){
20096 if(this.cachedTarget.isNotifyTarget){
20097 this.cachedTarget.notifyOut(this, e, this.dragData);
20099 this.cacheTarget = null;
20101 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20103 if(this.afterInvalidDrop){
20105 * An empty function by default, but provided so that you can perform a custom action
20106 * after an invalid drop has occurred by providing an implementation.
20107 * @param {Event} e The event object
20108 * @param {String} id The id of the dropped element
20109 * @method afterInvalidDrop
20111 this.afterInvalidDrop(e, id);
20116 afterRepair : function(){
20118 this.el.highlight(this.hlColor || "c3daf9");
20120 this.dragging = false;
20124 * An empty function by default, but provided so that you can perform a custom action after an invalid
20125 * drop has occurred.
20126 * @param {Roo.dd.DragDrop} target The drop target
20127 * @param {Event} e The event object
20128 * @param {String} id The id of the dragged element
20129 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20131 beforeInvalidDrop : function(target, e, id){
20136 handleMouseDown : function(e){
20137 if(this.dragging) {
20140 var data = this.getDragData(e);
20141 if(data && this.onBeforeDrag(data, e) !== false){
20142 this.dragData = data;
20144 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20149 * An empty function by default, but provided so that you can perform a custom action before the initial
20150 * drag event begins and optionally cancel it.
20151 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20152 * @param {Event} e The event object
20153 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20155 onBeforeDrag : function(data, e){
20160 * An empty function by default, but provided so that you can perform a custom action once the initial
20161 * drag event has begun. The drag cannot be canceled from this function.
20162 * @param {Number} x The x position of the click on the dragged object
20163 * @param {Number} y The y position of the click on the dragged object
20165 onStartDrag : Roo.emptyFn,
20167 // private - YUI override
20168 startDrag : function(x, y){
20169 this.proxy.reset();
20170 this.dragging = true;
20171 this.proxy.update("");
20172 this.onInitDrag(x, y);
20177 onInitDrag : function(x, y){
20178 var clone = this.el.dom.cloneNode(true);
20179 clone.id = Roo.id(); // prevent duplicate ids
20180 this.proxy.update(clone);
20181 this.onStartDrag(x, y);
20186 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20187 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20189 getProxy : function(){
20194 * Hides the drag source's {@link Roo.dd.StatusProxy}
20196 hideProxy : function(){
20198 this.proxy.reset(true);
20199 this.dragging = false;
20203 triggerCacheRefresh : function(){
20204 Roo.dd.DDM.refreshCache(this.groups);
20207 // private - override to prevent hiding
20208 b4EndDrag: function(e) {
20211 // private - override to prevent moving
20212 endDrag : function(e){
20213 this.onEndDrag(this.dragData, e);
20217 onEndDrag : function(data, e){
20220 // private - pin to cursor
20221 autoOffset : function(x, y) {
20222 this.setDelta(-12, -20);
20226 * Ext JS Library 1.1.1
20227 * Copyright(c) 2006-2007, Ext JS, LLC.
20229 * Originally Released Under LGPL - original licence link has changed is not relivant.
20232 * <script type="text/javascript">
20237 * @class Roo.dd.DropTarget
20238 * @extends Roo.dd.DDTarget
20239 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20240 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20242 * @param {String/HTMLElement/Element} el The container element
20243 * @param {Object} config
20245 Roo.dd.DropTarget = function(el, config){
20246 this.el = Roo.get(el);
20248 var listeners = false; ;
20249 if (config && config.listeners) {
20250 listeners= config.listeners;
20251 delete config.listeners;
20253 Roo.apply(this, config);
20255 if(this.containerScroll){
20256 Roo.dd.ScrollManager.register(this.el);
20260 * @scope Roo.dd.DropTarget
20265 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20266 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20267 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20269 * IMPORTANT : it should set this.overClass and this.dropAllowed
20271 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20272 * @param {Event} e The event
20273 * @param {Object} data An object containing arbitrary data supplied by the drag source
20279 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20280 * This method will be called on every mouse movement while the drag source is over the drop target.
20281 * This default implementation simply returns the dropAllowed config value.
20283 * IMPORTANT : it should set this.dropAllowed
20285 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20286 * @param {Event} e The event
20287 * @param {Object} data An object containing arbitrary data supplied by the drag source
20293 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20294 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20295 * overClass (if any) from the drop element.
20297 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20298 * @param {Event} e The event
20299 * @param {Object} data An object containing arbitrary data supplied by the drag source
20305 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20306 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20307 * implementation that does something to process the drop event and returns true so that the drag source's
20308 * repair action does not run.
20310 * IMPORTANT : it should set this.success
20312 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20313 * @param {Event} e The event
20314 * @param {Object} data An object containing arbitrary data supplied by the drag source
20320 Roo.dd.DropTarget.superclass.constructor.call( this,
20322 this.ddGroup || this.group,
20325 listeners : listeners || {}
20333 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20335 * @cfg {String} overClass
20336 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20339 * @cfg {String} ddGroup
20340 * The drag drop group to handle drop events for
20344 * @cfg {String} dropAllowed
20345 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20347 dropAllowed : "x-dd-drop-ok",
20349 * @cfg {String} dropNotAllowed
20350 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20352 dropNotAllowed : "x-dd-drop-nodrop",
20354 * @cfg {boolean} success
20355 * set this after drop listener..
20359 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20360 * if the drop point is valid for over/enter..
20367 isNotifyTarget : true,
20372 notifyEnter : function(dd, e, data)
20375 this.fireEvent('enter', dd, e, data);
20376 if(this.overClass){
20377 this.el.addClass(this.overClass);
20379 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20380 this.valid ? this.dropAllowed : this.dropNotAllowed
20387 notifyOver : function(dd, e, data)
20390 this.fireEvent('over', dd, e, data);
20391 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20392 this.valid ? this.dropAllowed : this.dropNotAllowed
20399 notifyOut : function(dd, e, data)
20401 this.fireEvent('out', dd, e, data);
20402 if(this.overClass){
20403 this.el.removeClass(this.overClass);
20410 notifyDrop : function(dd, e, data)
20412 this.success = false;
20413 this.fireEvent('drop', dd, e, data);
20414 return this.success;
20418 * Ext JS Library 1.1.1
20419 * Copyright(c) 2006-2007, Ext JS, LLC.
20421 * Originally Released Under LGPL - original licence link has changed is not relivant.
20424 * <script type="text/javascript">
20429 * @class Roo.dd.DragZone
20430 * @extends Roo.dd.DragSource
20431 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20432 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20434 * @param {String/HTMLElement/Element} el The container element
20435 * @param {Object} config
20437 Roo.dd.DragZone = function(el, config){
20438 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20439 if(this.containerScroll){
20440 Roo.dd.ScrollManager.register(this.el);
20444 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20446 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20447 * for auto scrolling during drag operations.
20450 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20451 * method after a failed drop (defaults to "c3daf9" - light blue)
20455 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20456 * for a valid target to drag based on the mouse down. Override this method
20457 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20458 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20459 * @param {EventObject} e The mouse down event
20460 * @return {Object} The dragData
20462 getDragData : function(e){
20463 return Roo.dd.Registry.getHandleFromEvent(e);
20467 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20468 * this.dragData.ddel
20469 * @param {Number} x The x position of the click on the dragged object
20470 * @param {Number} y The y position of the click on the dragged object
20471 * @return {Boolean} true to continue the drag, false to cancel
20473 onInitDrag : function(x, y){
20474 this.proxy.update(this.dragData.ddel.cloneNode(true));
20475 this.onStartDrag(x, y);
20480 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20482 afterRepair : function(){
20484 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20486 this.dragging = false;
20490 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20491 * the XY of this.dragData.ddel
20492 * @param {EventObject} e The mouse up event
20493 * @return {Array} The xy location (e.g. [100, 200])
20495 getRepairXY : function(e){
20496 return Roo.Element.fly(this.dragData.ddel).getXY();
20500 * Ext JS Library 1.1.1
20501 * Copyright(c) 2006-2007, Ext JS, LLC.
20503 * Originally Released Under LGPL - original licence link has changed is not relivant.
20506 * <script type="text/javascript">
20509 * @class Roo.dd.DropZone
20510 * @extends Roo.dd.DropTarget
20511 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20512 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20514 * @param {String/HTMLElement/Element} el The container element
20515 * @param {Object} config
20517 Roo.dd.DropZone = function(el, config){
20518 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20521 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20523 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20524 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20525 * provide your own custom lookup.
20526 * @param {Event} e The event
20527 * @return {Object} data The custom data
20529 getTargetFromEvent : function(e){
20530 return Roo.dd.Registry.getTargetFromEvent(e);
20534 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20535 * that it has registered. This method has no default implementation and should be overridden to provide
20536 * node-specific processing if necessary.
20537 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20538 * {@link #getTargetFromEvent} for this node)
20539 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20540 * @param {Event} e The event
20541 * @param {Object} data An object containing arbitrary data supplied by the drag source
20543 onNodeEnter : function(n, dd, e, data){
20548 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20549 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20550 * overridden to provide the proper feedback.
20551 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20552 * {@link #getTargetFromEvent} for this node)
20553 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20554 * @param {Event} e The event
20555 * @param {Object} data An object containing arbitrary data supplied by the drag source
20556 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20557 * underlying {@link Roo.dd.StatusProxy} can be updated
20559 onNodeOver : function(n, dd, e, data){
20560 return this.dropAllowed;
20564 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20565 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20566 * node-specific processing if necessary.
20567 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20568 * {@link #getTargetFromEvent} for this node)
20569 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20570 * @param {Event} e The event
20571 * @param {Object} data An object containing arbitrary data supplied by the drag source
20573 onNodeOut : function(n, dd, e, data){
20578 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20579 * the drop node. The default implementation returns false, so it should be overridden to provide the
20580 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20581 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20582 * {@link #getTargetFromEvent} for this node)
20583 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20584 * @param {Event} e The event
20585 * @param {Object} data An object containing arbitrary data supplied by the drag source
20586 * @return {Boolean} True if the drop was valid, else false
20588 onNodeDrop : function(n, dd, e, data){
20593 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20594 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20595 * it should be overridden to provide the proper feedback if necessary.
20596 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20597 * @param {Event} e The event
20598 * @param {Object} data An object containing arbitrary data supplied by the drag source
20599 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20600 * underlying {@link Roo.dd.StatusProxy} can be updated
20602 onContainerOver : function(dd, e, data){
20603 return this.dropNotAllowed;
20607 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20608 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20609 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20610 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20611 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20612 * @param {Event} e The event
20613 * @param {Object} data An object containing arbitrary data supplied by the drag source
20614 * @return {Boolean} True if the drop was valid, else false
20616 onContainerDrop : function(dd, e, data){
20621 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20622 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20623 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20624 * you should override this method and provide a custom implementation.
20625 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20626 * @param {Event} e The event
20627 * @param {Object} data An object containing arbitrary data supplied by the drag source
20628 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20629 * underlying {@link Roo.dd.StatusProxy} can be updated
20631 notifyEnter : function(dd, e, data){
20632 return this.dropNotAllowed;
20636 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20637 * This method will be called on every mouse movement while the drag source is over the drop zone.
20638 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20639 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20640 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20641 * registered node, it will call {@link #onContainerOver}.
20642 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20643 * @param {Event} e The event
20644 * @param {Object} data An object containing arbitrary data supplied by the drag source
20645 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20646 * underlying {@link Roo.dd.StatusProxy} can be updated
20648 notifyOver : function(dd, e, data){
20649 var n = this.getTargetFromEvent(e);
20650 if(!n){ // not over valid drop target
20651 if(this.lastOverNode){
20652 this.onNodeOut(this.lastOverNode, dd, e, data);
20653 this.lastOverNode = null;
20655 return this.onContainerOver(dd, e, data);
20657 if(this.lastOverNode != n){
20658 if(this.lastOverNode){
20659 this.onNodeOut(this.lastOverNode, dd, e, data);
20661 this.onNodeEnter(n, dd, e, data);
20662 this.lastOverNode = n;
20664 return this.onNodeOver(n, dd, e, data);
20668 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20669 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20670 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20671 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20672 * @param {Event} e The event
20673 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20675 notifyOut : function(dd, e, data){
20676 if(this.lastOverNode){
20677 this.onNodeOut(this.lastOverNode, dd, e, data);
20678 this.lastOverNode = null;
20683 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20684 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20685 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20686 * otherwise it will call {@link #onContainerDrop}.
20687 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20688 * @param {Event} e The event
20689 * @param {Object} data An object containing arbitrary data supplied by the drag source
20690 * @return {Boolean} True if the drop was valid, else false
20692 notifyDrop : function(dd, e, data){
20693 if(this.lastOverNode){
20694 this.onNodeOut(this.lastOverNode, dd, e, data);
20695 this.lastOverNode = null;
20697 var n = this.getTargetFromEvent(e);
20699 this.onNodeDrop(n, dd, e, data) :
20700 this.onContainerDrop(dd, e, data);
20704 triggerCacheRefresh : function(){
20705 Roo.dd.DDM.refreshCache(this.groups);
20709 * Ext JS Library 1.1.1
20710 * Copyright(c) 2006-2007, Ext JS, LLC.
20712 * Originally Released Under LGPL - original licence link has changed is not relivant.
20715 * <script type="text/javascript">
20720 * @class Roo.data.SortTypes
20722 * Defines the default sorting (casting?) comparison functions used when sorting data.
20724 Roo.data.SortTypes = {
20726 * Default sort that does nothing
20727 * @param {Mixed} s The value being converted
20728 * @return {Mixed} The comparison value
20730 none : function(s){
20735 * The regular expression used to strip tags
20739 stripTagsRE : /<\/?[^>]+>/gi,
20742 * Strips all HTML tags to sort on text only
20743 * @param {Mixed} s The value being converted
20744 * @return {String} The comparison value
20746 asText : function(s){
20747 return String(s).replace(this.stripTagsRE, "");
20751 * Strips all HTML tags to sort on text only - Case insensitive
20752 * @param {Mixed} s The value being converted
20753 * @return {String} The comparison value
20755 asUCText : function(s){
20756 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20760 * Case insensitive string
20761 * @param {Mixed} s The value being converted
20762 * @return {String} The comparison value
20764 asUCString : function(s) {
20765 return String(s).toUpperCase();
20770 * @param {Mixed} s The value being converted
20771 * @return {Number} The comparison value
20773 asDate : function(s) {
20777 if(s instanceof Date){
20778 return s.getTime();
20780 return Date.parse(String(s));
20785 * @param {Mixed} s The value being converted
20786 * @return {Float} The comparison value
20788 asFloat : function(s) {
20789 var val = parseFloat(String(s).replace(/,/g, ""));
20790 if(isNaN(val)) val = 0;
20796 * @param {Mixed} s The value being converted
20797 * @return {Number} The comparison value
20799 asInt : function(s) {
20800 var val = parseInt(String(s).replace(/,/g, ""));
20801 if(isNaN(val)) val = 0;
20806 * Ext JS Library 1.1.1
20807 * Copyright(c) 2006-2007, Ext JS, LLC.
20809 * Originally Released Under LGPL - original licence link has changed is not relivant.
20812 * <script type="text/javascript">
20816 * @class Roo.data.Record
20817 * Instances of this class encapsulate both record <em>definition</em> information, and record
20818 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20819 * to access Records cached in an {@link Roo.data.Store} object.<br>
20821 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20822 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20825 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20827 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20828 * {@link #create}. The parameters are the same.
20829 * @param {Array} data An associative Array of data values keyed by the field name.
20830 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20831 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20832 * not specified an integer id is generated.
20834 Roo.data.Record = function(data, id){
20835 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20840 * Generate a constructor for a specific record layout.
20841 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20842 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20843 * Each field definition object may contain the following properties: <ul>
20844 * <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,
20845 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20846 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20847 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20848 * is being used, then this is a string containing the javascript expression to reference the data relative to
20849 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20850 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20851 * this may be omitted.</p></li>
20852 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20853 * <ul><li>auto (Default, implies no conversion)</li>
20858 * <li>date</li></ul></p></li>
20859 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20860 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20861 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20862 * by the Reader into an object that will be stored in the Record. It is passed the
20863 * following parameters:<ul>
20864 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20866 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20868 * <br>usage:<br><pre><code>
20869 var TopicRecord = Roo.data.Record.create(
20870 {name: 'title', mapping: 'topic_title'},
20871 {name: 'author', mapping: 'username'},
20872 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20873 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20874 {name: 'lastPoster', mapping: 'user2'},
20875 {name: 'excerpt', mapping: 'post_text'}
20878 var myNewRecord = new TopicRecord({
20879 title: 'Do my job please',
20882 lastPost: new Date(),
20883 lastPoster: 'Animal',
20884 excerpt: 'No way dude!'
20886 myStore.add(myNewRecord);
20891 Roo.data.Record.create = function(o){
20892 var f = function(){
20893 f.superclass.constructor.apply(this, arguments);
20895 Roo.extend(f, Roo.data.Record);
20896 var p = f.prototype;
20897 p.fields = new Roo.util.MixedCollection(false, function(field){
20900 for(var i = 0, len = o.length; i < len; i++){
20901 p.fields.add(new Roo.data.Field(o[i]));
20903 f.getField = function(name){
20904 return p.fields.get(name);
20909 Roo.data.Record.AUTO_ID = 1000;
20910 Roo.data.Record.EDIT = 'edit';
20911 Roo.data.Record.REJECT = 'reject';
20912 Roo.data.Record.COMMIT = 'commit';
20914 Roo.data.Record.prototype = {
20916 * Readonly flag - true if this record has been modified.
20925 join : function(store){
20926 this.store = store;
20930 * Set the named field to the specified value.
20931 * @param {String} name The name of the field to set.
20932 * @param {Object} value The value to set the field to.
20934 set : function(name, value){
20935 if(this.data[name] == value){
20939 if(!this.modified){
20940 this.modified = {};
20942 if(typeof this.modified[name] == 'undefined'){
20943 this.modified[name] = this.data[name];
20945 this.data[name] = value;
20946 if(!this.editing && this.store){
20947 this.store.afterEdit(this);
20952 * Get the value of the named field.
20953 * @param {String} name The name of the field to get the value of.
20954 * @return {Object} The value of the field.
20956 get : function(name){
20957 return this.data[name];
20961 beginEdit : function(){
20962 this.editing = true;
20963 this.modified = {};
20967 cancelEdit : function(){
20968 this.editing = false;
20969 delete this.modified;
20973 endEdit : function(){
20974 this.editing = false;
20975 if(this.dirty && this.store){
20976 this.store.afterEdit(this);
20981 * Usually called by the {@link Roo.data.Store} which owns the Record.
20982 * Rejects all changes made to the Record since either creation, or the last commit operation.
20983 * Modified fields are reverted to their original values.
20985 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
20986 * of reject operations.
20988 reject : function(){
20989 var m = this.modified;
20991 if(typeof m[n] != "function"){
20992 this.data[n] = m[n];
20995 this.dirty = false;
20996 delete this.modified;
20997 this.editing = false;
20999 this.store.afterReject(this);
21004 * Usually called by the {@link Roo.data.Store} which owns the Record.
21005 * Commits all changes made to the Record since either creation, or the last commit operation.
21007 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21008 * of commit operations.
21010 commit : function(){
21011 this.dirty = false;
21012 delete this.modified;
21013 this.editing = false;
21015 this.store.afterCommit(this);
21020 hasError : function(){
21021 return this.error != null;
21025 clearError : function(){
21030 * Creates a copy of this record.
21031 * @param {String} id (optional) A new record id if you don't want to use this record's id
21034 copy : function(newId) {
21035 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21039 * Ext JS Library 1.1.1
21040 * Copyright(c) 2006-2007, Ext JS, LLC.
21042 * Originally Released Under LGPL - original licence link has changed is not relivant.
21045 * <script type="text/javascript">
21051 * @class Roo.data.Store
21052 * @extends Roo.util.Observable
21053 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21054 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21056 * 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
21057 * has no knowledge of the format of the data returned by the Proxy.<br>
21059 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21060 * instances from the data object. These records are cached and made available through accessor functions.
21062 * Creates a new Store.
21063 * @param {Object} config A config object containing the objects needed for the Store to access data,
21064 * and read the data into Records.
21066 Roo.data.Store = function(config){
21067 this.data = new Roo.util.MixedCollection(false);
21068 this.data.getKey = function(o){
21071 this.baseParams = {};
21073 this.paramNames = {
21078 "multisort" : "_multisort"
21081 if(config && config.data){
21082 this.inlineData = config.data;
21083 delete config.data;
21086 Roo.apply(this, config);
21088 if(this.reader){ // reader passed
21089 this.reader = Roo.factory(this.reader, Roo.data);
21090 this.reader.xmodule = this.xmodule || false;
21091 if(!this.recordType){
21092 this.recordType = this.reader.recordType;
21094 if(this.reader.onMetaChange){
21095 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21099 if(this.recordType){
21100 this.fields = this.recordType.prototype.fields;
21102 this.modified = [];
21106 * @event datachanged
21107 * Fires when the data cache has changed, and a widget which is using this Store
21108 * as a Record cache should refresh its view.
21109 * @param {Store} this
21111 datachanged : true,
21113 * @event metachange
21114 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21115 * @param {Store} this
21116 * @param {Object} meta The JSON metadata
21121 * Fires when Records have been added to the Store
21122 * @param {Store} this
21123 * @param {Roo.data.Record[]} records The array of Records added
21124 * @param {Number} index The index at which the record(s) were added
21129 * Fires when a Record has been removed from the Store
21130 * @param {Store} this
21131 * @param {Roo.data.Record} record The Record that was removed
21132 * @param {Number} index The index at which the record was removed
21137 * Fires when a Record has been updated
21138 * @param {Store} this
21139 * @param {Roo.data.Record} record The Record that was updated
21140 * @param {String} operation The update operation being performed. Value may be one of:
21142 Roo.data.Record.EDIT
21143 Roo.data.Record.REJECT
21144 Roo.data.Record.COMMIT
21150 * Fires when the data cache has been cleared.
21151 * @param {Store} this
21155 * @event beforeload
21156 * Fires before a request is made for a new data object. If the beforeload handler returns false
21157 * the load action will be canceled.
21158 * @param {Store} this
21159 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21163 * @event beforeloadadd
21164 * Fires after a new set of Records has been loaded.
21165 * @param {Store} this
21166 * @param {Roo.data.Record[]} records The Records that were loaded
21167 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21169 beforeloadadd : true,
21172 * Fires after a new set of Records has been loaded, before they are added to the store.
21173 * @param {Store} this
21174 * @param {Roo.data.Record[]} records The Records that were loaded
21175 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21176 * @params {Object} return from reader
21180 * @event loadexception
21181 * Fires if an exception occurs in the Proxy during loading.
21182 * Called with the signature of the Proxy's "loadexception" event.
21183 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21186 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21187 * @param {Object} load options
21188 * @param {Object} jsonData from your request (normally this contains the Exception)
21190 loadexception : true
21194 this.proxy = Roo.factory(this.proxy, Roo.data);
21195 this.proxy.xmodule = this.xmodule || false;
21196 this.relayEvents(this.proxy, ["loadexception"]);
21198 this.sortToggle = {};
21199 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21201 Roo.data.Store.superclass.constructor.call(this);
21203 if(this.inlineData){
21204 this.loadData(this.inlineData);
21205 delete this.inlineData;
21209 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21211 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21212 * without a remote query - used by combo/forms at present.
21216 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21219 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21222 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21223 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21226 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21227 * on any HTTP request
21230 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21233 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21237 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21238 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21240 remoteSort : false,
21243 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21244 * loaded or when a record is removed. (defaults to false).
21246 pruneModifiedRecords : false,
21249 lastOptions : null,
21252 * Add Records to the Store and fires the add event.
21253 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21255 add : function(records){
21256 records = [].concat(records);
21257 for(var i = 0, len = records.length; i < len; i++){
21258 records[i].join(this);
21260 var index = this.data.length;
21261 this.data.addAll(records);
21262 this.fireEvent("add", this, records, index);
21266 * Remove a Record from the Store and fires the remove event.
21267 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21269 remove : function(record){
21270 var index = this.data.indexOf(record);
21271 this.data.removeAt(index);
21272 if(this.pruneModifiedRecords){
21273 this.modified.remove(record);
21275 this.fireEvent("remove", this, record, index);
21279 * Remove all Records from the Store and fires the clear event.
21281 removeAll : function(){
21283 if(this.pruneModifiedRecords){
21284 this.modified = [];
21286 this.fireEvent("clear", this);
21290 * Inserts Records to the Store at the given index and fires the add event.
21291 * @param {Number} index The start index at which to insert the passed Records.
21292 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21294 insert : function(index, records){
21295 records = [].concat(records);
21296 for(var i = 0, len = records.length; i < len; i++){
21297 this.data.insert(index, records[i]);
21298 records[i].join(this);
21300 this.fireEvent("add", this, records, index);
21304 * Get the index within the cache of the passed Record.
21305 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21306 * @return {Number} The index of the passed Record. Returns -1 if not found.
21308 indexOf : function(record){
21309 return this.data.indexOf(record);
21313 * Get the index within the cache of the Record with the passed id.
21314 * @param {String} id The id of the Record to find.
21315 * @return {Number} The index of the Record. Returns -1 if not found.
21317 indexOfId : function(id){
21318 return this.data.indexOfKey(id);
21322 * Get the Record with the specified id.
21323 * @param {String} id The id of the Record to find.
21324 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21326 getById : function(id){
21327 return this.data.key(id);
21331 * Get the Record at the specified index.
21332 * @param {Number} index The index of the Record to find.
21333 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21335 getAt : function(index){
21336 return this.data.itemAt(index);
21340 * Returns a range of Records between specified indices.
21341 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21342 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21343 * @return {Roo.data.Record[]} An array of Records
21345 getRange : function(start, end){
21346 return this.data.getRange(start, end);
21350 storeOptions : function(o){
21351 o = Roo.apply({}, o);
21354 this.lastOptions = o;
21358 * Loads the Record cache from the configured Proxy using the configured Reader.
21360 * If using remote paging, then the first load call must specify the <em>start</em>
21361 * and <em>limit</em> properties in the options.params property to establish the initial
21362 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21364 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21365 * and this call will return before the new data has been loaded. Perform any post-processing
21366 * in a callback function, or in a "load" event handler.</strong>
21368 * @param {Object} options An object containing properties which control loading options:<ul>
21369 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21370 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21371 * passed the following arguments:<ul>
21372 * <li>r : Roo.data.Record[]</li>
21373 * <li>options: Options object from the load call</li>
21374 * <li>success: Boolean success indicator</li></ul></li>
21375 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21376 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21379 load : function(options){
21380 options = options || {};
21381 if(this.fireEvent("beforeload", this, options) !== false){
21382 this.storeOptions(options);
21383 var p = Roo.apply(options.params || {}, this.baseParams);
21384 // if meta was not loaded from remote source.. try requesting it.
21385 if (!this.reader.metaFromRemote) {
21386 p._requestMeta = 1;
21388 if(this.sortInfo && this.remoteSort){
21389 var pn = this.paramNames;
21390 p[pn["sort"]] = this.sortInfo.field;
21391 p[pn["dir"]] = this.sortInfo.direction;
21393 if (this.multiSort) {
21394 var pn = this.paramNames;
21395 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21398 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21403 * Reloads the Record cache from the configured Proxy using the configured Reader and
21404 * the options from the last load operation performed.
21405 * @param {Object} options (optional) An object containing properties which may override the options
21406 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21407 * the most recently used options are reused).
21409 reload : function(options){
21410 this.load(Roo.applyIf(options||{}, this.lastOptions));
21414 // Called as a callback by the Reader during a load operation.
21415 loadRecords : function(o, options, success){
21416 if(!o || success === false){
21417 if(success !== false){
21418 this.fireEvent("load", this, [], options, o);
21420 if(options.callback){
21421 options.callback.call(options.scope || this, [], options, false);
21425 // if data returned failure - throw an exception.
21426 if (o.success === false) {
21427 // show a message if no listener is registered.
21428 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21429 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21431 // loadmask wil be hooked into this..
21432 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21435 var r = o.records, t = o.totalRecords || r.length;
21437 this.fireEvent("beforeloadadd", this, r, options, o);
21439 if(!options || options.add !== true){
21440 if(this.pruneModifiedRecords){
21441 this.modified = [];
21443 for(var i = 0, len = r.length; i < len; i++){
21447 this.data = this.snapshot;
21448 delete this.snapshot;
21451 this.data.addAll(r);
21452 this.totalLength = t;
21454 this.fireEvent("datachanged", this);
21456 this.totalLength = Math.max(t, this.data.length+r.length);
21459 this.fireEvent("load", this, r, options, o);
21460 if(options.callback){
21461 options.callback.call(options.scope || this, r, options, true);
21467 * Loads data from a passed data block. A Reader which understands the format of the data
21468 * must have been configured in the constructor.
21469 * @param {Object} data The data block from which to read the Records. The format of the data expected
21470 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21471 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21473 loadData : function(o, append){
21474 var r = this.reader.readRecords(o);
21475 this.loadRecords(r, {add: append}, true);
21479 * Gets the number of cached records.
21481 * <em>If using paging, this may not be the total size of the dataset. If the data object
21482 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21483 * the data set size</em>
21485 getCount : function(){
21486 return this.data.length || 0;
21490 * Gets the total number of records in the dataset as returned by the server.
21492 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21493 * the dataset size</em>
21495 getTotalCount : function(){
21496 return this.totalLength || 0;
21500 * Returns the sort state of the Store as an object with two properties:
21502 field {String} The name of the field by which the Records are sorted
21503 direction {String} The sort order, "ASC" or "DESC"
21506 getSortState : function(){
21507 return this.sortInfo;
21511 applySort : function(){
21512 if(this.sortInfo && !this.remoteSort){
21513 var s = this.sortInfo, f = s.field;
21514 var st = this.fields.get(f).sortType;
21515 var fn = function(r1, r2){
21516 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21517 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21519 this.data.sort(s.direction, fn);
21520 if(this.snapshot && this.snapshot != this.data){
21521 this.snapshot.sort(s.direction, fn);
21527 * Sets the default sort column and order to be used by the next load operation.
21528 * @param {String} fieldName The name of the field to sort by.
21529 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21531 setDefaultSort : function(field, dir){
21532 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21536 * Sort the Records.
21537 * If remote sorting is used, the sort is performed on the server, and the cache is
21538 * reloaded. If local sorting is used, the cache is sorted internally.
21539 * @param {String} fieldName The name of the field to sort by.
21540 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21542 sort : function(fieldName, dir){
21543 var f = this.fields.get(fieldName);
21545 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21547 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21548 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21553 this.sortToggle[f.name] = dir;
21554 this.sortInfo = {field: f.name, direction: dir};
21555 if(!this.remoteSort){
21557 this.fireEvent("datachanged", this);
21559 this.load(this.lastOptions);
21564 * Calls the specified function for each of the Records in the cache.
21565 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21566 * Returning <em>false</em> aborts and exits the iteration.
21567 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21569 each : function(fn, scope){
21570 this.data.each(fn, scope);
21574 * Gets all records modified since the last commit. Modified records are persisted across load operations
21575 * (e.g., during paging).
21576 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21578 getModifiedRecords : function(){
21579 return this.modified;
21583 createFilterFn : function(property, value, anyMatch){
21584 if(!value.exec){ // not a regex
21585 value = String(value);
21586 if(value.length == 0){
21589 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21591 return function(r){
21592 return value.test(r.data[property]);
21597 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21598 * @param {String} property A field on your records
21599 * @param {Number} start The record index to start at (defaults to 0)
21600 * @param {Number} end The last record index to include (defaults to length - 1)
21601 * @return {Number} The sum
21603 sum : function(property, start, end){
21604 var rs = this.data.items, v = 0;
21605 start = start || 0;
21606 end = (end || end === 0) ? end : rs.length-1;
21608 for(var i = start; i <= end; i++){
21609 v += (rs[i].data[property] || 0);
21615 * Filter the records by a specified property.
21616 * @param {String} field A field on your records
21617 * @param {String/RegExp} value Either a string that the field
21618 * should start with or a RegExp to test against the field
21619 * @param {Boolean} anyMatch True to match any part not just the beginning
21621 filter : function(property, value, anyMatch){
21622 var fn = this.createFilterFn(property, value, anyMatch);
21623 return fn ? this.filterBy(fn) : this.clearFilter();
21627 * Filter by a function. The specified function will be called with each
21628 * record in this data source. If the function returns true the record is included,
21629 * otherwise it is filtered.
21630 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21631 * @param {Object} scope (optional) The scope of the function (defaults to this)
21633 filterBy : function(fn, scope){
21634 this.snapshot = this.snapshot || this.data;
21635 this.data = this.queryBy(fn, scope||this);
21636 this.fireEvent("datachanged", this);
21640 * Query the records by a specified property.
21641 * @param {String} field A field on your records
21642 * @param {String/RegExp} value Either a string that the field
21643 * should start with or a RegExp to test against the field
21644 * @param {Boolean} anyMatch True to match any part not just the beginning
21645 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21647 query : function(property, value, anyMatch){
21648 var fn = this.createFilterFn(property, value, anyMatch);
21649 return fn ? this.queryBy(fn) : this.data.clone();
21653 * Query by a function. The specified function will be called with each
21654 * record in this data source. If the function returns true the record is included
21656 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21657 * @param {Object} scope (optional) The scope of the function (defaults to this)
21658 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21660 queryBy : function(fn, scope){
21661 var data = this.snapshot || this.data;
21662 return data.filterBy(fn, scope||this);
21666 * Collects unique values for a particular dataIndex from this store.
21667 * @param {String} dataIndex The property to collect
21668 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21669 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21670 * @return {Array} An array of the unique values
21672 collect : function(dataIndex, allowNull, bypassFilter){
21673 var d = (bypassFilter === true && this.snapshot) ?
21674 this.snapshot.items : this.data.items;
21675 var v, sv, r = [], l = {};
21676 for(var i = 0, len = d.length; i < len; i++){
21677 v = d[i].data[dataIndex];
21679 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21688 * Revert to a view of the Record cache with no filtering applied.
21689 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21691 clearFilter : function(suppressEvent){
21692 if(this.snapshot && this.snapshot != this.data){
21693 this.data = this.snapshot;
21694 delete this.snapshot;
21695 if(suppressEvent !== true){
21696 this.fireEvent("datachanged", this);
21702 afterEdit : function(record){
21703 if(this.modified.indexOf(record) == -1){
21704 this.modified.push(record);
21706 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21710 afterReject : function(record){
21711 this.modified.remove(record);
21712 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21716 afterCommit : function(record){
21717 this.modified.remove(record);
21718 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21722 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21723 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21725 commitChanges : function(){
21726 var m = this.modified.slice(0);
21727 this.modified = [];
21728 for(var i = 0, len = m.length; i < len; i++){
21734 * Cancel outstanding changes on all changed records.
21736 rejectChanges : function(){
21737 var m = this.modified.slice(0);
21738 this.modified = [];
21739 for(var i = 0, len = m.length; i < len; i++){
21744 onMetaChange : function(meta, rtype, o){
21745 this.recordType = rtype;
21746 this.fields = rtype.prototype.fields;
21747 delete this.snapshot;
21748 this.sortInfo = meta.sortInfo || this.sortInfo;
21749 this.modified = [];
21750 this.fireEvent('metachange', this, this.reader.meta);
21753 moveIndex : function(data, type)
21755 var index = this.indexOf(data);
21757 var newIndex = index + type;
21761 this.insert(newIndex, data);
21766 * Ext JS Library 1.1.1
21767 * Copyright(c) 2006-2007, Ext JS, LLC.
21769 * Originally Released Under LGPL - original licence link has changed is not relivant.
21772 * <script type="text/javascript">
21776 * @class Roo.data.SimpleStore
21777 * @extends Roo.data.Store
21778 * Small helper class to make creating Stores from Array data easier.
21779 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21780 * @cfg {Array} fields An array of field definition objects, or field name strings.
21781 * @cfg {Array} data The multi-dimensional array of data
21783 * @param {Object} config
21785 Roo.data.SimpleStore = function(config){
21786 Roo.data.SimpleStore.superclass.constructor.call(this, {
21788 reader: new Roo.data.ArrayReader({
21791 Roo.data.Record.create(config.fields)
21793 proxy : new Roo.data.MemoryProxy(config.data)
21797 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21799 * Ext JS Library 1.1.1
21800 * Copyright(c) 2006-2007, Ext JS, LLC.
21802 * Originally Released Under LGPL - original licence link has changed is not relivant.
21805 * <script type="text/javascript">
21810 * @extends Roo.data.Store
21811 * @class Roo.data.JsonStore
21812 * Small helper class to make creating Stores for JSON data easier. <br/>
21814 var store = new Roo.data.JsonStore({
21815 url: 'get-images.php',
21817 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21820 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21821 * JsonReader and HttpProxy (unless inline data is provided).</b>
21822 * @cfg {Array} fields An array of field definition objects, or field name strings.
21824 * @param {Object} config
21826 Roo.data.JsonStore = function(c){
21827 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21828 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21829 reader: new Roo.data.JsonReader(c, c.fields)
21832 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21834 * Ext JS Library 1.1.1
21835 * Copyright(c) 2006-2007, Ext JS, LLC.
21837 * Originally Released Under LGPL - original licence link has changed is not relivant.
21840 * <script type="text/javascript">
21844 Roo.data.Field = function(config){
21845 if(typeof config == "string"){
21846 config = {name: config};
21848 Roo.apply(this, config);
21851 this.type = "auto";
21854 var st = Roo.data.SortTypes;
21855 // named sortTypes are supported, here we look them up
21856 if(typeof this.sortType == "string"){
21857 this.sortType = st[this.sortType];
21860 // set default sortType for strings and dates
21861 if(!this.sortType){
21864 this.sortType = st.asUCString;
21867 this.sortType = st.asDate;
21870 this.sortType = st.none;
21875 var stripRe = /[\$,%]/g;
21877 // prebuilt conversion function for this field, instead of
21878 // switching every time we're reading a value
21880 var cv, dateFormat = this.dateFormat;
21885 cv = function(v){ return v; };
21888 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
21892 return v !== undefined && v !== null && v !== '' ?
21893 parseInt(String(v).replace(stripRe, ""), 10) : '';
21898 return v !== undefined && v !== null && v !== '' ?
21899 parseFloat(String(v).replace(stripRe, ""), 10) : '';
21904 cv = function(v){ return v === true || v === "true" || v == 1; };
21911 if(v instanceof Date){
21915 if(dateFormat == "timestamp"){
21916 return new Date(v*1000);
21918 return Date.parseDate(v, dateFormat);
21920 var parsed = Date.parse(v);
21921 return parsed ? new Date(parsed) : null;
21930 Roo.data.Field.prototype = {
21938 * Ext JS Library 1.1.1
21939 * Copyright(c) 2006-2007, Ext JS, LLC.
21941 * Originally Released Under LGPL - original licence link has changed is not relivant.
21944 * <script type="text/javascript">
21947 // Base class for reading structured data from a data source. This class is intended to be
21948 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
21951 * @class Roo.data.DataReader
21952 * Base class for reading structured data from a data source. This class is intended to be
21953 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
21956 Roo.data.DataReader = function(meta, recordType){
21960 this.recordType = recordType instanceof Array ?
21961 Roo.data.Record.create(recordType) : recordType;
21964 Roo.data.DataReader.prototype = {
21966 * Create an empty record
21967 * @param {Object} data (optional) - overlay some values
21968 * @return {Roo.data.Record} record created.
21970 newRow : function(d) {
21972 this.recordType.prototype.fields.each(function(c) {
21974 case 'int' : da[c.name] = 0; break;
21975 case 'date' : da[c.name] = new Date(); break;
21976 case 'float' : da[c.name] = 0.0; break;
21977 case 'boolean' : da[c.name] = false; break;
21978 default : da[c.name] = ""; break;
21982 return new this.recordType(Roo.apply(da, d));
21987 * Ext JS Library 1.1.1
21988 * Copyright(c) 2006-2007, Ext JS, LLC.
21990 * Originally Released Under LGPL - original licence link has changed is not relivant.
21993 * <script type="text/javascript">
21997 * @class Roo.data.DataProxy
21998 * @extends Roo.data.Observable
21999 * This class is an abstract base class for implementations which provide retrieval of
22000 * unformatted data objects.<br>
22002 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22003 * (of the appropriate type which knows how to parse the data object) to provide a block of
22004 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22006 * Custom implementations must implement the load method as described in
22007 * {@link Roo.data.HttpProxy#load}.
22009 Roo.data.DataProxy = function(){
22012 * @event beforeload
22013 * Fires before a network request is made to retrieve a data object.
22014 * @param {Object} This DataProxy object.
22015 * @param {Object} params The params parameter to the load function.
22020 * Fires before the load method's callback is called.
22021 * @param {Object} This DataProxy object.
22022 * @param {Object} o The data object.
22023 * @param {Object} arg The callback argument object passed to the load function.
22027 * @event loadexception
22028 * Fires if an Exception occurs during data retrieval.
22029 * @param {Object} This DataProxy object.
22030 * @param {Object} o The data object.
22031 * @param {Object} arg The callback argument object passed to the load function.
22032 * @param {Object} e The Exception.
22034 loadexception : true
22036 Roo.data.DataProxy.superclass.constructor.call(this);
22039 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22042 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22046 * Ext JS Library 1.1.1
22047 * Copyright(c) 2006-2007, Ext JS, LLC.
22049 * Originally Released Under LGPL - original licence link has changed is not relivant.
22052 * <script type="text/javascript">
22055 * @class Roo.data.MemoryProxy
22056 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22057 * to the Reader when its load method is called.
22059 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22061 Roo.data.MemoryProxy = function(data){
22065 Roo.data.MemoryProxy.superclass.constructor.call(this);
22069 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22071 * Load data from the requested source (in this case an in-memory
22072 * data object passed to the constructor), read the data object into
22073 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22074 * process that block using the passed callback.
22075 * @param {Object} params This parameter is not used by the MemoryProxy class.
22076 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22077 * object into a block of Roo.data.Records.
22078 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22079 * The function must be passed <ul>
22080 * <li>The Record block object</li>
22081 * <li>The "arg" argument from the load function</li>
22082 * <li>A boolean success indicator</li>
22084 * @param {Object} scope The scope in which to call the callback
22085 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22087 load : function(params, reader, callback, scope, arg){
22088 params = params || {};
22091 result = reader.readRecords(this.data);
22093 this.fireEvent("loadexception", this, arg, null, e);
22094 callback.call(scope, null, arg, false);
22097 callback.call(scope, result, arg, true);
22101 update : function(params, records){
22106 * Ext JS Library 1.1.1
22107 * Copyright(c) 2006-2007, Ext JS, LLC.
22109 * Originally Released Under LGPL - original licence link has changed is not relivant.
22112 * <script type="text/javascript">
22115 * @class Roo.data.HttpProxy
22116 * @extends Roo.data.DataProxy
22117 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22118 * configured to reference a certain URL.<br><br>
22120 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22121 * from which the running page was served.<br><br>
22123 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22125 * Be aware that to enable the browser to parse an XML document, the server must set
22126 * the Content-Type header in the HTTP response to "text/xml".
22128 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22129 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22130 * will be used to make the request.
22132 Roo.data.HttpProxy = function(conn){
22133 Roo.data.HttpProxy.superclass.constructor.call(this);
22134 // is conn a conn config or a real conn?
22136 this.useAjax = !conn || !conn.events;
22140 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22141 // thse are take from connection...
22144 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22147 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22148 * extra parameters to each request made by this object. (defaults to undefined)
22151 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22152 * to each request made by this object. (defaults to undefined)
22155 * @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)
22158 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22161 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22167 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22171 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22172 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22173 * a finer-grained basis than the DataProxy events.
22175 getConnection : function(){
22176 return this.useAjax ? Roo.Ajax : this.conn;
22180 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22181 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22182 * process that block using the passed callback.
22183 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22184 * for the request to the remote server.
22185 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22186 * object into a block of Roo.data.Records.
22187 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22188 * The function must be passed <ul>
22189 * <li>The Record block object</li>
22190 * <li>The "arg" argument from the load function</li>
22191 * <li>A boolean success indicator</li>
22193 * @param {Object} scope The scope in which to call the callback
22194 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22196 load : function(params, reader, callback, scope, arg){
22197 if(this.fireEvent("beforeload", this, params) !== false){
22199 params : params || {},
22201 callback : callback,
22206 callback : this.loadResponse,
22210 Roo.applyIf(o, this.conn);
22211 if(this.activeRequest){
22212 Roo.Ajax.abort(this.activeRequest);
22214 this.activeRequest = Roo.Ajax.request(o);
22216 this.conn.request(o);
22219 callback.call(scope||this, null, arg, false);
22224 loadResponse : function(o, success, response){
22225 delete this.activeRequest;
22227 this.fireEvent("loadexception", this, o, response);
22228 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22233 result = o.reader.read(response);
22235 this.fireEvent("loadexception", this, o, response, e);
22236 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22240 this.fireEvent("load", this, o, o.request.arg);
22241 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22245 update : function(dataSet){
22250 updateResponse : function(dataSet){
22255 * Ext JS Library 1.1.1
22256 * Copyright(c) 2006-2007, Ext JS, LLC.
22258 * Originally Released Under LGPL - original licence link has changed is not relivant.
22261 * <script type="text/javascript">
22265 * @class Roo.data.ScriptTagProxy
22266 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22267 * other than the originating domain of the running page.<br><br>
22269 * <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
22270 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22272 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22273 * source code that is used as the source inside a <script> tag.<br><br>
22275 * In order for the browser to process the returned data, the server must wrap the data object
22276 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22277 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22278 * depending on whether the callback name was passed:
22281 boolean scriptTag = false;
22282 String cb = request.getParameter("callback");
22285 response.setContentType("text/javascript");
22287 response.setContentType("application/x-json");
22289 Writer out = response.getWriter();
22291 out.write(cb + "(");
22293 out.print(dataBlock.toJsonString());
22300 * @param {Object} config A configuration object.
22302 Roo.data.ScriptTagProxy = function(config){
22303 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22304 Roo.apply(this, config);
22305 this.head = document.getElementsByTagName("head")[0];
22308 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22310 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22312 * @cfg {String} url The URL from which to request the data object.
22315 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22319 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22320 * the server the name of the callback function set up by the load call to process the returned data object.
22321 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22322 * javascript output which calls this named function passing the data object as its only parameter.
22324 callbackParam : "callback",
22326 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22327 * name to the request.
22332 * Load data from the configured URL, read the data object into
22333 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22334 * process that block using the passed callback.
22335 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22336 * for the request to the remote server.
22337 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22338 * object into a block of Roo.data.Records.
22339 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22340 * The function must be passed <ul>
22341 * <li>The Record block object</li>
22342 * <li>The "arg" argument from the load function</li>
22343 * <li>A boolean success indicator</li>
22345 * @param {Object} scope The scope in which to call the callback
22346 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22348 load : function(params, reader, callback, scope, arg){
22349 if(this.fireEvent("beforeload", this, params) !== false){
22351 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22353 var url = this.url;
22354 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22356 url += "&_dc=" + (new Date().getTime());
22358 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22361 cb : "stcCallback"+transId,
22362 scriptId : "stcScript"+transId,
22366 callback : callback,
22372 window[trans.cb] = function(o){
22373 conn.handleResponse(o, trans);
22376 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22378 if(this.autoAbort !== false){
22382 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22384 var script = document.createElement("script");
22385 script.setAttribute("src", url);
22386 script.setAttribute("type", "text/javascript");
22387 script.setAttribute("id", trans.scriptId);
22388 this.head.appendChild(script);
22390 this.trans = trans;
22392 callback.call(scope||this, null, arg, false);
22397 isLoading : function(){
22398 return this.trans ? true : false;
22402 * Abort the current server request.
22404 abort : function(){
22405 if(this.isLoading()){
22406 this.destroyTrans(this.trans);
22411 destroyTrans : function(trans, isLoaded){
22412 this.head.removeChild(document.getElementById(trans.scriptId));
22413 clearTimeout(trans.timeoutId);
22415 window[trans.cb] = undefined;
22417 delete window[trans.cb];
22420 // if hasn't been loaded, wait for load to remove it to prevent script error
22421 window[trans.cb] = function(){
22422 window[trans.cb] = undefined;
22424 delete window[trans.cb];
22431 handleResponse : function(o, trans){
22432 this.trans = false;
22433 this.destroyTrans(trans, true);
22436 result = trans.reader.readRecords(o);
22438 this.fireEvent("loadexception", this, o, trans.arg, e);
22439 trans.callback.call(trans.scope||window, null, trans.arg, false);
22442 this.fireEvent("load", this, o, trans.arg);
22443 trans.callback.call(trans.scope||window, result, trans.arg, true);
22447 handleFailure : function(trans){
22448 this.trans = false;
22449 this.destroyTrans(trans, false);
22450 this.fireEvent("loadexception", this, null, trans.arg);
22451 trans.callback.call(trans.scope||window, null, trans.arg, false);
22455 * Ext JS Library 1.1.1
22456 * Copyright(c) 2006-2007, Ext JS, LLC.
22458 * Originally Released Under LGPL - original licence link has changed is not relivant.
22461 * <script type="text/javascript">
22465 * @class Roo.data.JsonReader
22466 * @extends Roo.data.DataReader
22467 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22468 * based on mappings in a provided Roo.data.Record constructor.
22470 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22471 * in the reply previously.
22476 var RecordDef = Roo.data.Record.create([
22477 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22478 {name: 'occupation'} // This field will use "occupation" as the mapping.
22480 var myReader = new Roo.data.JsonReader({
22481 totalProperty: "results", // The property which contains the total dataset size (optional)
22482 root: "rows", // The property which contains an Array of row objects
22483 id: "id" // The property within each row object that provides an ID for the record (optional)
22487 * This would consume a JSON file like this:
22489 { 'results': 2, 'rows': [
22490 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22491 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22494 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22495 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22496 * paged from the remote server.
22497 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22498 * @cfg {String} root name of the property which contains the Array of row objects.
22499 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22501 * Create a new JsonReader
22502 * @param {Object} meta Metadata configuration options
22503 * @param {Object} recordType Either an Array of field definition objects,
22504 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22506 Roo.data.JsonReader = function(meta, recordType){
22509 // set some defaults:
22510 Roo.applyIf(meta, {
22511 totalProperty: 'total',
22512 successProperty : 'success',
22517 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22519 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22522 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22523 * Used by Store query builder to append _requestMeta to params.
22526 metaFromRemote : false,
22528 * This method is only used by a DataProxy which has retrieved data from a remote server.
22529 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22530 * @return {Object} data A data block which is used by an Roo.data.Store object as
22531 * a cache of Roo.data.Records.
22533 read : function(response){
22534 var json = response.responseText;
22536 var o = /* eval:var:o */ eval("("+json+")");
22538 throw {message: "JsonReader.read: Json object not found"};
22544 this.metaFromRemote = true;
22545 this.meta = o.metaData;
22546 this.recordType = Roo.data.Record.create(o.metaData.fields);
22547 this.onMetaChange(this.meta, this.recordType, o);
22549 return this.readRecords(o);
22552 // private function a store will implement
22553 onMetaChange : function(meta, recordType, o){
22560 simpleAccess: function(obj, subsc) {
22567 getJsonAccessor: function(){
22569 return function(expr) {
22571 return(re.test(expr))
22572 ? new Function("obj", "return obj." + expr)
22577 return Roo.emptyFn;
22582 * Create a data block containing Roo.data.Records from an XML document.
22583 * @param {Object} o An object which contains an Array of row objects in the property specified
22584 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22585 * which contains the total size of the dataset.
22586 * @return {Object} data A data block which is used by an Roo.data.Store object as
22587 * a cache of Roo.data.Records.
22589 readRecords : function(o){
22591 * After any data loads, the raw JSON data is available for further custom processing.
22595 var s = this.meta, Record = this.recordType,
22596 f = Record.prototype.fields, fi = f.items, fl = f.length;
22598 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22600 if(s.totalProperty) {
22601 this.getTotal = this.getJsonAccessor(s.totalProperty);
22603 if(s.successProperty) {
22604 this.getSuccess = this.getJsonAccessor(s.successProperty);
22606 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22608 var g = this.getJsonAccessor(s.id);
22609 this.getId = function(rec) {
22611 return (r === undefined || r === "") ? null : r;
22614 this.getId = function(){return null;};
22617 for(var jj = 0; jj < fl; jj++){
22619 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22620 this.ef[jj] = this.getJsonAccessor(map);
22624 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22625 if(s.totalProperty){
22626 var vt = parseInt(this.getTotal(o), 10);
22631 if(s.successProperty){
22632 var vs = this.getSuccess(o);
22633 if(vs === false || vs === 'false'){
22638 for(var i = 0; i < c; i++){
22641 var id = this.getId(n);
22642 for(var j = 0; j < fl; j++){
22644 var v = this.ef[j](n);
22646 Roo.log('missing convert for ' + f.name);
22650 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22652 var record = new Record(values, id);
22654 records[i] = record;
22660 totalRecords : totalRecords
22665 * Ext JS Library 1.1.1
22666 * Copyright(c) 2006-2007, Ext JS, LLC.
22668 * Originally Released Under LGPL - original licence link has changed is not relivant.
22671 * <script type="text/javascript">
22675 * @class Roo.data.XmlReader
22676 * @extends Roo.data.DataReader
22677 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22678 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22680 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22681 * header in the HTTP response must be set to "text/xml".</em>
22685 var RecordDef = Roo.data.Record.create([
22686 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22687 {name: 'occupation'} // This field will use "occupation" as the mapping.
22689 var myReader = new Roo.data.XmlReader({
22690 totalRecords: "results", // The element which contains the total dataset size (optional)
22691 record: "row", // The repeated element which contains row information
22692 id: "id" // The element within the row that provides an ID for the record (optional)
22696 * This would consume an XML file like this:
22700 <results>2</results>
22703 <name>Bill</name>
22704 <occupation>Gardener</occupation>
22708 <name>Ben</name>
22709 <occupation>Horticulturalist</occupation>
22713 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22714 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22715 * paged from the remote server.
22716 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22717 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22718 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22719 * a record identifier value.
22721 * Create a new XmlReader
22722 * @param {Object} meta Metadata configuration options
22723 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22724 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22725 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22727 Roo.data.XmlReader = function(meta, recordType){
22729 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22731 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22733 * This method is only used by a DataProxy which has retrieved data from a remote server.
22734 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22735 * to contain a method called 'responseXML' that returns an XML document object.
22736 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22737 * a cache of Roo.data.Records.
22739 read : function(response){
22740 var doc = response.responseXML;
22742 throw {message: "XmlReader.read: XML Document not available"};
22744 return this.readRecords(doc);
22748 * Create a data block containing Roo.data.Records from an XML document.
22749 * @param {Object} doc A parsed XML document.
22750 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22751 * a cache of Roo.data.Records.
22753 readRecords : function(doc){
22755 * After any data loads/reads, the raw XML Document is available for further custom processing.
22756 * @type XMLDocument
22758 this.xmlData = doc;
22759 var root = doc.documentElement || doc;
22760 var q = Roo.DomQuery;
22761 var recordType = this.recordType, fields = recordType.prototype.fields;
22762 var sid = this.meta.id;
22763 var totalRecords = 0, success = true;
22764 if(this.meta.totalRecords){
22765 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22768 if(this.meta.success){
22769 var sv = q.selectValue(this.meta.success, root, true);
22770 success = sv !== false && sv !== 'false';
22773 var ns = q.select(this.meta.record, root);
22774 for(var i = 0, len = ns.length; i < len; i++) {
22777 var id = sid ? q.selectValue(sid, n) : undefined;
22778 for(var j = 0, jlen = fields.length; j < jlen; j++){
22779 var f = fields.items[j];
22780 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22782 values[f.name] = v;
22784 var record = new recordType(values, id);
22786 records[records.length] = record;
22792 totalRecords : totalRecords || records.length
22797 * Ext JS Library 1.1.1
22798 * Copyright(c) 2006-2007, Ext JS, LLC.
22800 * Originally Released Under LGPL - original licence link has changed is not relivant.
22803 * <script type="text/javascript">
22807 * @class Roo.data.ArrayReader
22808 * @extends Roo.data.DataReader
22809 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22810 * Each element of that Array represents a row of data fields. The
22811 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22812 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22816 var RecordDef = Roo.data.Record.create([
22817 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22818 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22820 var myReader = new Roo.data.ArrayReader({
22821 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22825 * This would consume an Array like this:
22827 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22829 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22831 * Create a new JsonReader
22832 * @param {Object} meta Metadata configuration options.
22833 * @param {Object} recordType Either an Array of field definition objects
22834 * as specified to {@link Roo.data.Record#create},
22835 * or an {@link Roo.data.Record} object
22836 * created using {@link Roo.data.Record#create}.
22838 Roo.data.ArrayReader = function(meta, recordType){
22839 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22842 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22844 * Create a data block containing Roo.data.Records from an XML document.
22845 * @param {Object} o An Array of row objects which represents the dataset.
22846 * @return {Object} data A data block which is used by an Roo.data.Store object as
22847 * a cache of Roo.data.Records.
22849 readRecords : function(o){
22850 var sid = this.meta ? this.meta.id : null;
22851 var recordType = this.recordType, fields = recordType.prototype.fields;
22854 for(var i = 0; i < root.length; i++){
22857 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22858 for(var j = 0, jlen = fields.length; j < jlen; j++){
22859 var f = fields.items[j];
22860 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22861 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22863 values[f.name] = v;
22865 var record = new recordType(values, id);
22867 records[records.length] = record;
22871 totalRecords : records.length
22876 * Ext JS Library 1.1.1
22877 * Copyright(c) 2006-2007, Ext JS, LLC.
22879 * Originally Released Under LGPL - original licence link has changed is not relivant.
22882 * <script type="text/javascript">
22887 * @class Roo.data.Tree
22888 * @extends Roo.util.Observable
22889 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
22890 * in the tree have most standard DOM functionality.
22892 * @param {Node} root (optional) The root node
22894 Roo.data.Tree = function(root){
22895 this.nodeHash = {};
22897 * The root node for this tree
22902 this.setRootNode(root);
22907 * Fires when a new child node is appended to a node in this tree.
22908 * @param {Tree} tree The owner tree
22909 * @param {Node} parent The parent node
22910 * @param {Node} node The newly appended node
22911 * @param {Number} index The index of the newly appended node
22916 * Fires when a child node is removed from a node in this tree.
22917 * @param {Tree} tree The owner tree
22918 * @param {Node} parent The parent node
22919 * @param {Node} node The child node removed
22924 * Fires when a node is moved to a new location in the tree
22925 * @param {Tree} tree The owner tree
22926 * @param {Node} node The node moved
22927 * @param {Node} oldParent The old parent of this node
22928 * @param {Node} newParent The new parent of this node
22929 * @param {Number} index The index it was moved to
22934 * Fires when a new child node is inserted in a node in this tree.
22935 * @param {Tree} tree The owner tree
22936 * @param {Node} parent The parent node
22937 * @param {Node} node The child node inserted
22938 * @param {Node} refNode The child node the node was inserted before
22942 * @event beforeappend
22943 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
22944 * @param {Tree} tree The owner tree
22945 * @param {Node} parent The parent node
22946 * @param {Node} node The child node to be appended
22948 "beforeappend" : true,
22950 * @event beforeremove
22951 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
22952 * @param {Tree} tree The owner tree
22953 * @param {Node} parent The parent node
22954 * @param {Node} node The child node to be removed
22956 "beforeremove" : true,
22958 * @event beforemove
22959 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
22960 * @param {Tree} tree The owner tree
22961 * @param {Node} node The node being moved
22962 * @param {Node} oldParent The parent of the node
22963 * @param {Node} newParent The new parent the node is moving to
22964 * @param {Number} index The index it is being moved to
22966 "beforemove" : true,
22968 * @event beforeinsert
22969 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
22970 * @param {Tree} tree The owner tree
22971 * @param {Node} parent The parent node
22972 * @param {Node} node The child node to be inserted
22973 * @param {Node} refNode The child node the node is being inserted before
22975 "beforeinsert" : true
22978 Roo.data.Tree.superclass.constructor.call(this);
22981 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
22982 pathSeparator: "/",
22984 proxyNodeEvent : function(){
22985 return this.fireEvent.apply(this, arguments);
22989 * Returns the root node for this tree.
22992 getRootNode : function(){
22997 * Sets the root node for this tree.
22998 * @param {Node} node
23001 setRootNode : function(node){
23003 node.ownerTree = this;
23004 node.isRoot = true;
23005 this.registerNode(node);
23010 * Gets a node in this tree by its id.
23011 * @param {String} id
23014 getNodeById : function(id){
23015 return this.nodeHash[id];
23018 registerNode : function(node){
23019 this.nodeHash[node.id] = node;
23022 unregisterNode : function(node){
23023 delete this.nodeHash[node.id];
23026 toString : function(){
23027 return "[Tree"+(this.id?" "+this.id:"")+"]";
23032 * @class Roo.data.Node
23033 * @extends Roo.util.Observable
23034 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23035 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23037 * @param {Object} attributes The attributes/config for the node
23039 Roo.data.Node = function(attributes){
23041 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23044 this.attributes = attributes || {};
23045 this.leaf = this.attributes.leaf;
23047 * The node id. @type String
23049 this.id = this.attributes.id;
23051 this.id = Roo.id(null, "ynode-");
23052 this.attributes.id = this.id;
23057 * All child nodes of this node. @type Array
23059 this.childNodes = [];
23060 if(!this.childNodes.indexOf){ // indexOf is a must
23061 this.childNodes.indexOf = function(o){
23062 for(var i = 0, len = this.length; i < len; i++){
23071 * The parent node for this node. @type Node
23073 this.parentNode = null;
23075 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23077 this.firstChild = null;
23079 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23081 this.lastChild = null;
23083 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23085 this.previousSibling = null;
23087 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23089 this.nextSibling = null;
23094 * Fires when a new child node is appended
23095 * @param {Tree} tree The owner tree
23096 * @param {Node} this This node
23097 * @param {Node} node The newly appended node
23098 * @param {Number} index The index of the newly appended node
23103 * Fires when a child node is removed
23104 * @param {Tree} tree The owner tree
23105 * @param {Node} this This node
23106 * @param {Node} node The removed node
23111 * Fires when this node is moved to a new location in the tree
23112 * @param {Tree} tree The owner tree
23113 * @param {Node} this This node
23114 * @param {Node} oldParent The old parent of this node
23115 * @param {Node} newParent The new parent of this node
23116 * @param {Number} index The index it was moved to
23121 * Fires when a new child node is inserted.
23122 * @param {Tree} tree The owner tree
23123 * @param {Node} this This node
23124 * @param {Node} node The child node inserted
23125 * @param {Node} refNode The child node the node was inserted before
23129 * @event beforeappend
23130 * Fires before a new child is appended, return false to cancel the append.
23131 * @param {Tree} tree The owner tree
23132 * @param {Node} this This node
23133 * @param {Node} node The child node to be appended
23135 "beforeappend" : true,
23137 * @event beforeremove
23138 * Fires before a child is removed, return false to cancel the remove.
23139 * @param {Tree} tree The owner tree
23140 * @param {Node} this This node
23141 * @param {Node} node The child node to be removed
23143 "beforeremove" : true,
23145 * @event beforemove
23146 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23147 * @param {Tree} tree The owner tree
23148 * @param {Node} this This node
23149 * @param {Node} oldParent The parent of this node
23150 * @param {Node} newParent The new parent this node is moving to
23151 * @param {Number} index The index it is being moved to
23153 "beforemove" : true,
23155 * @event beforeinsert
23156 * Fires before a new child is inserted, return false to cancel the insert.
23157 * @param {Tree} tree The owner tree
23158 * @param {Node} this This node
23159 * @param {Node} node The child node to be inserted
23160 * @param {Node} refNode The child node the node is being inserted before
23162 "beforeinsert" : true
23164 this.listeners = this.attributes.listeners;
23165 Roo.data.Node.superclass.constructor.call(this);
23168 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23169 fireEvent : function(evtName){
23170 // first do standard event for this node
23171 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23174 // then bubble it up to the tree if the event wasn't cancelled
23175 var ot = this.getOwnerTree();
23177 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23185 * Returns true if this node is a leaf
23186 * @return {Boolean}
23188 isLeaf : function(){
23189 return this.leaf === true;
23193 setFirstChild : function(node){
23194 this.firstChild = node;
23198 setLastChild : function(node){
23199 this.lastChild = node;
23204 * Returns true if this node is the last child of its parent
23205 * @return {Boolean}
23207 isLast : function(){
23208 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23212 * Returns true if this node is the first child of its parent
23213 * @return {Boolean}
23215 isFirst : function(){
23216 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23219 hasChildNodes : function(){
23220 return !this.isLeaf() && this.childNodes.length > 0;
23224 * Insert node(s) as the last child node of this node.
23225 * @param {Node/Array} node The node or Array of nodes to append
23226 * @return {Node} The appended node if single append, or null if an array was passed
23228 appendChild : function(node){
23230 if(node instanceof Array){
23232 }else if(arguments.length > 1){
23235 // if passed an array or multiple args do them one by one
23237 for(var i = 0, len = multi.length; i < len; i++) {
23238 this.appendChild(multi[i]);
23241 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23244 var index = this.childNodes.length;
23245 var oldParent = node.parentNode;
23246 // it's a move, make sure we move it cleanly
23248 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23251 oldParent.removeChild(node);
23253 index = this.childNodes.length;
23255 this.setFirstChild(node);
23257 this.childNodes.push(node);
23258 node.parentNode = this;
23259 var ps = this.childNodes[index-1];
23261 node.previousSibling = ps;
23262 ps.nextSibling = node;
23264 node.previousSibling = null;
23266 node.nextSibling = null;
23267 this.setLastChild(node);
23268 node.setOwnerTree(this.getOwnerTree());
23269 this.fireEvent("append", this.ownerTree, this, node, index);
23271 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23278 * Removes a child node from this node.
23279 * @param {Node} node The node to remove
23280 * @return {Node} The removed node
23282 removeChild : function(node){
23283 var index = this.childNodes.indexOf(node);
23287 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23291 // remove it from childNodes collection
23292 this.childNodes.splice(index, 1);
23295 if(node.previousSibling){
23296 node.previousSibling.nextSibling = node.nextSibling;
23298 if(node.nextSibling){
23299 node.nextSibling.previousSibling = node.previousSibling;
23302 // update child refs
23303 if(this.firstChild == node){
23304 this.setFirstChild(node.nextSibling);
23306 if(this.lastChild == node){
23307 this.setLastChild(node.previousSibling);
23310 node.setOwnerTree(null);
23311 // clear any references from the node
23312 node.parentNode = null;
23313 node.previousSibling = null;
23314 node.nextSibling = null;
23315 this.fireEvent("remove", this.ownerTree, this, node);
23320 * Inserts the first node before the second node in this nodes childNodes collection.
23321 * @param {Node} node The node to insert
23322 * @param {Node} refNode The node to insert before (if null the node is appended)
23323 * @return {Node} The inserted node
23325 insertBefore : function(node, refNode){
23326 if(!refNode){ // like standard Dom, refNode can be null for append
23327 return this.appendChild(node);
23330 if(node == refNode){
23334 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23337 var index = this.childNodes.indexOf(refNode);
23338 var oldParent = node.parentNode;
23339 var refIndex = index;
23341 // when moving internally, indexes will change after remove
23342 if(oldParent == this && this.childNodes.indexOf(node) < index){
23346 // it's a move, make sure we move it cleanly
23348 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23351 oldParent.removeChild(node);
23354 this.setFirstChild(node);
23356 this.childNodes.splice(refIndex, 0, node);
23357 node.parentNode = this;
23358 var ps = this.childNodes[refIndex-1];
23360 node.previousSibling = ps;
23361 ps.nextSibling = node;
23363 node.previousSibling = null;
23365 node.nextSibling = refNode;
23366 refNode.previousSibling = node;
23367 node.setOwnerTree(this.getOwnerTree());
23368 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23370 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23376 * Returns the child node at the specified index.
23377 * @param {Number} index
23380 item : function(index){
23381 return this.childNodes[index];
23385 * Replaces one child node in this node with another.
23386 * @param {Node} newChild The replacement node
23387 * @param {Node} oldChild The node to replace
23388 * @return {Node} The replaced node
23390 replaceChild : function(newChild, oldChild){
23391 this.insertBefore(newChild, oldChild);
23392 this.removeChild(oldChild);
23397 * Returns the index of a child node
23398 * @param {Node} node
23399 * @return {Number} The index of the node or -1 if it was not found
23401 indexOf : function(child){
23402 return this.childNodes.indexOf(child);
23406 * Returns the tree this node is in.
23409 getOwnerTree : function(){
23410 // if it doesn't have one, look for one
23411 if(!this.ownerTree){
23415 this.ownerTree = p.ownerTree;
23421 return this.ownerTree;
23425 * Returns depth of this node (the root node has a depth of 0)
23428 getDepth : function(){
23431 while(p.parentNode){
23439 setOwnerTree : function(tree){
23440 // if it's move, we need to update everyone
23441 if(tree != this.ownerTree){
23442 if(this.ownerTree){
23443 this.ownerTree.unregisterNode(this);
23445 this.ownerTree = tree;
23446 var cs = this.childNodes;
23447 for(var i = 0, len = cs.length; i < len; i++) {
23448 cs[i].setOwnerTree(tree);
23451 tree.registerNode(this);
23457 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23458 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23459 * @return {String} The path
23461 getPath : function(attr){
23462 attr = attr || "id";
23463 var p = this.parentNode;
23464 var b = [this.attributes[attr]];
23466 b.unshift(p.attributes[attr]);
23469 var sep = this.getOwnerTree().pathSeparator;
23470 return sep + b.join(sep);
23474 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23475 * function call will be the scope provided or the current node. The arguments to the function
23476 * will be the args provided or the current node. If the function returns false at any point,
23477 * the bubble is stopped.
23478 * @param {Function} fn The function to call
23479 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23480 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23482 bubble : function(fn, scope, args){
23485 if(fn.call(scope || p, args || p) === false){
23493 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23494 * function call will be the scope provided or the current node. The arguments to the function
23495 * will be the args provided or the current node. If the function returns false at any point,
23496 * the cascade is stopped on that branch.
23497 * @param {Function} fn The function to call
23498 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23499 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23501 cascade : function(fn, scope, args){
23502 if(fn.call(scope || this, args || this) !== false){
23503 var cs = this.childNodes;
23504 for(var i = 0, len = cs.length; i < len; i++) {
23505 cs[i].cascade(fn, scope, args);
23511 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23512 * function call will be the scope provided or the current node. The arguments to the function
23513 * will be the args provided or the current node. If the function returns false at any point,
23514 * the iteration stops.
23515 * @param {Function} fn The function to call
23516 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23517 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23519 eachChild : function(fn, scope, args){
23520 var cs = this.childNodes;
23521 for(var i = 0, len = cs.length; i < len; i++) {
23522 if(fn.call(scope || this, args || cs[i]) === false){
23529 * Finds the first child that has the attribute with the specified value.
23530 * @param {String} attribute The attribute name
23531 * @param {Mixed} value The value to search for
23532 * @return {Node} The found child or null if none was found
23534 findChild : function(attribute, value){
23535 var cs = this.childNodes;
23536 for(var i = 0, len = cs.length; i < len; i++) {
23537 if(cs[i].attributes[attribute] == value){
23545 * Finds the first child by a custom function. The child matches if the function passed
23547 * @param {Function} fn
23548 * @param {Object} scope (optional)
23549 * @return {Node} The found child or null if none was found
23551 findChildBy : function(fn, scope){
23552 var cs = this.childNodes;
23553 for(var i = 0, len = cs.length; i < len; i++) {
23554 if(fn.call(scope||cs[i], cs[i]) === true){
23562 * Sorts this nodes children using the supplied sort function
23563 * @param {Function} fn
23564 * @param {Object} scope (optional)
23566 sort : function(fn, scope){
23567 var cs = this.childNodes;
23568 var len = cs.length;
23570 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23572 for(var i = 0; i < len; i++){
23574 n.previousSibling = cs[i-1];
23575 n.nextSibling = cs[i+1];
23577 this.setFirstChild(n);
23580 this.setLastChild(n);
23587 * Returns true if this node is an ancestor (at any point) of the passed node.
23588 * @param {Node} node
23589 * @return {Boolean}
23591 contains : function(node){
23592 return node.isAncestor(this);
23596 * Returns true if the passed node is an ancestor (at any point) of this node.
23597 * @param {Node} node
23598 * @return {Boolean}
23600 isAncestor : function(node){
23601 var p = this.parentNode;
23611 toString : function(){
23612 return "[Node"+(this.id?" "+this.id:"")+"]";
23616 * Ext JS Library 1.1.1
23617 * Copyright(c) 2006-2007, Ext JS, LLC.
23619 * Originally Released Under LGPL - original licence link has changed is not relivant.
23622 * <script type="text/javascript">
23627 * @extends Roo.Element
23628 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23629 * automatic maintaining of shadow/shim positions.
23630 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23631 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23632 * you can pass a string with a CSS class name. False turns off the shadow.
23633 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23634 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23635 * @cfg {String} cls CSS class to add to the element
23636 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23637 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23639 * @param {Object} config An object with config options.
23640 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23643 Roo.Layer = function(config, existingEl){
23644 config = config || {};
23645 var dh = Roo.DomHelper;
23646 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23648 this.dom = Roo.getDom(existingEl);
23651 var o = config.dh || {tag: "div", cls: "x-layer"};
23652 this.dom = dh.append(pel, o);
23655 this.addClass(config.cls);
23657 this.constrain = config.constrain !== false;
23658 this.visibilityMode = Roo.Element.VISIBILITY;
23660 this.id = this.dom.id = config.id;
23662 this.id = Roo.id(this.dom);
23664 this.zindex = config.zindex || this.getZIndex();
23665 this.position("absolute", this.zindex);
23667 this.shadowOffset = config.shadowOffset || 4;
23668 this.shadow = new Roo.Shadow({
23669 offset : this.shadowOffset,
23670 mode : config.shadow
23673 this.shadowOffset = 0;
23675 this.useShim = config.shim !== false && Roo.useShims;
23676 this.useDisplay = config.useDisplay;
23680 var supr = Roo.Element.prototype;
23682 // shims are shared among layer to keep from having 100 iframes
23685 Roo.extend(Roo.Layer, Roo.Element, {
23687 getZIndex : function(){
23688 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23691 getShim : function(){
23698 var shim = shims.shift();
23700 shim = this.createShim();
23701 shim.enableDisplayMode('block');
23702 shim.dom.style.display = 'none';
23703 shim.dom.style.visibility = 'visible';
23705 var pn = this.dom.parentNode;
23706 if(shim.dom.parentNode != pn){
23707 pn.insertBefore(shim.dom, this.dom);
23709 shim.setStyle('z-index', this.getZIndex()-2);
23714 hideShim : function(){
23716 this.shim.setDisplayed(false);
23717 shims.push(this.shim);
23722 disableShadow : function(){
23724 this.shadowDisabled = true;
23725 this.shadow.hide();
23726 this.lastShadowOffset = this.shadowOffset;
23727 this.shadowOffset = 0;
23731 enableShadow : function(show){
23733 this.shadowDisabled = false;
23734 this.shadowOffset = this.lastShadowOffset;
23735 delete this.lastShadowOffset;
23743 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23744 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23745 sync : function(doShow){
23746 var sw = this.shadow;
23747 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23748 var sh = this.getShim();
23750 var w = this.getWidth(),
23751 h = this.getHeight();
23753 var l = this.getLeft(true),
23754 t = this.getTop(true);
23756 if(sw && !this.shadowDisabled){
23757 if(doShow && !sw.isVisible()){
23760 sw.realign(l, t, w, h);
23766 // fit the shim behind the shadow, so it is shimmed too
23767 var a = sw.adjusts, s = sh.dom.style;
23768 s.left = (Math.min(l, l+a.l))+"px";
23769 s.top = (Math.min(t, t+a.t))+"px";
23770 s.width = (w+a.w)+"px";
23771 s.height = (h+a.h)+"px";
23778 sh.setLeftTop(l, t);
23785 destroy : function(){
23788 this.shadow.hide();
23790 this.removeAllListeners();
23791 var pn = this.dom.parentNode;
23793 pn.removeChild(this.dom);
23795 Roo.Element.uncache(this.id);
23798 remove : function(){
23803 beginUpdate : function(){
23804 this.updating = true;
23808 endUpdate : function(){
23809 this.updating = false;
23814 hideUnders : function(negOffset){
23816 this.shadow.hide();
23822 constrainXY : function(){
23823 if(this.constrain){
23824 var vw = Roo.lib.Dom.getViewWidth(),
23825 vh = Roo.lib.Dom.getViewHeight();
23826 var s = Roo.get(document).getScroll();
23828 var xy = this.getXY();
23829 var x = xy[0], y = xy[1];
23830 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23831 // only move it if it needs it
23833 // first validate right/bottom
23834 if((x + w) > vw+s.left){
23835 x = vw - w - this.shadowOffset;
23838 if((y + h) > vh+s.top){
23839 y = vh - h - this.shadowOffset;
23842 // then make sure top/left isn't negative
23853 var ay = this.avoidY;
23854 if(y <= ay && (y+h) >= ay){
23860 supr.setXY.call(this, xy);
23866 isVisible : function(){
23867 return this.visible;
23871 showAction : function(){
23872 this.visible = true; // track visibility to prevent getStyle calls
23873 if(this.useDisplay === true){
23874 this.setDisplayed("");
23875 }else if(this.lastXY){
23876 supr.setXY.call(this, this.lastXY);
23877 }else if(this.lastLT){
23878 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
23883 hideAction : function(){
23884 this.visible = false;
23885 if(this.useDisplay === true){
23886 this.setDisplayed(false);
23888 this.setLeftTop(-10000,-10000);
23892 // overridden Element method
23893 setVisible : function(v, a, d, c, e){
23898 var cb = function(){
23903 }.createDelegate(this);
23904 supr.setVisible.call(this, true, true, d, cb, e);
23907 this.hideUnders(true);
23916 }.createDelegate(this);
23918 supr.setVisible.call(this, v, a, d, cb, e);
23927 storeXY : function(xy){
23928 delete this.lastLT;
23932 storeLeftTop : function(left, top){
23933 delete this.lastXY;
23934 this.lastLT = [left, top];
23938 beforeFx : function(){
23939 this.beforeAction();
23940 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
23944 afterFx : function(){
23945 Roo.Layer.superclass.afterFx.apply(this, arguments);
23946 this.sync(this.isVisible());
23950 beforeAction : function(){
23951 if(!this.updating && this.shadow){
23952 this.shadow.hide();
23956 // overridden Element method
23957 setLeft : function(left){
23958 this.storeLeftTop(left, this.getTop(true));
23959 supr.setLeft.apply(this, arguments);
23963 setTop : function(top){
23964 this.storeLeftTop(this.getLeft(true), top);
23965 supr.setTop.apply(this, arguments);
23969 setLeftTop : function(left, top){
23970 this.storeLeftTop(left, top);
23971 supr.setLeftTop.apply(this, arguments);
23975 setXY : function(xy, a, d, c, e){
23977 this.beforeAction();
23979 var cb = this.createCB(c);
23980 supr.setXY.call(this, xy, a, d, cb, e);
23987 createCB : function(c){
23998 // overridden Element method
23999 setX : function(x, a, d, c, e){
24000 this.setXY([x, this.getY()], a, d, c, e);
24003 // overridden Element method
24004 setY : function(y, a, d, c, e){
24005 this.setXY([this.getX(), y], a, d, c, e);
24008 // overridden Element method
24009 setSize : function(w, h, a, d, c, e){
24010 this.beforeAction();
24011 var cb = this.createCB(c);
24012 supr.setSize.call(this, w, h, a, d, cb, e);
24018 // overridden Element method
24019 setWidth : function(w, a, d, c, e){
24020 this.beforeAction();
24021 var cb = this.createCB(c);
24022 supr.setWidth.call(this, w, a, d, cb, e);
24028 // overridden Element method
24029 setHeight : function(h, a, d, c, e){
24030 this.beforeAction();
24031 var cb = this.createCB(c);
24032 supr.setHeight.call(this, h, a, d, cb, e);
24038 // overridden Element method
24039 setBounds : function(x, y, w, h, a, d, c, e){
24040 this.beforeAction();
24041 var cb = this.createCB(c);
24043 this.storeXY([x, y]);
24044 supr.setXY.call(this, [x, y]);
24045 supr.setSize.call(this, w, h, a, d, cb, e);
24048 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24054 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24055 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24056 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24057 * @param {Number} zindex The new z-index to set
24058 * @return {this} The Layer
24060 setZIndex : function(zindex){
24061 this.zindex = zindex;
24062 this.setStyle("z-index", zindex + 2);
24064 this.shadow.setZIndex(zindex + 1);
24067 this.shim.setStyle("z-index", zindex);
24073 * Ext JS Library 1.1.1
24074 * Copyright(c) 2006-2007, Ext JS, LLC.
24076 * Originally Released Under LGPL - original licence link has changed is not relivant.
24079 * <script type="text/javascript">
24084 * @class Roo.Shadow
24085 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24086 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24087 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24089 * Create a new Shadow
24090 * @param {Object} config The config object
24092 Roo.Shadow = function(config){
24093 Roo.apply(this, config);
24094 if(typeof this.mode != "string"){
24095 this.mode = this.defaultMode;
24097 var o = this.offset, a = {h: 0};
24098 var rad = Math.floor(this.offset/2);
24099 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24105 a.l -= this.offset + rad;
24106 a.t -= this.offset + rad;
24117 a.l -= (this.offset - rad);
24118 a.t -= this.offset + rad;
24120 a.w -= (this.offset - rad)*2;
24131 a.l -= (this.offset - rad);
24132 a.t -= (this.offset - rad);
24134 a.w -= (this.offset + rad + 1);
24135 a.h -= (this.offset + rad);
24144 Roo.Shadow.prototype = {
24146 * @cfg {String} mode
24147 * The shadow display mode. Supports the following options:<br />
24148 * sides: Shadow displays on both sides and bottom only<br />
24149 * frame: Shadow displays equally on all four sides<br />
24150 * drop: Traditional bottom-right drop shadow (default)
24153 * @cfg {String} offset
24154 * The number of pixels to offset the shadow from the element (defaults to 4)
24159 defaultMode: "drop",
24162 * Displays the shadow under the target element
24163 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24165 show : function(target){
24166 target = Roo.get(target);
24168 this.el = Roo.Shadow.Pool.pull();
24169 if(this.el.dom.nextSibling != target.dom){
24170 this.el.insertBefore(target);
24173 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24175 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24178 target.getLeft(true),
24179 target.getTop(true),
24183 this.el.dom.style.display = "block";
24187 * Returns true if the shadow is visible, else false
24189 isVisible : function(){
24190 return this.el ? true : false;
24194 * Direct alignment when values are already available. Show must be called at least once before
24195 * calling this method to ensure it is initialized.
24196 * @param {Number} left The target element left position
24197 * @param {Number} top The target element top position
24198 * @param {Number} width The target element width
24199 * @param {Number} height The target element height
24201 realign : function(l, t, w, h){
24205 var a = this.adjusts, d = this.el.dom, s = d.style;
24207 s.left = (l+a.l)+"px";
24208 s.top = (t+a.t)+"px";
24209 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24211 if(s.width != sws || s.height != shs){
24215 var cn = d.childNodes;
24216 var sww = Math.max(0, (sw-12))+"px";
24217 cn[0].childNodes[1].style.width = sww;
24218 cn[1].childNodes[1].style.width = sww;
24219 cn[2].childNodes[1].style.width = sww;
24220 cn[1].style.height = Math.max(0, (sh-12))+"px";
24226 * Hides this shadow
24230 this.el.dom.style.display = "none";
24231 Roo.Shadow.Pool.push(this.el);
24237 * Adjust the z-index of this shadow
24238 * @param {Number} zindex The new z-index
24240 setZIndex : function(z){
24243 this.el.setStyle("z-index", z);
24248 // Private utility class that manages the internal Shadow cache
24249 Roo.Shadow.Pool = function(){
24251 var markup = Roo.isIE ?
24252 '<div class="x-ie-shadow"></div>' :
24253 '<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>';
24256 var sh = p.shift();
24258 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24259 sh.autoBoxAdjust = false;
24264 push : function(sh){
24270 * Ext JS Library 1.1.1
24271 * Copyright(c) 2006-2007, Ext JS, LLC.
24273 * Originally Released Under LGPL - original licence link has changed is not relivant.
24276 * <script type="text/javascript">
24281 * @class Roo.SplitBar
24282 * @extends Roo.util.Observable
24283 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24287 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24288 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24289 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24290 split.minSize = 100;
24291 split.maxSize = 600;
24292 split.animate = true;
24293 split.on('moved', splitterMoved);
24296 * Create a new SplitBar
24297 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24298 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24299 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24300 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24301 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24302 position of the SplitBar).
24304 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24307 this.el = Roo.get(dragElement, true);
24308 this.el.dom.unselectable = "on";
24310 this.resizingEl = Roo.get(resizingElement, true);
24314 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24315 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24318 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24321 * The minimum size of the resizing element. (Defaults to 0)
24327 * The maximum size of the resizing element. (Defaults to 2000)
24330 this.maxSize = 2000;
24333 * Whether to animate the transition to the new size
24336 this.animate = false;
24339 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24342 this.useShim = false;
24347 if(!existingProxy){
24349 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24351 this.proxy = Roo.get(existingProxy).dom;
24354 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24357 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24360 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24363 this.dragSpecs = {};
24366 * @private The adapter to use to positon and resize elements
24368 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24369 this.adapter.init(this);
24371 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24373 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24374 this.el.addClass("x-splitbar-h");
24377 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24378 this.el.addClass("x-splitbar-v");
24384 * Fires when the splitter is moved (alias for {@link #event-moved})
24385 * @param {Roo.SplitBar} this
24386 * @param {Number} newSize the new width or height
24391 * Fires when the splitter is moved
24392 * @param {Roo.SplitBar} this
24393 * @param {Number} newSize the new width or height
24397 * @event beforeresize
24398 * Fires before the splitter is dragged
24399 * @param {Roo.SplitBar} this
24401 "beforeresize" : true,
24403 "beforeapply" : true
24406 Roo.util.Observable.call(this);
24409 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24410 onStartProxyDrag : function(x, y){
24411 this.fireEvent("beforeresize", this);
24413 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24415 o.enableDisplayMode("block");
24416 // all splitbars share the same overlay
24417 Roo.SplitBar.prototype.overlay = o;
24419 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24420 this.overlay.show();
24421 Roo.get(this.proxy).setDisplayed("block");
24422 var size = this.adapter.getElementSize(this);
24423 this.activeMinSize = this.getMinimumSize();;
24424 this.activeMaxSize = this.getMaximumSize();;
24425 var c1 = size - this.activeMinSize;
24426 var c2 = Math.max(this.activeMaxSize - size, 0);
24427 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24428 this.dd.resetConstraints();
24429 this.dd.setXConstraint(
24430 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24431 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24433 this.dd.setYConstraint(0, 0);
24435 this.dd.resetConstraints();
24436 this.dd.setXConstraint(0, 0);
24437 this.dd.setYConstraint(
24438 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24439 this.placement == Roo.SplitBar.TOP ? c2 : c1
24442 this.dragSpecs.startSize = size;
24443 this.dragSpecs.startPoint = [x, y];
24444 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24448 * @private Called after the drag operation by the DDProxy
24450 onEndProxyDrag : function(e){
24451 Roo.get(this.proxy).setDisplayed(false);
24452 var endPoint = Roo.lib.Event.getXY(e);
24454 this.overlay.hide();
24457 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24458 newSize = this.dragSpecs.startSize +
24459 (this.placement == Roo.SplitBar.LEFT ?
24460 endPoint[0] - this.dragSpecs.startPoint[0] :
24461 this.dragSpecs.startPoint[0] - endPoint[0]
24464 newSize = this.dragSpecs.startSize +
24465 (this.placement == Roo.SplitBar.TOP ?
24466 endPoint[1] - this.dragSpecs.startPoint[1] :
24467 this.dragSpecs.startPoint[1] - endPoint[1]
24470 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24471 if(newSize != this.dragSpecs.startSize){
24472 if(this.fireEvent('beforeapply', this, newSize) !== false){
24473 this.adapter.setElementSize(this, newSize);
24474 this.fireEvent("moved", this, newSize);
24475 this.fireEvent("resize", this, newSize);
24481 * Get the adapter this SplitBar uses
24482 * @return The adapter object
24484 getAdapter : function(){
24485 return this.adapter;
24489 * Set the adapter this SplitBar uses
24490 * @param {Object} adapter A SplitBar adapter object
24492 setAdapter : function(adapter){
24493 this.adapter = adapter;
24494 this.adapter.init(this);
24498 * Gets the minimum size for the resizing element
24499 * @return {Number} The minimum size
24501 getMinimumSize : function(){
24502 return this.minSize;
24506 * Sets the minimum size for the resizing element
24507 * @param {Number} minSize The minimum size
24509 setMinimumSize : function(minSize){
24510 this.minSize = minSize;
24514 * Gets the maximum size for the resizing element
24515 * @return {Number} The maximum size
24517 getMaximumSize : function(){
24518 return this.maxSize;
24522 * Sets the maximum size for the resizing element
24523 * @param {Number} maxSize The maximum size
24525 setMaximumSize : function(maxSize){
24526 this.maxSize = maxSize;
24530 * Sets the initialize size for the resizing element
24531 * @param {Number} size The initial size
24533 setCurrentSize : function(size){
24534 var oldAnimate = this.animate;
24535 this.animate = false;
24536 this.adapter.setElementSize(this, size);
24537 this.animate = oldAnimate;
24541 * Destroy this splitbar.
24542 * @param {Boolean} removeEl True to remove the element
24544 destroy : function(removeEl){
24546 this.shim.remove();
24549 this.proxy.parentNode.removeChild(this.proxy);
24557 * @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.
24559 Roo.SplitBar.createProxy = function(dir){
24560 var proxy = new Roo.Element(document.createElement("div"));
24561 proxy.unselectable();
24562 var cls = 'x-splitbar-proxy';
24563 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24564 document.body.appendChild(proxy.dom);
24569 * @class Roo.SplitBar.BasicLayoutAdapter
24570 * Default Adapter. It assumes the splitter and resizing element are not positioned
24571 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24573 Roo.SplitBar.BasicLayoutAdapter = function(){
24576 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24577 // do nothing for now
24578 init : function(s){
24582 * Called before drag operations to get the current size of the resizing element.
24583 * @param {Roo.SplitBar} s The SplitBar using this adapter
24585 getElementSize : function(s){
24586 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24587 return s.resizingEl.getWidth();
24589 return s.resizingEl.getHeight();
24594 * Called after drag operations to set the size of the resizing element.
24595 * @param {Roo.SplitBar} s The SplitBar using this adapter
24596 * @param {Number} newSize The new size to set
24597 * @param {Function} onComplete A function to be invoked when resizing is complete
24599 setElementSize : function(s, newSize, onComplete){
24600 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24602 s.resizingEl.setWidth(newSize);
24604 onComplete(s, newSize);
24607 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24612 s.resizingEl.setHeight(newSize);
24614 onComplete(s, newSize);
24617 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24624 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24625 * @extends Roo.SplitBar.BasicLayoutAdapter
24626 * Adapter that moves the splitter element to align with the resized sizing element.
24627 * Used with an absolute positioned SplitBar.
24628 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24629 * document.body, make sure you assign an id to the body element.
24631 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24632 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24633 this.container = Roo.get(container);
24636 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24637 init : function(s){
24638 this.basic.init(s);
24641 getElementSize : function(s){
24642 return this.basic.getElementSize(s);
24645 setElementSize : function(s, newSize, onComplete){
24646 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24649 moveSplitter : function(s){
24650 var yes = Roo.SplitBar;
24651 switch(s.placement){
24653 s.el.setX(s.resizingEl.getRight());
24656 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24659 s.el.setY(s.resizingEl.getBottom());
24662 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24669 * Orientation constant - Create a vertical SplitBar
24673 Roo.SplitBar.VERTICAL = 1;
24676 * Orientation constant - Create a horizontal SplitBar
24680 Roo.SplitBar.HORIZONTAL = 2;
24683 * Placement constant - The resizing element is to the left of the splitter element
24687 Roo.SplitBar.LEFT = 1;
24690 * Placement constant - The resizing element is to the right of the splitter element
24694 Roo.SplitBar.RIGHT = 2;
24697 * Placement constant - The resizing element is positioned above the splitter element
24701 Roo.SplitBar.TOP = 3;
24704 * Placement constant - The resizing element is positioned under splitter element
24708 Roo.SplitBar.BOTTOM = 4;
24711 * Ext JS Library 1.1.1
24712 * Copyright(c) 2006-2007, Ext JS, LLC.
24714 * Originally Released Under LGPL - original licence link has changed is not relivant.
24717 * <script type="text/javascript">
24722 * @extends Roo.util.Observable
24723 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24724 * This class also supports single and multi selection modes. <br>
24725 * Create a data model bound view:
24727 var store = new Roo.data.Store(...);
24729 var view = new Roo.View({
24731 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24733 singleSelect: true,
24734 selectedClass: "ydataview-selected",
24738 // listen for node click?
24739 view.on("click", function(vw, index, node, e){
24740 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24744 dataModel.load("foobar.xml");
24746 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24748 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24749 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24751 * Note: old style constructor is still suported (container, template, config)
24754 * Create a new View
24755 * @param {Object} config The config object
24758 Roo.View = function(config, depreciated_tpl, depreciated_config){
24760 if (typeof(depreciated_tpl) == 'undefined') {
24761 // new way.. - universal constructor.
24762 Roo.apply(this, config);
24763 this.el = Roo.get(this.el);
24766 this.el = Roo.get(config);
24767 this.tpl = depreciated_tpl;
24768 Roo.apply(this, depreciated_config);
24770 this.wrapEl = this.el.wrap().wrap();
24771 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24774 if(typeof(this.tpl) == "string"){
24775 this.tpl = new Roo.Template(this.tpl);
24777 // support xtype ctors..
24778 this.tpl = new Roo.factory(this.tpl, Roo);
24782 this.tpl.compile();
24790 * @event beforeclick
24791 * Fires before a click is processed. Returns false to cancel the default action.
24792 * @param {Roo.View} this
24793 * @param {Number} index The index of the target node
24794 * @param {HTMLElement} node The target node
24795 * @param {Roo.EventObject} e The raw event object
24797 "beforeclick" : true,
24800 * Fires when a template node is clicked.
24801 * @param {Roo.View} this
24802 * @param {Number} index The index of the target node
24803 * @param {HTMLElement} node The target node
24804 * @param {Roo.EventObject} e The raw event object
24809 * Fires when a template node is double clicked.
24810 * @param {Roo.View} this
24811 * @param {Number} index The index of the target node
24812 * @param {HTMLElement} node The target node
24813 * @param {Roo.EventObject} e The raw event object
24817 * @event contextmenu
24818 * Fires when a template node is right clicked.
24819 * @param {Roo.View} this
24820 * @param {Number} index The index of the target node
24821 * @param {HTMLElement} node The target node
24822 * @param {Roo.EventObject} e The raw event object
24824 "contextmenu" : true,
24826 * @event selectionchange
24827 * Fires when the selected nodes change.
24828 * @param {Roo.View} this
24829 * @param {Array} selections Array of the selected nodes
24831 "selectionchange" : true,
24834 * @event beforeselect
24835 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24836 * @param {Roo.View} this
24837 * @param {HTMLElement} node The node to be selected
24838 * @param {Array} selections Array of currently selected nodes
24840 "beforeselect" : true,
24842 * @event preparedata
24843 * Fires on every row to render, to allow you to change the data.
24844 * @param {Roo.View} this
24845 * @param {Object} data to be rendered (change this)
24847 "preparedata" : true
24855 "click": this.onClick,
24856 "dblclick": this.onDblClick,
24857 "contextmenu": this.onContextMenu,
24861 this.selections = [];
24863 this.cmp = new Roo.CompositeElementLite([]);
24865 this.store = Roo.factory(this.store, Roo.data);
24866 this.setStore(this.store, true);
24869 if ( this.footer && this.footer.xtype) {
24871 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24873 this.footer.dataSource = this.store
24874 this.footer.container = fctr;
24875 this.footer = Roo.factory(this.footer, Roo);
24876 fctr.insertFirst(this.el);
24878 // this is a bit insane - as the paging toolbar seems to detach the el..
24879 // dom.parentNode.parentNode.parentNode
24880 // they get detached?
24884 Roo.View.superclass.constructor.call(this);
24889 Roo.extend(Roo.View, Roo.util.Observable, {
24892 * @cfg {Roo.data.Store} store Data store to load data from.
24897 * @cfg {String|Roo.Element} el The container element.
24902 * @cfg {String|Roo.Template} tpl The template used by this View
24906 * @cfg {String} dataName the named area of the template to use as the data area
24907 * Works with domtemplates roo-name="name"
24911 * @cfg {String} selectedClass The css class to add to selected nodes
24913 selectedClass : "x-view-selected",
24915 * @cfg {String} emptyText The empty text to show when nothing is loaded.
24920 * @cfg {String} text to display on mask (default Loading)
24924 * @cfg {Boolean} multiSelect Allow multiple selection
24926 multiSelect : false,
24928 * @cfg {Boolean} singleSelect Allow single selection
24930 singleSelect: false,
24933 * @cfg {Boolean} toggleSelect - selecting
24935 toggleSelect : false,
24938 * Returns the element this view is bound to.
24939 * @return {Roo.Element}
24941 getEl : function(){
24942 return this.wrapEl;
24948 * Refreshes the view. - called by datachanged on the store. - do not call directly.
24950 refresh : function(){
24951 Roo.log('refresh');
24954 // if we are using something like 'domtemplate', then
24955 // the what gets used is:
24956 // t.applySubtemplate(NAME, data, wrapping data..)
24957 // the outer template then get' applied with
24958 // the store 'extra data'
24959 // and the body get's added to the
24960 // roo-name="data" node?
24961 // <span class='roo-tpl-{name}'></span> ?????
24965 this.clearSelections();
24966 this.el.update("");
24968 var records = this.store.getRange();
24969 if(records.length < 1) {
24971 // is this valid?? = should it render a template??
24973 this.el.update(this.emptyText);
24977 if (this.dataName) {
24978 this.el.update(t.apply(this.store.meta)); //????
24979 el = this.el.child('.roo-tpl-' + this.dataName);
24982 for(var i = 0, len = records.length; i < len; i++){
24983 var data = this.prepareData(records[i].data, i, records[i]);
24984 this.fireEvent("preparedata", this, data, i, records[i]);
24985 html[html.length] = Roo.util.Format.trim(
24987 t.applySubtemplate(this.dataName, data, this.store.meta) :
24994 el.update(html.join(""));
24995 this.nodes = el.dom.childNodes;
24996 this.updateIndexes(0);
25001 * Function to override to reformat the data that is sent to
25002 * the template for each node.
25003 * DEPRICATED - use the preparedata event handler.
25004 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25005 * a JSON object for an UpdateManager bound view).
25007 prepareData : function(data, index, record)
25009 this.fireEvent("preparedata", this, data, index, record);
25013 onUpdate : function(ds, record){
25014 Roo.log('on update');
25015 this.clearSelections();
25016 var index = this.store.indexOf(record);
25017 var n = this.nodes[index];
25018 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25019 n.parentNode.removeChild(n);
25020 this.updateIndexes(index, index);
25026 onAdd : function(ds, records, index)
25028 Roo.log(['on Add', ds, records, index] );
25029 this.clearSelections();
25030 if(this.nodes.length == 0){
25034 var n = this.nodes[index];
25035 for(var i = 0, len = records.length; i < len; i++){
25036 var d = this.prepareData(records[i].data, i, records[i]);
25038 this.tpl.insertBefore(n, d);
25041 this.tpl.append(this.el, d);
25044 this.updateIndexes(index);
25047 onRemove : function(ds, record, index){
25048 Roo.log('onRemove');
25049 this.clearSelections();
25050 var el = this.dataName ?
25051 this.el.child('.roo-tpl-' + this.dataName) :
25054 el.dom.removeChild(this.nodes[index]);
25055 this.updateIndexes(index);
25059 * Refresh an individual node.
25060 * @param {Number} index
25062 refreshNode : function(index){
25063 this.onUpdate(this.store, this.store.getAt(index));
25066 updateIndexes : function(startIndex, endIndex){
25067 var ns = this.nodes;
25068 startIndex = startIndex || 0;
25069 endIndex = endIndex || ns.length - 1;
25070 for(var i = startIndex; i <= endIndex; i++){
25071 ns[i].nodeIndex = i;
25076 * Changes the data store this view uses and refresh the view.
25077 * @param {Store} store
25079 setStore : function(store, initial){
25080 if(!initial && this.store){
25081 this.store.un("datachanged", this.refresh);
25082 this.store.un("add", this.onAdd);
25083 this.store.un("remove", this.onRemove);
25084 this.store.un("update", this.onUpdate);
25085 this.store.un("clear", this.refresh);
25086 this.store.un("beforeload", this.onBeforeLoad);
25087 this.store.un("load", this.onLoad);
25088 this.store.un("loadexception", this.onLoad);
25092 store.on("datachanged", this.refresh, this);
25093 store.on("add", this.onAdd, this);
25094 store.on("remove", this.onRemove, this);
25095 store.on("update", this.onUpdate, this);
25096 store.on("clear", this.refresh, this);
25097 store.on("beforeload", this.onBeforeLoad, this);
25098 store.on("load", this.onLoad, this);
25099 store.on("loadexception", this.onLoad, this);
25107 * onbeforeLoad - masks the loading area.
25110 onBeforeLoad : function(store,opts)
25112 Roo.log('onBeforeLoad');
25114 this.el.update("");
25116 this.el.mask(this.mask ? this.mask : "Loading" );
25118 onLoad : function ()
25125 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25126 * @param {HTMLElement} node
25127 * @return {HTMLElement} The template node
25129 findItemFromChild : function(node){
25130 var el = this.dataName ?
25131 this.el.child('.roo-tpl-' + this.dataName,true) :
25134 if(!node || node.parentNode == el){
25137 var p = node.parentNode;
25138 while(p && p != el){
25139 if(p.parentNode == el){
25148 onClick : function(e){
25149 var item = this.findItemFromChild(e.getTarget());
25151 var index = this.indexOf(item);
25152 if(this.onItemClick(item, index, e) !== false){
25153 this.fireEvent("click", this, index, item, e);
25156 this.clearSelections();
25161 onContextMenu : function(e){
25162 var item = this.findItemFromChild(e.getTarget());
25164 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25169 onDblClick : function(e){
25170 var item = this.findItemFromChild(e.getTarget());
25172 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25176 onItemClick : function(item, index, e)
25178 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25181 if (this.toggleSelect) {
25182 var m = this.isSelected(item) ? 'unselect' : 'select';
25185 _t[m](item, true, false);
25188 if(this.multiSelect || this.singleSelect){
25189 if(this.multiSelect && e.shiftKey && this.lastSelection){
25190 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25192 this.select(item, this.multiSelect && e.ctrlKey);
25193 this.lastSelection = item;
25195 e.preventDefault();
25201 * Get the number of selected nodes.
25204 getSelectionCount : function(){
25205 return this.selections.length;
25209 * Get the currently selected nodes.
25210 * @return {Array} An array of HTMLElements
25212 getSelectedNodes : function(){
25213 return this.selections;
25217 * Get the indexes of the selected nodes.
25220 getSelectedIndexes : function(){
25221 var indexes = [], s = this.selections;
25222 for(var i = 0, len = s.length; i < len; i++){
25223 indexes.push(s[i].nodeIndex);
25229 * Clear all selections
25230 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25232 clearSelections : function(suppressEvent){
25233 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25234 this.cmp.elements = this.selections;
25235 this.cmp.removeClass(this.selectedClass);
25236 this.selections = [];
25237 if(!suppressEvent){
25238 this.fireEvent("selectionchange", this, this.selections);
25244 * Returns true if the passed node is selected
25245 * @param {HTMLElement/Number} node The node or node index
25246 * @return {Boolean}
25248 isSelected : function(node){
25249 var s = this.selections;
25253 node = this.getNode(node);
25254 return s.indexOf(node) !== -1;
25259 * @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
25260 * @param {Boolean} keepExisting (optional) true to keep existing selections
25261 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25263 select : function(nodeInfo, keepExisting, suppressEvent){
25264 if(nodeInfo instanceof Array){
25266 this.clearSelections(true);
25268 for(var i = 0, len = nodeInfo.length; i < len; i++){
25269 this.select(nodeInfo[i], true, true);
25273 var node = this.getNode(nodeInfo);
25274 if(!node || this.isSelected(node)){
25275 return; // already selected.
25278 this.clearSelections(true);
25280 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25281 Roo.fly(node).addClass(this.selectedClass);
25282 this.selections.push(node);
25283 if(!suppressEvent){
25284 this.fireEvent("selectionchange", this, this.selections);
25292 * @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
25293 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25294 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25296 unselect : function(nodeInfo, keepExisting, suppressEvent)
25298 if(nodeInfo instanceof Array){
25299 Roo.each(this.selections, function(s) {
25300 this.unselect(s, nodeInfo);
25304 var node = this.getNode(nodeInfo);
25305 if(!node || !this.isSelected(node)){
25306 Roo.log("not selected");
25307 return; // not selected.
25311 Roo.each(this.selections, function(s) {
25313 Roo.fly(node).removeClass(this.selectedClass);
25320 this.selections= ns;
25321 this.fireEvent("selectionchange", this, this.selections);
25325 * Gets a template node.
25326 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25327 * @return {HTMLElement} The node or null if it wasn't found
25329 getNode : function(nodeInfo){
25330 if(typeof nodeInfo == "string"){
25331 return document.getElementById(nodeInfo);
25332 }else if(typeof nodeInfo == "number"){
25333 return this.nodes[nodeInfo];
25339 * Gets a range template nodes.
25340 * @param {Number} startIndex
25341 * @param {Number} endIndex
25342 * @return {Array} An array of nodes
25344 getNodes : function(start, end){
25345 var ns = this.nodes;
25346 start = start || 0;
25347 end = typeof end == "undefined" ? ns.length - 1 : end;
25350 for(var i = start; i <= end; i++){
25354 for(var i = start; i >= end; i--){
25362 * Finds the index of the passed node
25363 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25364 * @return {Number} The index of the node or -1
25366 indexOf : function(node){
25367 node = this.getNode(node);
25368 if(typeof node.nodeIndex == "number"){
25369 return node.nodeIndex;
25371 var ns = this.nodes;
25372 for(var i = 0, len = ns.length; i < len; i++){
25382 * Ext JS Library 1.1.1
25383 * Copyright(c) 2006-2007, Ext JS, LLC.
25385 * Originally Released Under LGPL - original licence link has changed is not relivant.
25388 * <script type="text/javascript">
25392 * @class Roo.JsonView
25393 * @extends Roo.View
25394 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25396 var view = new Roo.JsonView({
25397 container: "my-element",
25398 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25403 // listen for node click?
25404 view.on("click", function(vw, index, node, e){
25405 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25408 // direct load of JSON data
25409 view.load("foobar.php");
25411 // Example from my blog list
25412 var tpl = new Roo.Template(
25413 '<div class="entry">' +
25414 '<a class="entry-title" href="{link}">{title}</a>' +
25415 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25416 "</div><hr />"
25419 var moreView = new Roo.JsonView({
25420 container : "entry-list",
25424 moreView.on("beforerender", this.sortEntries, this);
25426 url: "/blog/get-posts.php",
25427 params: "allposts=true",
25428 text: "Loading Blog Entries..."
25432 * Note: old code is supported with arguments : (container, template, config)
25436 * Create a new JsonView
25438 * @param {Object} config The config object
25441 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25444 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25446 var um = this.el.getUpdateManager();
25447 um.setRenderer(this);
25448 um.on("update", this.onLoad, this);
25449 um.on("failure", this.onLoadException, this);
25452 * @event beforerender
25453 * Fires before rendering of the downloaded JSON data.
25454 * @param {Roo.JsonView} this
25455 * @param {Object} data The JSON data loaded
25459 * Fires when data is loaded.
25460 * @param {Roo.JsonView} this
25461 * @param {Object} data The JSON data loaded
25462 * @param {Object} response The raw Connect response object
25465 * @event loadexception
25466 * Fires when loading fails.
25467 * @param {Roo.JsonView} this
25468 * @param {Object} response The raw Connect response object
25471 'beforerender' : true,
25473 'loadexception' : true
25476 Roo.extend(Roo.JsonView, Roo.View, {
25478 * @type {String} The root property in the loaded JSON object that contains the data
25483 * Refreshes the view.
25485 refresh : function(){
25486 this.clearSelections();
25487 this.el.update("");
25489 var o = this.jsonData;
25490 if(o && o.length > 0){
25491 for(var i = 0, len = o.length; i < len; i++){
25492 var data = this.prepareData(o[i], i, o);
25493 html[html.length] = this.tpl.apply(data);
25496 html.push(this.emptyText);
25498 this.el.update(html.join(""));
25499 this.nodes = this.el.dom.childNodes;
25500 this.updateIndexes(0);
25504 * 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.
25505 * @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:
25508 url: "your-url.php",
25509 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25510 callback: yourFunction,
25511 scope: yourObject, //(optional scope)
25514 text: "Loading...",
25519 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25520 * 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.
25521 * @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}
25522 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25523 * @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.
25526 var um = this.el.getUpdateManager();
25527 um.update.apply(um, arguments);
25530 render : function(el, response){
25531 this.clearSelections();
25532 this.el.update("");
25535 o = Roo.util.JSON.decode(response.responseText);
25538 o = o[this.jsonRoot];
25543 * The current JSON data or null
25546 this.beforeRender();
25551 * Get the number of records in the current JSON dataset
25554 getCount : function(){
25555 return this.jsonData ? this.jsonData.length : 0;
25559 * Returns the JSON object for the specified node(s)
25560 * @param {HTMLElement/Array} node The node or an array of nodes
25561 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25562 * you get the JSON object for the node
25564 getNodeData : function(node){
25565 if(node instanceof Array){
25567 for(var i = 0, len = node.length; i < len; i++){
25568 data.push(this.getNodeData(node[i]));
25572 return this.jsonData[this.indexOf(node)] || null;
25575 beforeRender : function(){
25576 this.snapshot = this.jsonData;
25578 this.sort.apply(this, this.sortInfo);
25580 this.fireEvent("beforerender", this, this.jsonData);
25583 onLoad : function(el, o){
25584 this.fireEvent("load", this, this.jsonData, o);
25587 onLoadException : function(el, o){
25588 this.fireEvent("loadexception", this, o);
25592 * Filter the data by a specific property.
25593 * @param {String} property A property on your JSON objects
25594 * @param {String/RegExp} value Either string that the property values
25595 * should start with, or a RegExp to test against the property
25597 filter : function(property, value){
25600 var ss = this.snapshot;
25601 if(typeof value == "string"){
25602 var vlen = value.length;
25604 this.clearFilter();
25607 value = value.toLowerCase();
25608 for(var i = 0, len = ss.length; i < len; i++){
25610 if(o[property].substr(0, vlen).toLowerCase() == value){
25614 } else if(value.exec){ // regex?
25615 for(var i = 0, len = ss.length; i < len; i++){
25617 if(value.test(o[property])){
25624 this.jsonData = data;
25630 * Filter by a function. The passed function will be called with each
25631 * object in the current dataset. If the function returns true the value is kept,
25632 * otherwise it is filtered.
25633 * @param {Function} fn
25634 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25636 filterBy : function(fn, scope){
25639 var ss = this.snapshot;
25640 for(var i = 0, len = ss.length; i < len; i++){
25642 if(fn.call(scope || this, o)){
25646 this.jsonData = data;
25652 * Clears the current filter.
25654 clearFilter : function(){
25655 if(this.snapshot && this.jsonData != this.snapshot){
25656 this.jsonData = this.snapshot;
25663 * Sorts the data for this view and refreshes it.
25664 * @param {String} property A property on your JSON objects to sort on
25665 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25666 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25668 sort : function(property, dir, sortType){
25669 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25672 var dsc = dir && dir.toLowerCase() == "desc";
25673 var f = function(o1, o2){
25674 var v1 = sortType ? sortType(o1[p]) : o1[p];
25675 var v2 = sortType ? sortType(o2[p]) : o2[p];
25678 return dsc ? +1 : -1;
25679 } else if(v1 > v2){
25680 return dsc ? -1 : +1;
25685 this.jsonData.sort(f);
25687 if(this.jsonData != this.snapshot){
25688 this.snapshot.sort(f);
25694 * Ext JS Library 1.1.1
25695 * Copyright(c) 2006-2007, Ext JS, LLC.
25697 * Originally Released Under LGPL - original licence link has changed is not relivant.
25700 * <script type="text/javascript">
25705 * @class Roo.ColorPalette
25706 * @extends Roo.Component
25707 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25708 * Here's an example of typical usage:
25710 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25711 cp.render('my-div');
25713 cp.on('select', function(palette, selColor){
25714 // do something with selColor
25718 * Create a new ColorPalette
25719 * @param {Object} config The config object
25721 Roo.ColorPalette = function(config){
25722 Roo.ColorPalette.superclass.constructor.call(this, config);
25726 * Fires when a color is selected
25727 * @param {ColorPalette} this
25728 * @param {String} color The 6-digit color hex code (without the # symbol)
25734 this.on("select", this.handler, this.scope, true);
25737 Roo.extend(Roo.ColorPalette, Roo.Component, {
25739 * @cfg {String} itemCls
25740 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25742 itemCls : "x-color-palette",
25744 * @cfg {String} value
25745 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25746 * the hex codes are case-sensitive.
25749 clickEvent:'click',
25751 ctype: "Roo.ColorPalette",
25754 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25756 allowReselect : false,
25759 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25760 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25761 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25762 * of colors with the width setting until the box is symmetrical.</p>
25763 * <p>You can override individual colors if needed:</p>
25765 var cp = new Roo.ColorPalette();
25766 cp.colors[0] = "FF0000"; // change the first box to red
25769 Or you can provide a custom array of your own for complete control:
25771 var cp = new Roo.ColorPalette();
25772 cp.colors = ["000000", "993300", "333300"];
25777 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25778 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25779 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25780 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25781 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25785 onRender : function(container, position){
25786 var t = new Roo.MasterTemplate(
25787 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25789 var c = this.colors;
25790 for(var i = 0, len = c.length; i < len; i++){
25793 var el = document.createElement("div");
25794 el.className = this.itemCls;
25796 container.dom.insertBefore(el, position);
25797 this.el = Roo.get(el);
25798 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25799 if(this.clickEvent != 'click'){
25800 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25805 afterRender : function(){
25806 Roo.ColorPalette.superclass.afterRender.call(this);
25808 var s = this.value;
25815 handleClick : function(e, t){
25816 e.preventDefault();
25817 if(!this.disabled){
25818 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25819 this.select(c.toUpperCase());
25824 * Selects the specified color in the palette (fires the select event)
25825 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25827 select : function(color){
25828 color = color.replace("#", "");
25829 if(color != this.value || this.allowReselect){
25832 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25834 el.child("a.color-"+color).addClass("x-color-palette-sel");
25835 this.value = color;
25836 this.fireEvent("select", this, color);
25841 * Ext JS Library 1.1.1
25842 * Copyright(c) 2006-2007, Ext JS, LLC.
25844 * Originally Released Under LGPL - original licence link has changed is not relivant.
25847 * <script type="text/javascript">
25851 * @class Roo.DatePicker
25852 * @extends Roo.Component
25853 * Simple date picker class.
25855 * Create a new DatePicker
25856 * @param {Object} config The config object
25858 Roo.DatePicker = function(config){
25859 Roo.DatePicker.superclass.constructor.call(this, config);
25861 this.value = config && config.value ?
25862 config.value.clearTime() : new Date().clearTime();
25867 * Fires when a date is selected
25868 * @param {DatePicker} this
25869 * @param {Date} date The selected date
25873 * @event monthchange
25874 * Fires when the displayed month changes
25875 * @param {DatePicker} this
25876 * @param {Date} date The selected month
25878 'monthchange': true
25882 this.on("select", this.handler, this.scope || this);
25884 // build the disabledDatesRE
25885 if(!this.disabledDatesRE && this.disabledDates){
25886 var dd = this.disabledDates;
25888 for(var i = 0; i < dd.length; i++){
25890 if(i != dd.length-1) re += "|";
25892 this.disabledDatesRE = new RegExp(re + ")");
25896 Roo.extend(Roo.DatePicker, Roo.Component, {
25898 * @cfg {String} todayText
25899 * The text to display on the button that selects the current date (defaults to "Today")
25901 todayText : "Today",
25903 * @cfg {String} okText
25904 * The text to display on the ok button
25906 okText : " OK ", //   to give the user extra clicking room
25908 * @cfg {String} cancelText
25909 * The text to display on the cancel button
25911 cancelText : "Cancel",
25913 * @cfg {String} todayTip
25914 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
25916 todayTip : "{0} (Spacebar)",
25918 * @cfg {Date} minDate
25919 * Minimum allowable date (JavaScript date object, defaults to null)
25923 * @cfg {Date} maxDate
25924 * Maximum allowable date (JavaScript date object, defaults to null)
25928 * @cfg {String} minText
25929 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
25931 minText : "This date is before the minimum date",
25933 * @cfg {String} maxText
25934 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
25936 maxText : "This date is after the maximum date",
25938 * @cfg {String} format
25939 * The default date format string which can be overriden for localization support. The format must be
25940 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
25944 * @cfg {Array} disabledDays
25945 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
25947 disabledDays : null,
25949 * @cfg {String} disabledDaysText
25950 * The tooltip to display when the date falls on a disabled day (defaults to "")
25952 disabledDaysText : "",
25954 * @cfg {RegExp} disabledDatesRE
25955 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
25957 disabledDatesRE : null,
25959 * @cfg {String} disabledDatesText
25960 * The tooltip text to display when the date falls on a disabled date (defaults to "")
25962 disabledDatesText : "",
25964 * @cfg {Boolean} constrainToViewport
25965 * True to constrain the date picker to the viewport (defaults to true)
25967 constrainToViewport : true,
25969 * @cfg {Array} monthNames
25970 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
25972 monthNames : Date.monthNames,
25974 * @cfg {Array} dayNames
25975 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
25977 dayNames : Date.dayNames,
25979 * @cfg {String} nextText
25980 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
25982 nextText: 'Next Month (Control+Right)',
25984 * @cfg {String} prevText
25985 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
25987 prevText: 'Previous Month (Control+Left)',
25989 * @cfg {String} monthYearText
25990 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
25992 monthYearText: 'Choose a month (Control+Up/Down to move years)',
25994 * @cfg {Number} startDay
25995 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
25999 * @cfg {Bool} showClear
26000 * Show a clear button (usefull for date form elements that can be blank.)
26006 * Sets the value of the date field
26007 * @param {Date} value The date to set
26009 setValue : function(value){
26010 var old = this.value;
26012 if (typeof(value) == 'string') {
26014 value = Date.parseDate(value, this.format);
26017 value = new Date();
26020 this.value = value.clearTime(true);
26022 this.update(this.value);
26027 * Gets the current selected value of the date field
26028 * @return {Date} The selected date
26030 getValue : function(){
26035 focus : function(){
26037 this.update(this.activeDate);
26042 onRender : function(container, position){
26045 '<table cellspacing="0">',
26046 '<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>',
26047 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26048 var dn = this.dayNames;
26049 for(var i = 0; i < 7; i++){
26050 var d = this.startDay+i;
26054 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26056 m[m.length] = "</tr></thead><tbody><tr>";
26057 for(var i = 0; i < 42; i++) {
26058 if(i % 7 == 0 && i != 0){
26059 m[m.length] = "</tr><tr>";
26061 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26063 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26064 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26066 var el = document.createElement("div");
26067 el.className = "x-date-picker";
26068 el.innerHTML = m.join("");
26070 container.dom.insertBefore(el, position);
26072 this.el = Roo.get(el);
26073 this.eventEl = Roo.get(el.firstChild);
26075 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26076 handler: this.showPrevMonth,
26078 preventDefault:true,
26082 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26083 handler: this.showNextMonth,
26085 preventDefault:true,
26089 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26091 this.monthPicker = this.el.down('div.x-date-mp');
26092 this.monthPicker.enableDisplayMode('block');
26094 var kn = new Roo.KeyNav(this.eventEl, {
26095 "left" : function(e){
26097 this.showPrevMonth() :
26098 this.update(this.activeDate.add("d", -1));
26101 "right" : function(e){
26103 this.showNextMonth() :
26104 this.update(this.activeDate.add("d", 1));
26107 "up" : function(e){
26109 this.showNextYear() :
26110 this.update(this.activeDate.add("d", -7));
26113 "down" : function(e){
26115 this.showPrevYear() :
26116 this.update(this.activeDate.add("d", 7));
26119 "pageUp" : function(e){
26120 this.showNextMonth();
26123 "pageDown" : function(e){
26124 this.showPrevMonth();
26127 "enter" : function(e){
26128 e.stopPropagation();
26135 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26137 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26139 this.el.unselectable();
26141 this.cells = this.el.select("table.x-date-inner tbody td");
26142 this.textNodes = this.el.query("table.x-date-inner tbody span");
26144 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26146 tooltip: this.monthYearText
26149 this.mbtn.on('click', this.showMonthPicker, this);
26150 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26153 var today = (new Date()).dateFormat(this.format);
26155 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26156 if (this.showClear) {
26157 baseTb.add( new Roo.Toolbar.Fill());
26160 text: String.format(this.todayText, today),
26161 tooltip: String.format(this.todayTip, today),
26162 handler: this.selectToday,
26166 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26169 if (this.showClear) {
26171 baseTb.add( new Roo.Toolbar.Fill());
26174 cls: 'x-btn-icon x-btn-clear',
26175 handler: function() {
26177 this.fireEvent("select", this, '');
26187 this.update(this.value);
26190 createMonthPicker : function(){
26191 if(!this.monthPicker.dom.firstChild){
26192 var buf = ['<table border="0" cellspacing="0">'];
26193 for(var i = 0; i < 6; i++){
26195 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26196 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26198 '<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>' :
26199 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26203 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26205 '</button><button type="button" class="x-date-mp-cancel">',
26207 '</button></td></tr>',
26210 this.monthPicker.update(buf.join(''));
26211 this.monthPicker.on('click', this.onMonthClick, this);
26212 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26214 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26215 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26217 this.mpMonths.each(function(m, a, i){
26220 m.dom.xmonth = 5 + Math.round(i * .5);
26222 m.dom.xmonth = Math.round((i-1) * .5);
26228 showMonthPicker : function(){
26229 this.createMonthPicker();
26230 var size = this.el.getSize();
26231 this.monthPicker.setSize(size);
26232 this.monthPicker.child('table').setSize(size);
26234 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26235 this.updateMPMonth(this.mpSelMonth);
26236 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26237 this.updateMPYear(this.mpSelYear);
26239 this.monthPicker.slideIn('t', {duration:.2});
26242 updateMPYear : function(y){
26244 var ys = this.mpYears.elements;
26245 for(var i = 1; i <= 10; i++){
26246 var td = ys[i-1], y2;
26248 y2 = y + Math.round(i * .5);
26249 td.firstChild.innerHTML = y2;
26252 y2 = y - (5-Math.round(i * .5));
26253 td.firstChild.innerHTML = y2;
26256 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26260 updateMPMonth : function(sm){
26261 this.mpMonths.each(function(m, a, i){
26262 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26266 selectMPMonth: function(m){
26270 onMonthClick : function(e, t){
26272 var el = new Roo.Element(t), pn;
26273 if(el.is('button.x-date-mp-cancel')){
26274 this.hideMonthPicker();
26276 else if(el.is('button.x-date-mp-ok')){
26277 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26278 this.hideMonthPicker();
26280 else if(pn = el.up('td.x-date-mp-month', 2)){
26281 this.mpMonths.removeClass('x-date-mp-sel');
26282 pn.addClass('x-date-mp-sel');
26283 this.mpSelMonth = pn.dom.xmonth;
26285 else if(pn = el.up('td.x-date-mp-year', 2)){
26286 this.mpYears.removeClass('x-date-mp-sel');
26287 pn.addClass('x-date-mp-sel');
26288 this.mpSelYear = pn.dom.xyear;
26290 else if(el.is('a.x-date-mp-prev')){
26291 this.updateMPYear(this.mpyear-10);
26293 else if(el.is('a.x-date-mp-next')){
26294 this.updateMPYear(this.mpyear+10);
26298 onMonthDblClick : function(e, t){
26300 var el = new Roo.Element(t), pn;
26301 if(pn = el.up('td.x-date-mp-month', 2)){
26302 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26303 this.hideMonthPicker();
26305 else if(pn = el.up('td.x-date-mp-year', 2)){
26306 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26307 this.hideMonthPicker();
26311 hideMonthPicker : function(disableAnim){
26312 if(this.monthPicker){
26313 if(disableAnim === true){
26314 this.monthPicker.hide();
26316 this.monthPicker.slideOut('t', {duration:.2});
26322 showPrevMonth : function(e){
26323 this.update(this.activeDate.add("mo", -1));
26327 showNextMonth : function(e){
26328 this.update(this.activeDate.add("mo", 1));
26332 showPrevYear : function(){
26333 this.update(this.activeDate.add("y", -1));
26337 showNextYear : function(){
26338 this.update(this.activeDate.add("y", 1));
26342 handleMouseWheel : function(e){
26343 var delta = e.getWheelDelta();
26345 this.showPrevMonth();
26347 } else if(delta < 0){
26348 this.showNextMonth();
26354 handleDateClick : function(e, t){
26356 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26357 this.setValue(new Date(t.dateValue));
26358 this.fireEvent("select", this, this.value);
26363 selectToday : function(){
26364 this.setValue(new Date().clearTime());
26365 this.fireEvent("select", this, this.value);
26369 update : function(date)
26371 var vd = this.activeDate;
26372 this.activeDate = date;
26374 var t = date.getTime();
26375 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26376 this.cells.removeClass("x-date-selected");
26377 this.cells.each(function(c){
26378 if(c.dom.firstChild.dateValue == t){
26379 c.addClass("x-date-selected");
26380 setTimeout(function(){
26381 try{c.dom.firstChild.focus();}catch(e){}
26390 var days = date.getDaysInMonth();
26391 var firstOfMonth = date.getFirstDateOfMonth();
26392 var startingPos = firstOfMonth.getDay()-this.startDay;
26394 if(startingPos <= this.startDay){
26398 var pm = date.add("mo", -1);
26399 var prevStart = pm.getDaysInMonth()-startingPos;
26401 var cells = this.cells.elements;
26402 var textEls = this.textNodes;
26403 days += startingPos;
26405 // convert everything to numbers so it's fast
26406 var day = 86400000;
26407 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26408 var today = new Date().clearTime().getTime();
26409 var sel = date.clearTime().getTime();
26410 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26411 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26412 var ddMatch = this.disabledDatesRE;
26413 var ddText = this.disabledDatesText;
26414 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26415 var ddaysText = this.disabledDaysText;
26416 var format = this.format;
26418 var setCellClass = function(cal, cell){
26420 var t = d.getTime();
26421 cell.firstChild.dateValue = t;
26423 cell.className += " x-date-today";
26424 cell.title = cal.todayText;
26427 cell.className += " x-date-selected";
26428 setTimeout(function(){
26429 try{cell.firstChild.focus();}catch(e){}
26434 cell.className = " x-date-disabled";
26435 cell.title = cal.minText;
26439 cell.className = " x-date-disabled";
26440 cell.title = cal.maxText;
26444 if(ddays.indexOf(d.getDay()) != -1){
26445 cell.title = ddaysText;
26446 cell.className = " x-date-disabled";
26449 if(ddMatch && format){
26450 var fvalue = d.dateFormat(format);
26451 if(ddMatch.test(fvalue)){
26452 cell.title = ddText.replace("%0", fvalue);
26453 cell.className = " x-date-disabled";
26459 for(; i < startingPos; i++) {
26460 textEls[i].innerHTML = (++prevStart);
26461 d.setDate(d.getDate()+1);
26462 cells[i].className = "x-date-prevday";
26463 setCellClass(this, cells[i]);
26465 for(; i < days; i++){
26466 intDay = i - startingPos + 1;
26467 textEls[i].innerHTML = (intDay);
26468 d.setDate(d.getDate()+1);
26469 cells[i].className = "x-date-active";
26470 setCellClass(this, cells[i]);
26473 for(; i < 42; i++) {
26474 textEls[i].innerHTML = (++extraDays);
26475 d.setDate(d.getDate()+1);
26476 cells[i].className = "x-date-nextday";
26477 setCellClass(this, cells[i]);
26480 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26481 this.fireEvent('monthchange', this, date);
26483 if(!this.internalRender){
26484 var main = this.el.dom.firstChild;
26485 var w = main.offsetWidth;
26486 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26487 Roo.fly(main).setWidth(w);
26488 this.internalRender = true;
26489 // opera does not respect the auto grow header center column
26490 // then, after it gets a width opera refuses to recalculate
26491 // without a second pass
26492 if(Roo.isOpera && !this.secondPass){
26493 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26494 this.secondPass = true;
26495 this.update.defer(10, this, [date]);
26503 * Ext JS Library 1.1.1
26504 * Copyright(c) 2006-2007, Ext JS, LLC.
26506 * Originally Released Under LGPL - original licence link has changed is not relivant.
26509 * <script type="text/javascript">
26512 * @class Roo.TabPanel
26513 * @extends Roo.util.Observable
26514 * A lightweight tab container.
26518 // basic tabs 1, built from existing content
26519 var tabs = new Roo.TabPanel("tabs1");
26520 tabs.addTab("script", "View Script");
26521 tabs.addTab("markup", "View Markup");
26522 tabs.activate("script");
26524 // more advanced tabs, built from javascript
26525 var jtabs = new Roo.TabPanel("jtabs");
26526 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26528 // set up the UpdateManager
26529 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26530 var updater = tab2.getUpdateManager();
26531 updater.setDefaultUrl("ajax1.htm");
26532 tab2.on('activate', updater.refresh, updater, true);
26534 // Use setUrl for Ajax loading
26535 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26536 tab3.setUrl("ajax2.htm", null, true);
26539 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26542 jtabs.activate("jtabs-1");
26545 * Create a new TabPanel.
26546 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26547 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26549 Roo.TabPanel = function(container, config){
26551 * The container element for this TabPanel.
26552 * @type Roo.Element
26554 this.el = Roo.get(container, true);
26556 if(typeof config == "boolean"){
26557 this.tabPosition = config ? "bottom" : "top";
26559 Roo.apply(this, config);
26562 if(this.tabPosition == "bottom"){
26563 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26564 this.el.addClass("x-tabs-bottom");
26566 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26567 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26568 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26570 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26572 if(this.tabPosition != "bottom"){
26573 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26574 * @type Roo.Element
26576 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26577 this.el.addClass("x-tabs-top");
26581 this.bodyEl.setStyle("position", "relative");
26583 this.active = null;
26584 this.activateDelegate = this.activate.createDelegate(this);
26589 * Fires when the active tab changes
26590 * @param {Roo.TabPanel} this
26591 * @param {Roo.TabPanelItem} activePanel The new active tab
26595 * @event beforetabchange
26596 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26597 * @param {Roo.TabPanel} this
26598 * @param {Object} e Set cancel to true on this object to cancel the tab change
26599 * @param {Roo.TabPanelItem} tab The tab being changed to
26601 "beforetabchange" : true
26604 Roo.EventManager.onWindowResize(this.onResize, this);
26605 this.cpad = this.el.getPadding("lr");
26606 this.hiddenCount = 0;
26609 // toolbar on the tabbar support...
26610 if (this.toolbar) {
26611 var tcfg = this.toolbar;
26612 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26613 this.toolbar = new Roo.Toolbar(tcfg);
26614 if (Roo.isSafari) {
26615 var tbl = tcfg.container.child('table', true);
26616 tbl.setAttribute('width', '100%');
26623 Roo.TabPanel.superclass.constructor.call(this);
26626 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26628 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26630 tabPosition : "top",
26632 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26634 currentTabWidth : 0,
26636 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26640 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26644 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26646 preferredTabWidth : 175,
26648 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26650 resizeTabs : false,
26652 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26654 monitorResize : true,
26656 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26661 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26662 * @param {String} id The id of the div to use <b>or create</b>
26663 * @param {String} text The text for the tab
26664 * @param {String} content (optional) Content to put in the TabPanelItem body
26665 * @param {Boolean} closable (optional) True to create a close icon on the tab
26666 * @return {Roo.TabPanelItem} The created TabPanelItem
26668 addTab : function(id, text, content, closable){
26669 var item = new Roo.TabPanelItem(this, id, text, closable);
26670 this.addTabItem(item);
26672 item.setContent(content);
26678 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26679 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26680 * @return {Roo.TabPanelItem}
26682 getTab : function(id){
26683 return this.items[id];
26687 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26688 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26690 hideTab : function(id){
26691 var t = this.items[id];
26694 this.hiddenCount++;
26695 this.autoSizeTabs();
26700 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26701 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26703 unhideTab : function(id){
26704 var t = this.items[id];
26706 t.setHidden(false);
26707 this.hiddenCount--;
26708 this.autoSizeTabs();
26713 * Adds an existing {@link Roo.TabPanelItem}.
26714 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26716 addTabItem : function(item){
26717 this.items[item.id] = item;
26718 this.items.push(item);
26719 if(this.resizeTabs){
26720 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26721 this.autoSizeTabs();
26728 * Removes a {@link Roo.TabPanelItem}.
26729 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26731 removeTab : function(id){
26732 var items = this.items;
26733 var tab = items[id];
26734 if(!tab) { return; }
26735 var index = items.indexOf(tab);
26736 if(this.active == tab && items.length > 1){
26737 var newTab = this.getNextAvailable(index);
26742 this.stripEl.dom.removeChild(tab.pnode.dom);
26743 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26744 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26746 items.splice(index, 1);
26747 delete this.items[tab.id];
26748 tab.fireEvent("close", tab);
26749 tab.purgeListeners();
26750 this.autoSizeTabs();
26753 getNextAvailable : function(start){
26754 var items = this.items;
26756 // look for a next tab that will slide over to
26757 // replace the one being removed
26758 while(index < items.length){
26759 var item = items[++index];
26760 if(item && !item.isHidden()){
26764 // if one isn't found select the previous tab (on the left)
26767 var item = items[--index];
26768 if(item && !item.isHidden()){
26776 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26777 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26779 disableTab : function(id){
26780 var tab = this.items[id];
26781 if(tab && this.active != tab){
26787 * Enables a {@link Roo.TabPanelItem} that is disabled.
26788 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26790 enableTab : function(id){
26791 var tab = this.items[id];
26796 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26797 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26798 * @return {Roo.TabPanelItem} The TabPanelItem.
26800 activate : function(id){
26801 var tab = this.items[id];
26805 if(tab == this.active || tab.disabled){
26809 this.fireEvent("beforetabchange", this, e, tab);
26810 if(e.cancel !== true && !tab.disabled){
26812 this.active.hide();
26814 this.active = this.items[id];
26815 this.active.show();
26816 this.fireEvent("tabchange", this, this.active);
26822 * Gets the active {@link Roo.TabPanelItem}.
26823 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26825 getActiveTab : function(){
26826 return this.active;
26830 * Updates the tab body element to fit the height of the container element
26831 * for overflow scrolling
26832 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26834 syncHeight : function(targetHeight){
26835 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26836 var bm = this.bodyEl.getMargins();
26837 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26838 this.bodyEl.setHeight(newHeight);
26842 onResize : function(){
26843 if(this.monitorResize){
26844 this.autoSizeTabs();
26849 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26851 beginUpdate : function(){
26852 this.updating = true;
26856 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
26858 endUpdate : function(){
26859 this.updating = false;
26860 this.autoSizeTabs();
26864 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
26866 autoSizeTabs : function(){
26867 var count = this.items.length;
26868 var vcount = count - this.hiddenCount;
26869 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
26870 var w = Math.max(this.el.getWidth() - this.cpad, 10);
26871 var availWidth = Math.floor(w / vcount);
26872 var b = this.stripBody;
26873 if(b.getWidth() > w){
26874 var tabs = this.items;
26875 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
26876 if(availWidth < this.minTabWidth){
26877 /*if(!this.sleft){ // incomplete scrolling code
26878 this.createScrollButtons();
26881 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
26884 if(this.currentTabWidth < this.preferredTabWidth){
26885 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
26891 * Returns the number of tabs in this TabPanel.
26894 getCount : function(){
26895 return this.items.length;
26899 * Resizes all the tabs to the passed width
26900 * @param {Number} The new width
26902 setTabWidth : function(width){
26903 this.currentTabWidth = width;
26904 for(var i = 0, len = this.items.length; i < len; i++) {
26905 if(!this.items[i].isHidden())this.items[i].setWidth(width);
26910 * Destroys this TabPanel
26911 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
26913 destroy : function(removeEl){
26914 Roo.EventManager.removeResizeListener(this.onResize, this);
26915 for(var i = 0, len = this.items.length; i < len; i++){
26916 this.items[i].purgeListeners();
26918 if(removeEl === true){
26919 this.el.update("");
26926 * @class Roo.TabPanelItem
26927 * @extends Roo.util.Observable
26928 * Represents an individual item (tab plus body) in a TabPanel.
26929 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
26930 * @param {String} id The id of this TabPanelItem
26931 * @param {String} text The text for the tab of this TabPanelItem
26932 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
26934 Roo.TabPanelItem = function(tabPanel, id, text, closable){
26936 * The {@link Roo.TabPanel} this TabPanelItem belongs to
26937 * @type Roo.TabPanel
26939 this.tabPanel = tabPanel;
26941 * The id for this TabPanelItem
26946 this.disabled = false;
26950 this.loaded = false;
26951 this.closable = closable;
26954 * The body element for this TabPanelItem.
26955 * @type Roo.Element
26957 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
26958 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
26959 this.bodyEl.setStyle("display", "block");
26960 this.bodyEl.setStyle("zoom", "1");
26963 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
26965 this.el = Roo.get(els.el, true);
26966 this.inner = Roo.get(els.inner, true);
26967 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
26968 this.pnode = Roo.get(els.el.parentNode, true);
26969 this.el.on("mousedown", this.onTabMouseDown, this);
26970 this.el.on("click", this.onTabClick, this);
26973 var c = Roo.get(els.close, true);
26974 c.dom.title = this.closeText;
26975 c.addClassOnOver("close-over");
26976 c.on("click", this.closeClick, this);
26982 * Fires when this tab becomes the active tab.
26983 * @param {Roo.TabPanel} tabPanel The parent TabPanel
26984 * @param {Roo.TabPanelItem} this
26988 * @event beforeclose
26989 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
26990 * @param {Roo.TabPanelItem} this
26991 * @param {Object} e Set cancel to true on this object to cancel the close.
26993 "beforeclose": true,
26996 * Fires when this tab is closed.
26997 * @param {Roo.TabPanelItem} this
27001 * @event deactivate
27002 * Fires when this tab is no longer the active tab.
27003 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27004 * @param {Roo.TabPanelItem} this
27006 "deactivate" : true
27008 this.hidden = false;
27010 Roo.TabPanelItem.superclass.constructor.call(this);
27013 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27014 purgeListeners : function(){
27015 Roo.util.Observable.prototype.purgeListeners.call(this);
27016 this.el.removeAllListeners();
27019 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27022 this.pnode.addClass("on");
27025 this.tabPanel.stripWrap.repaint();
27027 this.fireEvent("activate", this.tabPanel, this);
27031 * Returns true if this tab is the active tab.
27032 * @return {Boolean}
27034 isActive : function(){
27035 return this.tabPanel.getActiveTab() == this;
27039 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27042 this.pnode.removeClass("on");
27044 this.fireEvent("deactivate", this.tabPanel, this);
27047 hideAction : function(){
27048 this.bodyEl.hide();
27049 this.bodyEl.setStyle("position", "absolute");
27050 this.bodyEl.setLeft("-20000px");
27051 this.bodyEl.setTop("-20000px");
27054 showAction : function(){
27055 this.bodyEl.setStyle("position", "relative");
27056 this.bodyEl.setTop("");
27057 this.bodyEl.setLeft("");
27058 this.bodyEl.show();
27062 * Set the tooltip for the tab.
27063 * @param {String} tooltip The tab's tooltip
27065 setTooltip : function(text){
27066 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27067 this.textEl.dom.qtip = text;
27068 this.textEl.dom.removeAttribute('title');
27070 this.textEl.dom.title = text;
27074 onTabClick : function(e){
27075 e.preventDefault();
27076 this.tabPanel.activate(this.id);
27079 onTabMouseDown : function(e){
27080 e.preventDefault();
27081 this.tabPanel.activate(this.id);
27084 getWidth : function(){
27085 return this.inner.getWidth();
27088 setWidth : function(width){
27089 var iwidth = width - this.pnode.getPadding("lr");
27090 this.inner.setWidth(iwidth);
27091 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27092 this.pnode.setWidth(width);
27096 * Show or hide the tab
27097 * @param {Boolean} hidden True to hide or false to show.
27099 setHidden : function(hidden){
27100 this.hidden = hidden;
27101 this.pnode.setStyle("display", hidden ? "none" : "");
27105 * Returns true if this tab is "hidden"
27106 * @return {Boolean}
27108 isHidden : function(){
27109 return this.hidden;
27113 * Returns the text for this tab
27116 getText : function(){
27120 autoSize : function(){
27121 //this.el.beginMeasure();
27122 this.textEl.setWidth(1);
27123 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
27124 //this.el.endMeasure();
27128 * Sets the text for the tab (Note: this also sets the tooltip text)
27129 * @param {String} text The tab's text and tooltip
27131 setText : function(text){
27133 this.textEl.update(text);
27134 this.setTooltip(text);
27135 if(!this.tabPanel.resizeTabs){
27140 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27142 activate : function(){
27143 this.tabPanel.activate(this.id);
27147 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27149 disable : function(){
27150 if(this.tabPanel.active != this){
27151 this.disabled = true;
27152 this.pnode.addClass("disabled");
27157 * Enables this TabPanelItem if it was previously disabled.
27159 enable : function(){
27160 this.disabled = false;
27161 this.pnode.removeClass("disabled");
27165 * Sets the content for this TabPanelItem.
27166 * @param {String} content The content
27167 * @param {Boolean} loadScripts true to look for and load scripts
27169 setContent : function(content, loadScripts){
27170 this.bodyEl.update(content, loadScripts);
27174 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27175 * @return {Roo.UpdateManager} The UpdateManager
27177 getUpdateManager : function(){
27178 return this.bodyEl.getUpdateManager();
27182 * Set a URL to be used to load the content for this TabPanelItem.
27183 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27184 * @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)
27185 * @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)
27186 * @return {Roo.UpdateManager} The UpdateManager
27188 setUrl : function(url, params, loadOnce){
27189 if(this.refreshDelegate){
27190 this.un('activate', this.refreshDelegate);
27192 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27193 this.on("activate", this.refreshDelegate);
27194 return this.bodyEl.getUpdateManager();
27198 _handleRefresh : function(url, params, loadOnce){
27199 if(!loadOnce || !this.loaded){
27200 var updater = this.bodyEl.getUpdateManager();
27201 updater.update(url, params, this._setLoaded.createDelegate(this));
27206 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27207 * Will fail silently if the setUrl method has not been called.
27208 * This does not activate the panel, just updates its content.
27210 refresh : function(){
27211 if(this.refreshDelegate){
27212 this.loaded = false;
27213 this.refreshDelegate();
27218 _setLoaded : function(){
27219 this.loaded = true;
27223 closeClick : function(e){
27226 this.fireEvent("beforeclose", this, o);
27227 if(o.cancel !== true){
27228 this.tabPanel.removeTab(this.id);
27232 * The text displayed in the tooltip for the close icon.
27235 closeText : "Close this tab"
27239 Roo.TabPanel.prototype.createStrip = function(container){
27240 var strip = document.createElement("div");
27241 strip.className = "x-tabs-wrap";
27242 container.appendChild(strip);
27246 Roo.TabPanel.prototype.createStripList = function(strip){
27247 // div wrapper for retard IE
27248 // returns the "tr" element.
27249 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27250 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27251 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27252 return strip.firstChild.firstChild.firstChild.firstChild;
27255 Roo.TabPanel.prototype.createBody = function(container){
27256 var body = document.createElement("div");
27257 Roo.id(body, "tab-body");
27258 Roo.fly(body).addClass("x-tabs-body");
27259 container.appendChild(body);
27263 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27264 var body = Roo.getDom(id);
27266 body = document.createElement("div");
27269 Roo.fly(body).addClass("x-tabs-item-body");
27270 bodyEl.insertBefore(body, bodyEl.firstChild);
27274 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27275 var td = document.createElement("td");
27276 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27277 //stripEl.appendChild(td);
27279 td.className = "x-tabs-closable";
27280 if(!this.closeTpl){
27281 this.closeTpl = new Roo.Template(
27282 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27283 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27284 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27287 var el = this.closeTpl.overwrite(td, {"text": text});
27288 var close = el.getElementsByTagName("div")[0];
27289 var inner = el.getElementsByTagName("em")[0];
27290 return {"el": el, "close": close, "inner": inner};
27293 this.tabTpl = new Roo.Template(
27294 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27295 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27298 var el = this.tabTpl.overwrite(td, {"text": text});
27299 var inner = el.getElementsByTagName("em")[0];
27300 return {"el": el, "inner": inner};
27304 * Ext JS Library 1.1.1
27305 * Copyright(c) 2006-2007, Ext JS, LLC.
27307 * Originally Released Under LGPL - original licence link has changed is not relivant.
27310 * <script type="text/javascript">
27314 * @class Roo.Button
27315 * @extends Roo.util.Observable
27316 * Simple Button class
27317 * @cfg {String} text The button text
27318 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27319 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27320 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27321 * @cfg {Object} scope The scope of the handler
27322 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27323 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27324 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27325 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27326 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27327 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27328 applies if enableToggle = true)
27329 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27330 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27331 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27333 * Create a new button
27334 * @param {Object} config The config object
27336 Roo.Button = function(renderTo, config)
27340 renderTo = config.renderTo || false;
27343 Roo.apply(this, config);
27347 * Fires when this button is clicked
27348 * @param {Button} this
27349 * @param {EventObject} e The click event
27354 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27355 * @param {Button} this
27356 * @param {Boolean} pressed
27361 * Fires when the mouse hovers over the button
27362 * @param {Button} this
27363 * @param {Event} e The event object
27365 'mouseover' : true,
27368 * Fires when the mouse exits the button
27369 * @param {Button} this
27370 * @param {Event} e The event object
27375 * Fires when the button is rendered
27376 * @param {Button} this
27381 this.menu = Roo.menu.MenuMgr.get(this.menu);
27383 // register listeners first!! - so render can be captured..
27384 Roo.util.Observable.call(this);
27386 this.render(renderTo);
27392 Roo.extend(Roo.Button, Roo.util.Observable, {
27398 * Read-only. True if this button is hidden
27403 * Read-only. True if this button is disabled
27408 * Read-only. True if this button is pressed (only if enableToggle = true)
27414 * @cfg {Number} tabIndex
27415 * The DOM tabIndex for this button (defaults to undefined)
27417 tabIndex : undefined,
27420 * @cfg {Boolean} enableToggle
27421 * True to enable pressed/not pressed toggling (defaults to false)
27423 enableToggle: false,
27425 * @cfg {Mixed} menu
27426 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27430 * @cfg {String} menuAlign
27431 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27433 menuAlign : "tl-bl?",
27436 * @cfg {String} iconCls
27437 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27439 iconCls : undefined,
27441 * @cfg {String} type
27442 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27447 menuClassTarget: 'tr',
27450 * @cfg {String} clickEvent
27451 * The type of event to map to the button's event handler (defaults to 'click')
27453 clickEvent : 'click',
27456 * @cfg {Boolean} handleMouseEvents
27457 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27459 handleMouseEvents : true,
27462 * @cfg {String} tooltipType
27463 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27465 tooltipType : 'qtip',
27468 * @cfg {String} cls
27469 * A CSS class to apply to the button's main element.
27473 * @cfg {Roo.Template} template (Optional)
27474 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27475 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27476 * require code modifications if required elements (e.g. a button) aren't present.
27480 render : function(renderTo){
27482 if(this.hideParent){
27483 this.parentEl = Roo.get(renderTo);
27485 if(!this.dhconfig){
27486 if(!this.template){
27487 if(!Roo.Button.buttonTemplate){
27488 // hideous table template
27489 Roo.Button.buttonTemplate = new Roo.Template(
27490 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27491 '<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>',
27492 "</tr></tbody></table>");
27494 this.template = Roo.Button.buttonTemplate;
27496 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27497 var btnEl = btn.child("button:first");
27498 btnEl.on('focus', this.onFocus, this);
27499 btnEl.on('blur', this.onBlur, this);
27501 btn.addClass(this.cls);
27504 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27507 btnEl.addClass(this.iconCls);
27509 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27512 if(this.tabIndex !== undefined){
27513 btnEl.dom.tabIndex = this.tabIndex;
27516 if(typeof this.tooltip == 'object'){
27517 Roo.QuickTips.tips(Roo.apply({
27521 btnEl.dom[this.tooltipType] = this.tooltip;
27525 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27529 this.el.dom.id = this.el.id = this.id;
27532 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27533 this.menu.on("show", this.onMenuShow, this);
27534 this.menu.on("hide", this.onMenuHide, this);
27536 btn.addClass("x-btn");
27537 if(Roo.isIE && !Roo.isIE7){
27538 this.autoWidth.defer(1, this);
27542 if(this.handleMouseEvents){
27543 btn.on("mouseover", this.onMouseOver, this);
27544 btn.on("mouseout", this.onMouseOut, this);
27545 btn.on("mousedown", this.onMouseDown, this);
27547 btn.on(this.clickEvent, this.onClick, this);
27548 //btn.on("mouseup", this.onMouseUp, this);
27555 Roo.ButtonToggleMgr.register(this);
27557 this.el.addClass("x-btn-pressed");
27560 var repeater = new Roo.util.ClickRepeater(btn,
27561 typeof this.repeat == "object" ? this.repeat : {}
27563 repeater.on("click", this.onClick, this);
27566 this.fireEvent('render', this);
27570 * Returns the button's underlying element
27571 * @return {Roo.Element} The element
27573 getEl : function(){
27578 * Destroys this Button and removes any listeners.
27580 destroy : function(){
27581 Roo.ButtonToggleMgr.unregister(this);
27582 this.el.removeAllListeners();
27583 this.purgeListeners();
27588 autoWidth : function(){
27590 this.el.setWidth("auto");
27591 if(Roo.isIE7 && Roo.isStrict){
27592 var ib = this.el.child('button');
27593 if(ib && ib.getWidth() > 20){
27595 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27600 this.el.beginMeasure();
27602 if(this.el.getWidth() < this.minWidth){
27603 this.el.setWidth(this.minWidth);
27606 this.el.endMeasure();
27613 * Assigns this button's click handler
27614 * @param {Function} handler The function to call when the button is clicked
27615 * @param {Object} scope (optional) Scope for the function passed in
27617 setHandler : function(handler, scope){
27618 this.handler = handler;
27619 this.scope = scope;
27623 * Sets this button's text
27624 * @param {String} text The button text
27626 setText : function(text){
27629 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27635 * Gets the text for this button
27636 * @return {String} The button text
27638 getText : function(){
27646 this.hidden = false;
27648 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27656 this.hidden = true;
27658 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27663 * Convenience function for boolean show/hide
27664 * @param {Boolean} visible True to show, false to hide
27666 setVisible: function(visible){
27675 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27676 * @param {Boolean} state (optional) Force a particular state
27678 toggle : function(state){
27679 state = state === undefined ? !this.pressed : state;
27680 if(state != this.pressed){
27682 this.el.addClass("x-btn-pressed");
27683 this.pressed = true;
27684 this.fireEvent("toggle", this, true);
27686 this.el.removeClass("x-btn-pressed");
27687 this.pressed = false;
27688 this.fireEvent("toggle", this, false);
27690 if(this.toggleHandler){
27691 this.toggleHandler.call(this.scope || this, this, state);
27699 focus : function(){
27700 this.el.child('button:first').focus();
27704 * Disable this button
27706 disable : function(){
27708 this.el.addClass("x-btn-disabled");
27710 this.disabled = true;
27714 * Enable this button
27716 enable : function(){
27718 this.el.removeClass("x-btn-disabled");
27720 this.disabled = false;
27724 * Convenience function for boolean enable/disable
27725 * @param {Boolean} enabled True to enable, false to disable
27727 setDisabled : function(v){
27728 this[v !== true ? "enable" : "disable"]();
27732 onClick : function(e){
27734 e.preventDefault();
27739 if(!this.disabled){
27740 if(this.enableToggle){
27743 if(this.menu && !this.menu.isVisible()){
27744 this.menu.show(this.el, this.menuAlign);
27746 this.fireEvent("click", this, e);
27748 this.el.removeClass("x-btn-over");
27749 this.handler.call(this.scope || this, this, e);
27754 onMouseOver : function(e){
27755 if(!this.disabled){
27756 this.el.addClass("x-btn-over");
27757 this.fireEvent('mouseover', this, e);
27761 onMouseOut : function(e){
27762 if(!e.within(this.el, true)){
27763 this.el.removeClass("x-btn-over");
27764 this.fireEvent('mouseout', this, e);
27768 onFocus : function(e){
27769 if(!this.disabled){
27770 this.el.addClass("x-btn-focus");
27774 onBlur : function(e){
27775 this.el.removeClass("x-btn-focus");
27778 onMouseDown : function(e){
27779 if(!this.disabled && e.button == 0){
27780 this.el.addClass("x-btn-click");
27781 Roo.get(document).on('mouseup', this.onMouseUp, this);
27785 onMouseUp : function(e){
27787 this.el.removeClass("x-btn-click");
27788 Roo.get(document).un('mouseup', this.onMouseUp, this);
27792 onMenuShow : function(e){
27793 this.el.addClass("x-btn-menu-active");
27796 onMenuHide : function(e){
27797 this.el.removeClass("x-btn-menu-active");
27801 // Private utility class used by Button
27802 Roo.ButtonToggleMgr = function(){
27805 function toggleGroup(btn, state){
27807 var g = groups[btn.toggleGroup];
27808 for(var i = 0, l = g.length; i < l; i++){
27810 g[i].toggle(false);
27817 register : function(btn){
27818 if(!btn.toggleGroup){
27821 var g = groups[btn.toggleGroup];
27823 g = groups[btn.toggleGroup] = [];
27826 btn.on("toggle", toggleGroup);
27829 unregister : function(btn){
27830 if(!btn.toggleGroup){
27833 var g = groups[btn.toggleGroup];
27836 btn.un("toggle", toggleGroup);
27842 * Ext JS Library 1.1.1
27843 * Copyright(c) 2006-2007, Ext JS, LLC.
27845 * Originally Released Under LGPL - original licence link has changed is not relivant.
27848 * <script type="text/javascript">
27852 * @class Roo.SplitButton
27853 * @extends Roo.Button
27854 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
27855 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
27856 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
27857 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
27858 * @cfg {String} arrowTooltip The title attribute of the arrow
27860 * Create a new menu button
27861 * @param {String/HTMLElement/Element} renderTo The element to append the button to
27862 * @param {Object} config The config object
27864 Roo.SplitButton = function(renderTo, config){
27865 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
27867 * @event arrowclick
27868 * Fires when this button's arrow is clicked
27869 * @param {SplitButton} this
27870 * @param {EventObject} e The click event
27872 this.addEvents({"arrowclick":true});
27875 Roo.extend(Roo.SplitButton, Roo.Button, {
27876 render : function(renderTo){
27877 // this is one sweet looking template!
27878 var tpl = new Roo.Template(
27879 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
27880 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
27881 '<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>',
27882 "</tbody></table></td><td>",
27883 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
27884 '<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>',
27885 "</tbody></table></td></tr></table>"
27887 var btn = tpl.append(renderTo, [this.text, this.type], true);
27888 var btnEl = btn.child("button");
27890 btn.addClass(this.cls);
27893 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27896 btnEl.addClass(this.iconCls);
27898 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27902 if(this.handleMouseEvents){
27903 btn.on("mouseover", this.onMouseOver, this);
27904 btn.on("mouseout", this.onMouseOut, this);
27905 btn.on("mousedown", this.onMouseDown, this);
27906 btn.on("mouseup", this.onMouseUp, this);
27908 btn.on(this.clickEvent, this.onClick, this);
27910 if(typeof this.tooltip == 'object'){
27911 Roo.QuickTips.tips(Roo.apply({
27915 btnEl.dom[this.tooltipType] = this.tooltip;
27918 if(this.arrowTooltip){
27919 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
27928 this.el.addClass("x-btn-pressed");
27930 if(Roo.isIE && !Roo.isIE7){
27931 this.autoWidth.defer(1, this);
27936 this.menu.on("show", this.onMenuShow, this);
27937 this.menu.on("hide", this.onMenuHide, this);
27939 this.fireEvent('render', this);
27943 autoWidth : function(){
27945 var tbl = this.el.child("table:first");
27946 var tbl2 = this.el.child("table:last");
27947 this.el.setWidth("auto");
27948 tbl.setWidth("auto");
27949 if(Roo.isIE7 && Roo.isStrict){
27950 var ib = this.el.child('button:first');
27951 if(ib && ib.getWidth() > 20){
27953 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27958 this.el.beginMeasure();
27960 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
27961 tbl.setWidth(this.minWidth-tbl2.getWidth());
27964 this.el.endMeasure();
27967 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
27971 * Sets this button's click handler
27972 * @param {Function} handler The function to call when the button is clicked
27973 * @param {Object} scope (optional) Scope for the function passed above
27975 setHandler : function(handler, scope){
27976 this.handler = handler;
27977 this.scope = scope;
27981 * Sets this button's arrow click handler
27982 * @param {Function} handler The function to call when the arrow is clicked
27983 * @param {Object} scope (optional) Scope for the function passed above
27985 setArrowHandler : function(handler, scope){
27986 this.arrowHandler = handler;
27987 this.scope = scope;
27993 focus : function(){
27995 this.el.child("button:first").focus();
28000 onClick : function(e){
28001 e.preventDefault();
28002 if(!this.disabled){
28003 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28004 if(this.menu && !this.menu.isVisible()){
28005 this.menu.show(this.el, this.menuAlign);
28007 this.fireEvent("arrowclick", this, e);
28008 if(this.arrowHandler){
28009 this.arrowHandler.call(this.scope || this, this, e);
28012 this.fireEvent("click", this, e);
28014 this.handler.call(this.scope || this, this, e);
28020 onMouseDown : function(e){
28021 if(!this.disabled){
28022 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28026 onMouseUp : function(e){
28027 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28032 // backwards compat
28033 Roo.MenuButton = Roo.SplitButton;/*
28035 * Ext JS Library 1.1.1
28036 * Copyright(c) 2006-2007, Ext JS, LLC.
28038 * Originally Released Under LGPL - original licence link has changed is not relivant.
28041 * <script type="text/javascript">
28045 * @class Roo.Toolbar
28046 * Basic Toolbar class.
28048 * Creates a new Toolbar
28049 * @param {Object} container The config object
28051 Roo.Toolbar = function(container, buttons, config)
28053 /// old consturctor format still supported..
28054 if(container instanceof Array){ // omit the container for later rendering
28055 buttons = container;
28059 if (typeof(container) == 'object' && container.xtype) {
28060 config = container;
28061 container = config.container;
28062 buttons = config.buttons || []; // not really - use items!!
28065 if (config && config.items) {
28066 xitems = config.items;
28067 delete config.items;
28069 Roo.apply(this, config);
28070 this.buttons = buttons;
28073 this.render(container);
28075 this.xitems = xitems;
28076 Roo.each(xitems, function(b) {
28082 Roo.Toolbar.prototype = {
28084 * @cfg {Array} items
28085 * array of button configs or elements to add (will be converted to a MixedCollection)
28089 * @cfg {String/HTMLElement/Element} container
28090 * The id or element that will contain the toolbar
28093 render : function(ct){
28094 this.el = Roo.get(ct);
28096 this.el.addClass(this.cls);
28098 // using a table allows for vertical alignment
28099 // 100% width is needed by Safari...
28100 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28101 this.tr = this.el.child("tr", true);
28103 this.items = new Roo.util.MixedCollection(false, function(o){
28104 return o.id || ("item" + (++autoId));
28107 this.add.apply(this, this.buttons);
28108 delete this.buttons;
28113 * Adds element(s) to the toolbar -- this function takes a variable number of
28114 * arguments of mixed type and adds them to the toolbar.
28115 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28117 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28118 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28119 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28120 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28121 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28122 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28123 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28124 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28125 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28127 * @param {Mixed} arg2
28128 * @param {Mixed} etc.
28131 var a = arguments, l = a.length;
28132 for(var i = 0; i < l; i++){
28137 _add : function(el) {
28140 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28143 if (el.applyTo){ // some kind of form field
28144 return this.addField(el);
28146 if (el.render){ // some kind of Toolbar.Item
28147 return this.addItem(el);
28149 if (typeof el == "string"){ // string
28150 if(el == "separator" || el == "-"){
28151 return this.addSeparator();
28154 return this.addSpacer();
28157 return this.addFill();
28159 return this.addText(el);
28162 if(el.tagName){ // element
28163 return this.addElement(el);
28165 if(typeof el == "object"){ // must be button config?
28166 return this.addButton(el);
28168 // and now what?!?!
28174 * Add an Xtype element
28175 * @param {Object} xtype Xtype Object
28176 * @return {Object} created Object
28178 addxtype : function(e){
28179 return this.add(e);
28183 * Returns the Element for this toolbar.
28184 * @return {Roo.Element}
28186 getEl : function(){
28192 * @return {Roo.Toolbar.Item} The separator item
28194 addSeparator : function(){
28195 return this.addItem(new Roo.Toolbar.Separator());
28199 * Adds a spacer element
28200 * @return {Roo.Toolbar.Spacer} The spacer item
28202 addSpacer : function(){
28203 return this.addItem(new Roo.Toolbar.Spacer());
28207 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28208 * @return {Roo.Toolbar.Fill} The fill item
28210 addFill : function(){
28211 return this.addItem(new Roo.Toolbar.Fill());
28215 * Adds any standard HTML element to the toolbar
28216 * @param {String/HTMLElement/Element} el The element or id of the element to add
28217 * @return {Roo.Toolbar.Item} The element's item
28219 addElement : function(el){
28220 return this.addItem(new Roo.Toolbar.Item(el));
28223 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28224 * @type Roo.util.MixedCollection
28229 * Adds any Toolbar.Item or subclass
28230 * @param {Roo.Toolbar.Item} item
28231 * @return {Roo.Toolbar.Item} The item
28233 addItem : function(item){
28234 var td = this.nextBlock();
28236 this.items.add(item);
28241 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28242 * @param {Object/Array} config A button config or array of configs
28243 * @return {Roo.Toolbar.Button/Array}
28245 addButton : function(config){
28246 if(config instanceof Array){
28248 for(var i = 0, len = config.length; i < len; i++) {
28249 buttons.push(this.addButton(config[i]));
28254 if(!(config instanceof Roo.Toolbar.Button)){
28256 new Roo.Toolbar.SplitButton(config) :
28257 new Roo.Toolbar.Button(config);
28259 var td = this.nextBlock();
28266 * Adds text to the toolbar
28267 * @param {String} text The text to add
28268 * @return {Roo.Toolbar.Item} The element's item
28270 addText : function(text){
28271 return this.addItem(new Roo.Toolbar.TextItem(text));
28275 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28276 * @param {Number} index The index where the item is to be inserted
28277 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28278 * @return {Roo.Toolbar.Button/Item}
28280 insertButton : function(index, item){
28281 if(item instanceof Array){
28283 for(var i = 0, len = item.length; i < len; i++) {
28284 buttons.push(this.insertButton(index + i, item[i]));
28288 if (!(item instanceof Roo.Toolbar.Button)){
28289 item = new Roo.Toolbar.Button(item);
28291 var td = document.createElement("td");
28292 this.tr.insertBefore(td, this.tr.childNodes[index]);
28294 this.items.insert(index, item);
28299 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28300 * @param {Object} config
28301 * @return {Roo.Toolbar.Item} The element's item
28303 addDom : function(config, returnEl){
28304 var td = this.nextBlock();
28305 Roo.DomHelper.overwrite(td, config);
28306 var ti = new Roo.Toolbar.Item(td.firstChild);
28308 this.items.add(ti);
28313 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28314 * @type Roo.util.MixedCollection
28319 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28320 * Note: the field should not have been rendered yet. For a field that has already been
28321 * rendered, use {@link #addElement}.
28322 * @param {Roo.form.Field} field
28323 * @return {Roo.ToolbarItem}
28327 addField : function(field) {
28328 if (!this.fields) {
28330 this.fields = new Roo.util.MixedCollection(false, function(o){
28331 return o.id || ("item" + (++autoId));
28336 var td = this.nextBlock();
28338 var ti = new Roo.Toolbar.Item(td.firstChild);
28340 this.items.add(ti);
28341 this.fields.add(field);
28352 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28353 this.el.child('div').hide();
28361 this.el.child('div').show();
28365 nextBlock : function(){
28366 var td = document.createElement("td");
28367 this.tr.appendChild(td);
28372 destroy : function(){
28373 if(this.items){ // rendered?
28374 Roo.destroy.apply(Roo, this.items.items);
28376 if(this.fields){ // rendered?
28377 Roo.destroy.apply(Roo, this.fields.items);
28379 Roo.Element.uncache(this.el, this.tr);
28384 * @class Roo.Toolbar.Item
28385 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28387 * Creates a new Item
28388 * @param {HTMLElement} el
28390 Roo.Toolbar.Item = function(el){
28391 this.el = Roo.getDom(el);
28392 this.id = Roo.id(this.el);
28393 this.hidden = false;
28396 Roo.Toolbar.Item.prototype = {
28399 * Get this item's HTML Element
28400 * @return {HTMLElement}
28402 getEl : function(){
28407 render : function(td){
28409 td.appendChild(this.el);
28413 * Removes and destroys this item.
28415 destroy : function(){
28416 this.td.parentNode.removeChild(this.td);
28423 this.hidden = false;
28424 this.td.style.display = "";
28431 this.hidden = true;
28432 this.td.style.display = "none";
28436 * Convenience function for boolean show/hide.
28437 * @param {Boolean} visible true to show/false to hide
28439 setVisible: function(visible){
28448 * Try to focus this item.
28450 focus : function(){
28451 Roo.fly(this.el).focus();
28455 * Disables this item.
28457 disable : function(){
28458 Roo.fly(this.td).addClass("x-item-disabled");
28459 this.disabled = true;
28460 this.el.disabled = true;
28464 * Enables this item.
28466 enable : function(){
28467 Roo.fly(this.td).removeClass("x-item-disabled");
28468 this.disabled = false;
28469 this.el.disabled = false;
28475 * @class Roo.Toolbar.Separator
28476 * @extends Roo.Toolbar.Item
28477 * A simple toolbar separator class
28479 * Creates a new Separator
28481 Roo.Toolbar.Separator = function(){
28482 var s = document.createElement("span");
28483 s.className = "ytb-sep";
28484 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
28486 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28487 enable:Roo.emptyFn,
28488 disable:Roo.emptyFn,
28493 * @class Roo.Toolbar.Spacer
28494 * @extends Roo.Toolbar.Item
28495 * A simple element that adds extra horizontal space to a toolbar.
28497 * Creates a new Spacer
28499 Roo.Toolbar.Spacer = function(){
28500 var s = document.createElement("div");
28501 s.className = "ytb-spacer";
28502 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
28504 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28505 enable:Roo.emptyFn,
28506 disable:Roo.emptyFn,
28511 * @class Roo.Toolbar.Fill
28512 * @extends Roo.Toolbar.Spacer
28513 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28515 * Creates a new Spacer
28517 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28519 render : function(td){
28520 td.style.width = '100%';
28521 Roo.Toolbar.Fill.superclass.render.call(this, td);
28526 * @class Roo.Toolbar.TextItem
28527 * @extends Roo.Toolbar.Item
28528 * A simple class that renders text directly into a toolbar.
28530 * Creates a new TextItem
28531 * @param {String} text
28533 Roo.Toolbar.TextItem = function(text){
28534 if (typeof(text) == 'object') {
28537 var s = document.createElement("span");
28538 s.className = "ytb-text";
28539 s.innerHTML = text;
28540 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
28542 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28543 enable:Roo.emptyFn,
28544 disable:Roo.emptyFn,
28549 * @class Roo.Toolbar.Button
28550 * @extends Roo.Button
28551 * A button that renders into a toolbar.
28553 * Creates a new Button
28554 * @param {Object} config A standard {@link Roo.Button} config object
28556 Roo.Toolbar.Button = function(config){
28557 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28559 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28560 render : function(td){
28562 Roo.Toolbar.Button.superclass.render.call(this, td);
28566 * Removes and destroys this button
28568 destroy : function(){
28569 Roo.Toolbar.Button.superclass.destroy.call(this);
28570 this.td.parentNode.removeChild(this.td);
28574 * Shows this button
28577 this.hidden = false;
28578 this.td.style.display = "";
28582 * Hides this button
28585 this.hidden = true;
28586 this.td.style.display = "none";
28590 * Disables this item
28592 disable : function(){
28593 Roo.fly(this.td).addClass("x-item-disabled");
28594 this.disabled = true;
28598 * Enables this item
28600 enable : function(){
28601 Roo.fly(this.td).removeClass("x-item-disabled");
28602 this.disabled = false;
28605 // backwards compat
28606 Roo.ToolbarButton = Roo.Toolbar.Button;
28609 * @class Roo.Toolbar.SplitButton
28610 * @extends Roo.SplitButton
28611 * A menu button that renders into a toolbar.
28613 * Creates a new SplitButton
28614 * @param {Object} config A standard {@link Roo.SplitButton} config object
28616 Roo.Toolbar.SplitButton = function(config){
28617 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28619 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28620 render : function(td){
28622 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28626 * Removes and destroys this button
28628 destroy : function(){
28629 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28630 this.td.parentNode.removeChild(this.td);
28634 * Shows this button
28637 this.hidden = false;
28638 this.td.style.display = "";
28642 * Hides this button
28645 this.hidden = true;
28646 this.td.style.display = "none";
28650 // backwards compat
28651 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28653 * Ext JS Library 1.1.1
28654 * Copyright(c) 2006-2007, Ext JS, LLC.
28656 * Originally Released Under LGPL - original licence link has changed is not relivant.
28659 * <script type="text/javascript">
28663 * @class Roo.PagingToolbar
28664 * @extends Roo.Toolbar
28665 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28667 * Create a new PagingToolbar
28668 * @param {Object} config The config object
28670 Roo.PagingToolbar = function(el, ds, config)
28672 // old args format still supported... - xtype is prefered..
28673 if (typeof(el) == 'object' && el.xtype) {
28674 // created from xtype...
28676 ds = el.dataSource;
28677 el = config.container;
28680 if (config.items) {
28681 items = config.items;
28685 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28688 this.renderButtons(this.el);
28691 // supprot items array.
28693 Roo.each(items, function(e) {
28694 this.add(Roo.factory(e));
28699 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28701 * @cfg {Roo.data.Store} dataSource
28702 * The underlying data store providing the paged data
28705 * @cfg {String/HTMLElement/Element} container
28706 * container The id or element that will contain the toolbar
28709 * @cfg {Boolean} displayInfo
28710 * True to display the displayMsg (defaults to false)
28713 * @cfg {Number} pageSize
28714 * The number of records to display per page (defaults to 20)
28718 * @cfg {String} displayMsg
28719 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28721 displayMsg : 'Displaying {0} - {1} of {2}',
28723 * @cfg {String} emptyMsg
28724 * The message to display when no records are found (defaults to "No data to display")
28726 emptyMsg : 'No data to display',
28728 * Customizable piece of the default paging text (defaults to "Page")
28731 beforePageText : "Page",
28733 * Customizable piece of the default paging text (defaults to "of %0")
28736 afterPageText : "of {0}",
28738 * Customizable piece of the default paging text (defaults to "First Page")
28741 firstText : "First Page",
28743 * Customizable piece of the default paging text (defaults to "Previous Page")
28746 prevText : "Previous Page",
28748 * Customizable piece of the default paging text (defaults to "Next Page")
28751 nextText : "Next Page",
28753 * Customizable piece of the default paging text (defaults to "Last Page")
28756 lastText : "Last Page",
28758 * Customizable piece of the default paging text (defaults to "Refresh")
28761 refreshText : "Refresh",
28764 renderButtons : function(el){
28765 Roo.PagingToolbar.superclass.render.call(this, el);
28766 this.first = this.addButton({
28767 tooltip: this.firstText,
28768 cls: "x-btn-icon x-grid-page-first",
28770 handler: this.onClick.createDelegate(this, ["first"])
28772 this.prev = this.addButton({
28773 tooltip: this.prevText,
28774 cls: "x-btn-icon x-grid-page-prev",
28776 handler: this.onClick.createDelegate(this, ["prev"])
28778 //this.addSeparator();
28779 this.add(this.beforePageText);
28780 this.field = Roo.get(this.addDom({
28785 cls: "x-grid-page-number"
28787 this.field.on("keydown", this.onPagingKeydown, this);
28788 this.field.on("focus", function(){this.dom.select();});
28789 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28790 this.field.setHeight(18);
28791 //this.addSeparator();
28792 this.next = this.addButton({
28793 tooltip: this.nextText,
28794 cls: "x-btn-icon x-grid-page-next",
28796 handler: this.onClick.createDelegate(this, ["next"])
28798 this.last = this.addButton({
28799 tooltip: this.lastText,
28800 cls: "x-btn-icon x-grid-page-last",
28802 handler: this.onClick.createDelegate(this, ["last"])
28804 //this.addSeparator();
28805 this.loading = this.addButton({
28806 tooltip: this.refreshText,
28807 cls: "x-btn-icon x-grid-loading",
28808 handler: this.onClick.createDelegate(this, ["refresh"])
28811 if(this.displayInfo){
28812 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
28817 updateInfo : function(){
28818 if(this.displayEl){
28819 var count = this.ds.getCount();
28820 var msg = count == 0 ?
28824 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
28826 this.displayEl.update(msg);
28831 onLoad : function(ds, r, o){
28832 this.cursor = o.params ? o.params.start : 0;
28833 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
28835 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
28836 this.field.dom.value = ap;
28837 this.first.setDisabled(ap == 1);
28838 this.prev.setDisabled(ap == 1);
28839 this.next.setDisabled(ap == ps);
28840 this.last.setDisabled(ap == ps);
28841 this.loading.enable();
28846 getPageData : function(){
28847 var total = this.ds.getTotalCount();
28850 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
28851 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
28856 onLoadError : function(){
28857 this.loading.enable();
28861 onPagingKeydown : function(e){
28862 var k = e.getKey();
28863 var d = this.getPageData();
28865 var v = this.field.dom.value, pageNum;
28866 if(!v || isNaN(pageNum = parseInt(v, 10))){
28867 this.field.dom.value = d.activePage;
28870 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
28871 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28874 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))
28876 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
28877 this.field.dom.value = pageNum;
28878 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
28881 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28883 var v = this.field.dom.value, pageNum;
28884 var increment = (e.shiftKey) ? 10 : 1;
28885 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
28887 if(!v || isNaN(pageNum = parseInt(v, 10))) {
28888 this.field.dom.value = d.activePage;
28891 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
28893 this.field.dom.value = parseInt(v, 10) + increment;
28894 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
28895 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
28902 beforeLoad : function(){
28904 this.loading.disable();
28909 onClick : function(which){
28913 ds.load({params:{start: 0, limit: this.pageSize}});
28916 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
28919 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
28922 var total = ds.getTotalCount();
28923 var extra = total % this.pageSize;
28924 var lastStart = extra ? (total - extra) : total-this.pageSize;
28925 ds.load({params:{start: lastStart, limit: this.pageSize}});
28928 ds.load({params:{start: this.cursor, limit: this.pageSize}});
28934 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
28935 * @param {Roo.data.Store} store The data store to unbind
28937 unbind : function(ds){
28938 ds.un("beforeload", this.beforeLoad, this);
28939 ds.un("load", this.onLoad, this);
28940 ds.un("loadexception", this.onLoadError, this);
28941 ds.un("remove", this.updateInfo, this);
28942 ds.un("add", this.updateInfo, this);
28943 this.ds = undefined;
28947 * Binds the paging toolbar to the specified {@link Roo.data.Store}
28948 * @param {Roo.data.Store} store The data store to bind
28950 bind : function(ds){
28951 ds.on("beforeload", this.beforeLoad, this);
28952 ds.on("load", this.onLoad, this);
28953 ds.on("loadexception", this.onLoadError, this);
28954 ds.on("remove", this.updateInfo, this);
28955 ds.on("add", this.updateInfo, this);
28960 * Ext JS Library 1.1.1
28961 * Copyright(c) 2006-2007, Ext JS, LLC.
28963 * Originally Released Under LGPL - original licence link has changed is not relivant.
28966 * <script type="text/javascript">
28970 * @class Roo.Resizable
28971 * @extends Roo.util.Observable
28972 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
28973 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
28974 * 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
28975 * the element will be wrapped for you automatically.</p>
28976 * <p>Here is the list of valid resize handles:</p>
28979 ------ -------------------
28988 'hd' horizontal drag
28991 * <p>Here's an example showing the creation of a typical Resizable:</p>
28993 var resizer = new Roo.Resizable("element-id", {
29001 resizer.on("resize", myHandler);
29003 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29004 * resizer.east.setDisplayed(false);</p>
29005 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29006 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29007 * resize operation's new size (defaults to [0, 0])
29008 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29009 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29010 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29011 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29012 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29013 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29014 * @cfg {Number} width The width of the element in pixels (defaults to null)
29015 * @cfg {Number} height The height of the element in pixels (defaults to null)
29016 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29017 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29018 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29019 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29020 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29021 * in favor of the handles config option (defaults to false)
29022 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29023 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29024 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29025 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29026 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29027 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29028 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29029 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29030 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29031 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29032 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29034 * Create a new resizable component
29035 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29036 * @param {Object} config configuration options
29038 Roo.Resizable = function(el, config)
29040 this.el = Roo.get(el);
29042 if(config && config.wrap){
29043 config.resizeChild = this.el;
29044 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29045 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29046 this.el.setStyle("overflow", "hidden");
29047 this.el.setPositioning(config.resizeChild.getPositioning());
29048 config.resizeChild.clearPositioning();
29049 if(!config.width || !config.height){
29050 var csize = config.resizeChild.getSize();
29051 this.el.setSize(csize.width, csize.height);
29053 if(config.pinned && !config.adjustments){
29054 config.adjustments = "auto";
29058 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29059 this.proxy.unselectable();
29060 this.proxy.enableDisplayMode('block');
29062 Roo.apply(this, config);
29065 this.disableTrackOver = true;
29066 this.el.addClass("x-resizable-pinned");
29068 // if the element isn't positioned, make it relative
29069 var position = this.el.getStyle("position");
29070 if(position != "absolute" && position != "fixed"){
29071 this.el.setStyle("position", "relative");
29073 if(!this.handles){ // no handles passed, must be legacy style
29074 this.handles = 's,e,se';
29075 if(this.multiDirectional){
29076 this.handles += ',n,w';
29079 if(this.handles == "all"){
29080 this.handles = "n s e w ne nw se sw";
29082 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29083 var ps = Roo.Resizable.positions;
29084 for(var i = 0, len = hs.length; i < len; i++){
29085 if(hs[i] && ps[hs[i]]){
29086 var pos = ps[hs[i]];
29087 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29091 this.corner = this.southeast;
29093 // updateBox = the box can move..
29094 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29095 this.updateBox = true;
29098 this.activeHandle = null;
29100 if(this.resizeChild){
29101 if(typeof this.resizeChild == "boolean"){
29102 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29104 this.resizeChild = Roo.get(this.resizeChild, true);
29108 if(this.adjustments == "auto"){
29109 var rc = this.resizeChild;
29110 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29111 if(rc && (hw || hn)){
29112 rc.position("relative");
29113 rc.setLeft(hw ? hw.el.getWidth() : 0);
29114 rc.setTop(hn ? hn.el.getHeight() : 0);
29116 this.adjustments = [
29117 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29118 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29122 if(this.draggable){
29123 this.dd = this.dynamic ?
29124 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29125 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29131 * @event beforeresize
29132 * Fired before resize is allowed. Set enabled to false to cancel resize.
29133 * @param {Roo.Resizable} this
29134 * @param {Roo.EventObject} e The mousedown event
29136 "beforeresize" : true,
29139 * Fired a resizing.
29140 * @param {Roo.Resizable} this
29141 * @param {Number} x The new x position
29142 * @param {Number} y The new y position
29143 * @param {Number} w The new w width
29144 * @param {Number} h The new h hight
29145 * @param {Roo.EventObject} e The mouseup event
29150 * Fired after a resize.
29151 * @param {Roo.Resizable} this
29152 * @param {Number} width The new width
29153 * @param {Number} height The new height
29154 * @param {Roo.EventObject} e The mouseup event
29159 if(this.width !== null && this.height !== null){
29160 this.resizeTo(this.width, this.height);
29162 this.updateChildSize();
29165 this.el.dom.style.zoom = 1;
29167 Roo.Resizable.superclass.constructor.call(this);
29170 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29171 resizeChild : false,
29172 adjustments : [0, 0],
29182 multiDirectional : false,
29183 disableTrackOver : false,
29184 easing : 'easeOutStrong',
29185 widthIncrement : 0,
29186 heightIncrement : 0,
29190 preserveRatio : false,
29191 transparent: false,
29197 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29199 constrainTo: undefined,
29201 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29203 resizeRegion: undefined,
29207 * Perform a manual resize
29208 * @param {Number} width
29209 * @param {Number} height
29211 resizeTo : function(width, height){
29212 this.el.setSize(width, height);
29213 this.updateChildSize();
29214 this.fireEvent("resize", this, width, height, null);
29218 startSizing : function(e, handle){
29219 this.fireEvent("beforeresize", this, e);
29220 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29223 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29224 this.overlay.unselectable();
29225 this.overlay.enableDisplayMode("block");
29226 this.overlay.on("mousemove", this.onMouseMove, this);
29227 this.overlay.on("mouseup", this.onMouseUp, this);
29229 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29231 this.resizing = true;
29232 this.startBox = this.el.getBox();
29233 this.startPoint = e.getXY();
29234 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29235 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29237 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29238 this.overlay.show();
29240 if(this.constrainTo) {
29241 var ct = Roo.get(this.constrainTo);
29242 this.resizeRegion = ct.getRegion().adjust(
29243 ct.getFrameWidth('t'),
29244 ct.getFrameWidth('l'),
29245 -ct.getFrameWidth('b'),
29246 -ct.getFrameWidth('r')
29250 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29252 this.proxy.setBox(this.startBox);
29254 this.proxy.setStyle('visibility', 'visible');
29260 onMouseDown : function(handle, e){
29263 this.activeHandle = handle;
29264 this.startSizing(e, handle);
29269 onMouseUp : function(e){
29270 var size = this.resizeElement();
29271 this.resizing = false;
29273 this.overlay.hide();
29275 this.fireEvent("resize", this, size.width, size.height, e);
29279 updateChildSize : function(){
29281 if(this.resizeChild){
29283 var child = this.resizeChild;
29284 var adj = this.adjustments;
29285 if(el.dom.offsetWidth){
29286 var b = el.getSize(true);
29287 child.setSize(b.width+adj[0], b.height+adj[1]);
29289 // Second call here for IE
29290 // The first call enables instant resizing and
29291 // the second call corrects scroll bars if they
29294 setTimeout(function(){
29295 if(el.dom.offsetWidth){
29296 var b = el.getSize(true);
29297 child.setSize(b.width+adj[0], b.height+adj[1]);
29305 snap : function(value, inc, min){
29306 if(!inc || !value) return value;
29307 var newValue = value;
29308 var m = value % inc;
29311 newValue = value + (inc-m);
29313 newValue = value - m;
29316 return Math.max(min, newValue);
29320 resizeElement : function(){
29321 var box = this.proxy.getBox();
29322 if(this.updateBox){
29323 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29325 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29327 this.updateChildSize();
29335 constrain : function(v, diff, m, mx){
29338 }else if(v - diff > mx){
29345 onMouseMove : function(e){
29348 try{// try catch so if something goes wrong the user doesn't get hung
29350 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29354 //var curXY = this.startPoint;
29355 var curSize = this.curSize || this.startBox;
29356 var x = this.startBox.x, y = this.startBox.y;
29357 var ox = x, oy = y;
29358 var w = curSize.width, h = curSize.height;
29359 var ow = w, oh = h;
29360 var mw = this.minWidth, mh = this.minHeight;
29361 var mxw = this.maxWidth, mxh = this.maxHeight;
29362 var wi = this.widthIncrement;
29363 var hi = this.heightIncrement;
29365 var eventXY = e.getXY();
29366 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29367 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29369 var pos = this.activeHandle.position;
29374 w = Math.min(Math.max(mw, w), mxw);
29379 h = Math.min(Math.max(mh, h), mxh);
29384 w = Math.min(Math.max(mw, w), mxw);
29385 h = Math.min(Math.max(mh, h), mxh);
29388 diffY = this.constrain(h, diffY, mh, mxh);
29395 var adiffX = Math.abs(diffX);
29396 var sub = (adiffX % wi); // how much
29397 if (sub > (wi/2)) { // far enough to snap
29398 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29400 // remove difference..
29401 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29405 x = Math.max(this.minX, x);
29408 diffX = this.constrain(w, diffX, mw, mxw);
29414 w = Math.min(Math.max(mw, w), mxw);
29415 diffY = this.constrain(h, diffY, mh, mxh);
29420 diffX = this.constrain(w, diffX, mw, mxw);
29421 diffY = this.constrain(h, diffY, mh, mxh);
29428 diffX = this.constrain(w, diffX, mw, mxw);
29430 h = Math.min(Math.max(mh, h), mxh);
29436 var sw = this.snap(w, wi, mw);
29437 var sh = this.snap(h, hi, mh);
29438 if(sw != w || sh != h){
29461 if(this.preserveRatio){
29466 h = Math.min(Math.max(mh, h), mxh);
29471 w = Math.min(Math.max(mw, w), mxw);
29476 w = Math.min(Math.max(mw, w), mxw);
29482 w = Math.min(Math.max(mw, w), mxw);
29488 h = Math.min(Math.max(mh, h), mxh);
29496 h = Math.min(Math.max(mh, h), mxh);
29506 h = Math.min(Math.max(mh, h), mxh);
29514 if (pos == 'hdrag') {
29517 this.proxy.setBounds(x, y, w, h);
29519 this.resizeElement();
29523 this.fireEvent("resizing", this, x, y, w, h, e);
29527 handleOver : function(){
29529 this.el.addClass("x-resizable-over");
29534 handleOut : function(){
29535 if(!this.resizing){
29536 this.el.removeClass("x-resizable-over");
29541 * Returns the element this component is bound to.
29542 * @return {Roo.Element}
29544 getEl : function(){
29549 * Returns the resizeChild element (or null).
29550 * @return {Roo.Element}
29552 getResizeChild : function(){
29553 return this.resizeChild;
29555 groupHandler : function()
29560 * Destroys this resizable. If the element was wrapped and
29561 * removeEl is not true then the element remains.
29562 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29564 destroy : function(removeEl){
29565 this.proxy.remove();
29567 this.overlay.removeAllListeners();
29568 this.overlay.remove();
29570 var ps = Roo.Resizable.positions;
29572 if(typeof ps[k] != "function" && this[ps[k]]){
29573 var h = this[ps[k]];
29574 h.el.removeAllListeners();
29579 this.el.update("");
29586 // hash to map config positions to true positions
29587 Roo.Resizable.positions = {
29588 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29593 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29595 // only initialize the template if resizable is used
29596 var tpl = Roo.DomHelper.createTemplate(
29597 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29600 Roo.Resizable.Handle.prototype.tpl = tpl;
29602 this.position = pos;
29604 // show north drag fro topdra
29605 var handlepos = pos == 'hdrag' ? 'north' : pos;
29607 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29608 if (pos == 'hdrag') {
29609 this.el.setStyle('cursor', 'pointer');
29611 this.el.unselectable();
29613 this.el.setOpacity(0);
29615 this.el.on("mousedown", this.onMouseDown, this);
29616 if(!disableTrackOver){
29617 this.el.on("mouseover", this.onMouseOver, this);
29618 this.el.on("mouseout", this.onMouseOut, this);
29623 Roo.Resizable.Handle.prototype = {
29624 afterResize : function(rz){
29629 onMouseDown : function(e){
29630 this.rz.onMouseDown(this, e);
29633 onMouseOver : function(e){
29634 this.rz.handleOver(this, e);
29637 onMouseOut : function(e){
29638 this.rz.handleOut(this, e);
29642 * Ext JS Library 1.1.1
29643 * Copyright(c) 2006-2007, Ext JS, LLC.
29645 * Originally Released Under LGPL - original licence link has changed is not relivant.
29648 * <script type="text/javascript">
29652 * @class Roo.Editor
29653 * @extends Roo.Component
29654 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29656 * Create a new Editor
29657 * @param {Roo.form.Field} field The Field object (or descendant)
29658 * @param {Object} config The config object
29660 Roo.Editor = function(field, config){
29661 Roo.Editor.superclass.constructor.call(this, config);
29662 this.field = field;
29665 * @event beforestartedit
29666 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29667 * false from the handler of this event.
29668 * @param {Editor} this
29669 * @param {Roo.Element} boundEl The underlying element bound to this editor
29670 * @param {Mixed} value The field value being set
29672 "beforestartedit" : true,
29675 * Fires when this editor is displayed
29676 * @param {Roo.Element} boundEl The underlying element bound to this editor
29677 * @param {Mixed} value The starting field value
29679 "startedit" : true,
29681 * @event beforecomplete
29682 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29683 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29684 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29685 * event will not fire since no edit actually occurred.
29686 * @param {Editor} this
29687 * @param {Mixed} value The current field value
29688 * @param {Mixed} startValue The original field value
29690 "beforecomplete" : true,
29693 * Fires after editing is complete and any changed value has been written to the underlying field.
29694 * @param {Editor} this
29695 * @param {Mixed} value The current field value
29696 * @param {Mixed} startValue The original field value
29700 * @event specialkey
29701 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29702 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29703 * @param {Roo.form.Field} this
29704 * @param {Roo.EventObject} e The event object
29706 "specialkey" : true
29710 Roo.extend(Roo.Editor, Roo.Component, {
29712 * @cfg {Boolean/String} autosize
29713 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29714 * or "height" to adopt the height only (defaults to false)
29717 * @cfg {Boolean} revertInvalid
29718 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29719 * validation fails (defaults to true)
29722 * @cfg {Boolean} ignoreNoChange
29723 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29724 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29725 * will never be ignored.
29728 * @cfg {Boolean} hideEl
29729 * False to keep the bound element visible while the editor is displayed (defaults to true)
29732 * @cfg {Mixed} value
29733 * The data value of the underlying field (defaults to "")
29737 * @cfg {String} alignment
29738 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29742 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29743 * for bottom-right shadow (defaults to "frame")
29747 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29751 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29753 completeOnEnter : false,
29755 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29757 cancelOnEsc : false,
29759 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29764 onRender : function(ct, position){
29765 this.el = new Roo.Layer({
29766 shadow: this.shadow,
29772 constrain: this.constrain
29774 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29775 if(this.field.msgTarget != 'title'){
29776 this.field.msgTarget = 'qtip';
29778 this.field.render(this.el);
29780 this.field.el.dom.setAttribute('autocomplete', 'off');
29782 this.field.on("specialkey", this.onSpecialKey, this);
29783 if(this.swallowKeys){
29784 this.field.el.swallowEvent(['keydown','keypress']);
29787 this.field.on("blur", this.onBlur, this);
29788 if(this.field.grow){
29789 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29793 onSpecialKey : function(field, e)
29795 //Roo.log('editor onSpecialKey');
29796 if(this.completeOnEnter && e.getKey() == e.ENTER){
29798 this.completeEdit();
29801 // do not fire special key otherwise it might hide close the editor...
29802 if(e.getKey() == e.ENTER){
29805 if(this.cancelOnEsc && e.getKey() == e.ESC){
29809 this.fireEvent('specialkey', field, e);
29814 * Starts the editing process and shows the editor.
29815 * @param {String/HTMLElement/Element} el The element to edit
29816 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
29817 * to the innerHTML of el.
29819 startEdit : function(el, value){
29821 this.completeEdit();
29823 this.boundEl = Roo.get(el);
29824 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
29825 if(!this.rendered){
29826 this.render(this.parentEl || document.body);
29828 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
29831 this.startValue = v;
29832 this.field.setValue(v);
29834 var sz = this.boundEl.getSize();
29835 switch(this.autoSize){
29837 this.setSize(sz.width, "");
29840 this.setSize("", sz.height);
29843 this.setSize(sz.width, sz.height);
29846 this.el.alignTo(this.boundEl, this.alignment);
29847 this.editing = true;
29849 Roo.QuickTips.disable();
29855 * Sets the height and width of this editor.
29856 * @param {Number} width The new width
29857 * @param {Number} height The new height
29859 setSize : function(w, h){
29860 this.field.setSize(w, h);
29867 * Realigns the editor to the bound field based on the current alignment config value.
29869 realign : function(){
29870 this.el.alignTo(this.boundEl, this.alignment);
29874 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
29875 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
29877 completeEdit : function(remainVisible){
29881 var v = this.getValue();
29882 if(this.revertInvalid !== false && !this.field.isValid()){
29883 v = this.startValue;
29884 this.cancelEdit(true);
29886 if(String(v) === String(this.startValue) && this.ignoreNoChange){
29887 this.editing = false;
29891 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
29892 this.editing = false;
29893 if(this.updateEl && this.boundEl){
29894 this.boundEl.update(v);
29896 if(remainVisible !== true){
29899 this.fireEvent("complete", this, v, this.startValue);
29904 onShow : function(){
29906 if(this.hideEl !== false){
29907 this.boundEl.hide();
29910 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
29911 this.fixIEFocus = true;
29912 this.deferredFocus.defer(50, this);
29914 this.field.focus();
29916 this.fireEvent("startedit", this.boundEl, this.startValue);
29919 deferredFocus : function(){
29921 this.field.focus();
29926 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
29927 * reverted to the original starting value.
29928 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
29929 * cancel (defaults to false)
29931 cancelEdit : function(remainVisible){
29933 this.setValue(this.startValue);
29934 if(remainVisible !== true){
29941 onBlur : function(){
29942 if(this.allowBlur !== true && this.editing){
29943 this.completeEdit();
29948 onHide : function(){
29950 this.completeEdit();
29954 if(this.field.collapse){
29955 this.field.collapse();
29958 if(this.hideEl !== false){
29959 this.boundEl.show();
29962 Roo.QuickTips.enable();
29967 * Sets the data value of the editor
29968 * @param {Mixed} value Any valid value supported by the underlying field
29970 setValue : function(v){
29971 this.field.setValue(v);
29975 * Gets the data value of the editor
29976 * @return {Mixed} The data value
29978 getValue : function(){
29979 return this.field.getValue();
29983 * Ext JS Library 1.1.1
29984 * Copyright(c) 2006-2007, Ext JS, LLC.
29986 * Originally Released Under LGPL - original licence link has changed is not relivant.
29989 * <script type="text/javascript">
29993 * @class Roo.BasicDialog
29994 * @extends Roo.util.Observable
29995 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
29997 var dlg = new Roo.BasicDialog("my-dlg", {
30006 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30007 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30008 dlg.addButton('Cancel', dlg.hide, dlg);
30011 <b>A Dialog should always be a direct child of the body element.</b>
30012 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30013 * @cfg {String} title Default text to display in the title bar (defaults to null)
30014 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30015 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30016 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30017 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30018 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30019 * (defaults to null with no animation)
30020 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30021 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30022 * property for valid values (defaults to 'all')
30023 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30024 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30025 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30026 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30027 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30028 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30029 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30030 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30031 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30032 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30033 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30034 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30035 * draggable = true (defaults to false)
30036 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30037 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30038 * shadow (defaults to false)
30039 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30040 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30041 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30042 * @cfg {Array} buttons Array of buttons
30043 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30045 * Create a new BasicDialog.
30046 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30047 * @param {Object} config Configuration options
30049 Roo.BasicDialog = function(el, config){
30050 this.el = Roo.get(el);
30051 var dh = Roo.DomHelper;
30052 if(!this.el && config && config.autoCreate){
30053 if(typeof config.autoCreate == "object"){
30054 if(!config.autoCreate.id){
30055 config.autoCreate.id = el;
30057 this.el = dh.append(document.body,
30058 config.autoCreate, true);
30060 this.el = dh.append(document.body,
30061 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30065 el.setDisplayed(true);
30066 el.hide = this.hideAction;
30068 el.addClass("x-dlg");
30070 Roo.apply(this, config);
30072 this.proxy = el.createProxy("x-dlg-proxy");
30073 this.proxy.hide = this.hideAction;
30074 this.proxy.setOpacity(.5);
30078 el.setWidth(config.width);
30081 el.setHeight(config.height);
30083 this.size = el.getSize();
30084 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30085 this.xy = [config.x,config.y];
30087 this.xy = el.getCenterXY(true);
30089 /** The header element @type Roo.Element */
30090 this.header = el.child("> .x-dlg-hd");
30091 /** The body element @type Roo.Element */
30092 this.body = el.child("> .x-dlg-bd");
30093 /** The footer element @type Roo.Element */
30094 this.footer = el.child("> .x-dlg-ft");
30097 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30100 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30103 this.header.unselectable();
30105 this.header.update(this.title);
30107 // this element allows the dialog to be focused for keyboard event
30108 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30109 this.focusEl.swallowEvent("click", true);
30111 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30113 // wrap the body and footer for special rendering
30114 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30116 this.bwrap.dom.appendChild(this.footer.dom);
30119 this.bg = this.el.createChild({
30120 tag: "div", cls:"x-dlg-bg",
30121 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30123 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30126 if(this.autoScroll !== false && !this.autoTabs){
30127 this.body.setStyle("overflow", "auto");
30130 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30132 if(this.closable !== false){
30133 this.el.addClass("x-dlg-closable");
30134 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30135 this.close.on("click", this.closeClick, this);
30136 this.close.addClassOnOver("x-dlg-close-over");
30138 if(this.collapsible !== false){
30139 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30140 this.collapseBtn.on("click", this.collapseClick, this);
30141 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30142 this.header.on("dblclick", this.collapseClick, this);
30144 if(this.resizable !== false){
30145 this.el.addClass("x-dlg-resizable");
30146 this.resizer = new Roo.Resizable(el, {
30147 minWidth: this.minWidth || 80,
30148 minHeight:this.minHeight || 80,
30149 handles: this.resizeHandles || "all",
30152 this.resizer.on("beforeresize", this.beforeResize, this);
30153 this.resizer.on("resize", this.onResize, this);
30155 if(this.draggable !== false){
30156 el.addClass("x-dlg-draggable");
30157 if (!this.proxyDrag) {
30158 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30161 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30163 dd.setHandleElId(this.header.id);
30164 dd.endDrag = this.endMove.createDelegate(this);
30165 dd.startDrag = this.startMove.createDelegate(this);
30166 dd.onDrag = this.onDrag.createDelegate(this);
30171 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30172 this.mask.enableDisplayMode("block");
30174 this.el.addClass("x-dlg-modal");
30177 this.shadow = new Roo.Shadow({
30178 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30179 offset : this.shadowOffset
30182 this.shadowOffset = 0;
30184 if(Roo.useShims && this.shim !== false){
30185 this.shim = this.el.createShim();
30186 this.shim.hide = this.hideAction;
30194 if (this.buttons) {
30195 var bts= this.buttons;
30197 Roo.each(bts, function(b) {
30206 * Fires when a key is pressed
30207 * @param {Roo.BasicDialog} this
30208 * @param {Roo.EventObject} e
30213 * Fires when this dialog is moved by the user.
30214 * @param {Roo.BasicDialog} this
30215 * @param {Number} x The new page X
30216 * @param {Number} y The new page Y
30221 * Fires when this dialog is resized by the user.
30222 * @param {Roo.BasicDialog} this
30223 * @param {Number} width The new width
30224 * @param {Number} height The new height
30228 * @event beforehide
30229 * Fires before this dialog is hidden.
30230 * @param {Roo.BasicDialog} this
30232 "beforehide" : true,
30235 * Fires when this dialog is hidden.
30236 * @param {Roo.BasicDialog} this
30240 * @event beforeshow
30241 * Fires before this dialog is shown.
30242 * @param {Roo.BasicDialog} this
30244 "beforeshow" : true,
30247 * Fires when this dialog is shown.
30248 * @param {Roo.BasicDialog} this
30252 el.on("keydown", this.onKeyDown, this);
30253 el.on("mousedown", this.toFront, this);
30254 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30256 Roo.DialogManager.register(this);
30257 Roo.BasicDialog.superclass.constructor.call(this);
30260 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30261 shadowOffset: Roo.isIE ? 6 : 5,
30264 minButtonWidth: 75,
30265 defaultButton: null,
30266 buttonAlign: "right",
30271 * Sets the dialog title text
30272 * @param {String} text The title text to display
30273 * @return {Roo.BasicDialog} this
30275 setTitle : function(text){
30276 this.header.update(text);
30281 closeClick : function(){
30286 collapseClick : function(){
30287 this[this.collapsed ? "expand" : "collapse"]();
30291 * Collapses the dialog to its minimized state (only the title bar is visible).
30292 * Equivalent to the user clicking the collapse dialog button.
30294 collapse : function(){
30295 if(!this.collapsed){
30296 this.collapsed = true;
30297 this.el.addClass("x-dlg-collapsed");
30298 this.restoreHeight = this.el.getHeight();
30299 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30304 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30305 * clicking the expand dialog button.
30307 expand : function(){
30308 if(this.collapsed){
30309 this.collapsed = false;
30310 this.el.removeClass("x-dlg-collapsed");
30311 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30316 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30317 * @return {Roo.TabPanel} The tabs component
30319 initTabs : function(){
30320 var tabs = this.getTabs();
30321 while(tabs.getTab(0)){
30324 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30326 tabs.addTab(Roo.id(dom), dom.title);
30334 beforeResize : function(){
30335 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30339 onResize : function(){
30340 this.refreshSize();
30341 this.syncBodyHeight();
30342 this.adjustAssets();
30344 this.fireEvent("resize", this, this.size.width, this.size.height);
30348 onKeyDown : function(e){
30349 if(this.isVisible()){
30350 this.fireEvent("keydown", this, e);
30355 * Resizes the dialog.
30356 * @param {Number} width
30357 * @param {Number} height
30358 * @return {Roo.BasicDialog} this
30360 resizeTo : function(width, height){
30361 this.el.setSize(width, height);
30362 this.size = {width: width, height: height};
30363 this.syncBodyHeight();
30364 if(this.fixedcenter){
30367 if(this.isVisible()){
30368 this.constrainXY();
30369 this.adjustAssets();
30371 this.fireEvent("resize", this, width, height);
30377 * Resizes the dialog to fit the specified content size.
30378 * @param {Number} width
30379 * @param {Number} height
30380 * @return {Roo.BasicDialog} this
30382 setContentSize : function(w, h){
30383 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30384 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30385 //if(!this.el.isBorderBox()){
30386 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30387 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30390 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30391 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30393 this.resizeTo(w, h);
30398 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30399 * executed in response to a particular key being pressed while the dialog is active.
30400 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30401 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30402 * @param {Function} fn The function to call
30403 * @param {Object} scope (optional) The scope of the function
30404 * @return {Roo.BasicDialog} this
30406 addKeyListener : function(key, fn, scope){
30407 var keyCode, shift, ctrl, alt;
30408 if(typeof key == "object" && !(key instanceof Array)){
30409 keyCode = key["key"];
30410 shift = key["shift"];
30411 ctrl = key["ctrl"];
30416 var handler = function(dlg, e){
30417 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30418 var k = e.getKey();
30419 if(keyCode instanceof Array){
30420 for(var i = 0, len = keyCode.length; i < len; i++){
30421 if(keyCode[i] == k){
30422 fn.call(scope || window, dlg, k, e);
30428 fn.call(scope || window, dlg, k, e);
30433 this.on("keydown", handler);
30438 * Returns the TabPanel component (creates it if it doesn't exist).
30439 * Note: If you wish to simply check for the existence of tabs without creating them,
30440 * check for a null 'tabs' property.
30441 * @return {Roo.TabPanel} The tabs component
30443 getTabs : function(){
30445 this.el.addClass("x-dlg-auto-tabs");
30446 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30447 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30453 * Adds a button to the footer section of the dialog.
30454 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30455 * object or a valid Roo.DomHelper element config
30456 * @param {Function} handler The function called when the button is clicked
30457 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30458 * @return {Roo.Button} The new button
30460 addButton : function(config, handler, scope){
30461 var dh = Roo.DomHelper;
30463 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30465 if(!this.btnContainer){
30466 var tb = this.footer.createChild({
30468 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30469 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30471 this.btnContainer = tb.firstChild.firstChild.firstChild;
30476 minWidth: this.minButtonWidth,
30479 if(typeof config == "string"){
30480 bconfig.text = config;
30483 bconfig.dhconfig = config;
30485 Roo.apply(bconfig, config);
30489 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30490 bconfig.position = Math.max(0, bconfig.position);
30491 fc = this.btnContainer.childNodes[bconfig.position];
30494 var btn = new Roo.Button(
30496 this.btnContainer.insertBefore(document.createElement("td"),fc)
30497 : this.btnContainer.appendChild(document.createElement("td")),
30498 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30501 this.syncBodyHeight();
30504 * Array of all the buttons that have been added to this dialog via addButton
30509 this.buttons.push(btn);
30514 * Sets the default button to be focused when the dialog is displayed.
30515 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30516 * @return {Roo.BasicDialog} this
30518 setDefaultButton : function(btn){
30519 this.defaultButton = btn;
30524 getHeaderFooterHeight : function(safe){
30527 height += this.header.getHeight();
30530 var fm = this.footer.getMargins();
30531 height += (this.footer.getHeight()+fm.top+fm.bottom);
30533 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30534 height += this.centerBg.getPadding("tb");
30539 syncBodyHeight : function()
30541 var bd = this.body, // the text
30542 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30544 var height = this.size.height - this.getHeaderFooterHeight(false);
30545 bd.setHeight(height-bd.getMargins("tb"));
30546 var hh = this.header.getHeight();
30547 var h = this.size.height-hh;
30550 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30551 bw.setHeight(h-cb.getPadding("tb"));
30553 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30554 bd.setWidth(bw.getWidth(true));
30556 this.tabs.syncHeight();
30558 this.tabs.el.repaint();
30564 * Restores the previous state of the dialog if Roo.state is configured.
30565 * @return {Roo.BasicDialog} this
30567 restoreState : function(){
30568 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30569 if(box && box.width){
30570 this.xy = [box.x, box.y];
30571 this.resizeTo(box.width, box.height);
30577 beforeShow : function(){
30579 if(this.fixedcenter){
30580 this.xy = this.el.getCenterXY(true);
30583 Roo.get(document.body).addClass("x-body-masked");
30584 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30587 this.constrainXY();
30591 animShow : function(){
30592 var b = Roo.get(this.animateTarget).getBox();
30593 this.proxy.setSize(b.width, b.height);
30594 this.proxy.setLocation(b.x, b.y);
30596 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30597 true, .35, this.showEl.createDelegate(this));
30601 * Shows the dialog.
30602 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30603 * @return {Roo.BasicDialog} this
30605 show : function(animateTarget){
30606 if (this.fireEvent("beforeshow", this) === false){
30609 if(this.syncHeightBeforeShow){
30610 this.syncBodyHeight();
30611 }else if(this.firstShow){
30612 this.firstShow = false;
30613 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30615 this.animateTarget = animateTarget || this.animateTarget;
30616 if(!this.el.isVisible()){
30618 if(this.animateTarget && Roo.get(this.animateTarget)){
30628 showEl : function(){
30630 this.el.setXY(this.xy);
30632 this.adjustAssets(true);
30635 // IE peekaboo bug - fix found by Dave Fenwick
30639 this.fireEvent("show", this);
30643 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30644 * dialog itself will receive focus.
30646 focus : function(){
30647 if(this.defaultButton){
30648 this.defaultButton.focus();
30650 this.focusEl.focus();
30655 constrainXY : function(){
30656 if(this.constraintoviewport !== false){
30657 if(!this.viewSize){
30658 if(this.container){
30659 var s = this.container.getSize();
30660 this.viewSize = [s.width, s.height];
30662 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30665 var s = Roo.get(this.container||document).getScroll();
30667 var x = this.xy[0], y = this.xy[1];
30668 var w = this.size.width, h = this.size.height;
30669 var vw = this.viewSize[0], vh = this.viewSize[1];
30670 // only move it if it needs it
30672 // first validate right/bottom
30673 if(x + w > vw+s.left){
30677 if(y + h > vh+s.top){
30681 // then make sure top/left isn't negative
30693 if(this.isVisible()){
30694 this.el.setLocation(x, y);
30695 this.adjustAssets();
30702 onDrag : function(){
30703 if(!this.proxyDrag){
30704 this.xy = this.el.getXY();
30705 this.adjustAssets();
30710 adjustAssets : function(doShow){
30711 var x = this.xy[0], y = this.xy[1];
30712 var w = this.size.width, h = this.size.height;
30713 if(doShow === true){
30715 this.shadow.show(this.el);
30721 if(this.shadow && this.shadow.isVisible()){
30722 this.shadow.show(this.el);
30724 if(this.shim && this.shim.isVisible()){
30725 this.shim.setBounds(x, y, w, h);
30730 adjustViewport : function(w, h){
30732 w = Roo.lib.Dom.getViewWidth();
30733 h = Roo.lib.Dom.getViewHeight();
30736 this.viewSize = [w, h];
30737 if(this.modal && this.mask.isVisible()){
30738 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30739 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30741 if(this.isVisible()){
30742 this.constrainXY();
30747 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30748 * shadow, proxy, mask, etc.) Also removes all event listeners.
30749 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30751 destroy : function(removeEl){
30752 if(this.isVisible()){
30753 this.animateTarget = null;
30756 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30758 this.tabs.destroy(removeEl);
30771 for(var i = 0, len = this.buttons.length; i < len; i++){
30772 this.buttons[i].destroy();
30775 this.el.removeAllListeners();
30776 if(removeEl === true){
30777 this.el.update("");
30780 Roo.DialogManager.unregister(this);
30784 startMove : function(){
30785 if(this.proxyDrag){
30788 if(this.constraintoviewport !== false){
30789 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30794 endMove : function(){
30795 if(!this.proxyDrag){
30796 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30798 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30801 this.refreshSize();
30802 this.adjustAssets();
30804 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30808 * Brings this dialog to the front of any other visible dialogs
30809 * @return {Roo.BasicDialog} this
30811 toFront : function(){
30812 Roo.DialogManager.bringToFront(this);
30817 * Sends this dialog to the back (under) of any other visible dialogs
30818 * @return {Roo.BasicDialog} this
30820 toBack : function(){
30821 Roo.DialogManager.sendToBack(this);
30826 * Centers this dialog in the viewport
30827 * @return {Roo.BasicDialog} this
30829 center : function(){
30830 var xy = this.el.getCenterXY(true);
30831 this.moveTo(xy[0], xy[1]);
30836 * Moves the dialog's top-left corner to the specified point
30837 * @param {Number} x
30838 * @param {Number} y
30839 * @return {Roo.BasicDialog} this
30841 moveTo : function(x, y){
30843 if(this.isVisible()){
30844 this.el.setXY(this.xy);
30845 this.adjustAssets();
30851 * Aligns the dialog to the specified element
30852 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30853 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
30854 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30855 * @return {Roo.BasicDialog} this
30857 alignTo : function(element, position, offsets){
30858 this.xy = this.el.getAlignToXY(element, position, offsets);
30859 if(this.isVisible()){
30860 this.el.setXY(this.xy);
30861 this.adjustAssets();
30867 * Anchors an element to another element and realigns it when the window is resized.
30868 * @param {String/HTMLElement/Roo.Element} element The element to align to.
30869 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
30870 * @param {Array} offsets (optional) Offset the positioning by [x, y]
30871 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
30872 * is a number, it is used as the buffer delay (defaults to 50ms).
30873 * @return {Roo.BasicDialog} this
30875 anchorTo : function(el, alignment, offsets, monitorScroll){
30876 var action = function(){
30877 this.alignTo(el, alignment, offsets);
30879 Roo.EventManager.onWindowResize(action, this);
30880 var tm = typeof monitorScroll;
30881 if(tm != 'undefined'){
30882 Roo.EventManager.on(window, 'scroll', action, this,
30883 {buffer: tm == 'number' ? monitorScroll : 50});
30890 * Returns true if the dialog is visible
30891 * @return {Boolean}
30893 isVisible : function(){
30894 return this.el.isVisible();
30898 animHide : function(callback){
30899 var b = Roo.get(this.animateTarget).getBox();
30901 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
30903 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
30904 this.hideEl.createDelegate(this, [callback]));
30908 * Hides the dialog.
30909 * @param {Function} callback (optional) Function to call when the dialog is hidden
30910 * @return {Roo.BasicDialog} this
30912 hide : function(callback){
30913 if (this.fireEvent("beforehide", this) === false){
30917 this.shadow.hide();
30922 // sometimes animateTarget seems to get set.. causing problems...
30923 // this just double checks..
30924 if(this.animateTarget && Roo.get(this.animateTarget)) {
30925 this.animHide(callback);
30928 this.hideEl(callback);
30934 hideEl : function(callback){
30938 Roo.get(document.body).removeClass("x-body-masked");
30940 this.fireEvent("hide", this);
30941 if(typeof callback == "function"){
30947 hideAction : function(){
30948 this.setLeft("-10000px");
30949 this.setTop("-10000px");
30950 this.setStyle("visibility", "hidden");
30954 refreshSize : function(){
30955 this.size = this.el.getSize();
30956 this.xy = this.el.getXY();
30957 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
30961 // z-index is managed by the DialogManager and may be overwritten at any time
30962 setZIndex : function(index){
30964 this.mask.setStyle("z-index", index);
30967 this.shim.setStyle("z-index", ++index);
30970 this.shadow.setZIndex(++index);
30972 this.el.setStyle("z-index", ++index);
30974 this.proxy.setStyle("z-index", ++index);
30977 this.resizer.proxy.setStyle("z-index", ++index);
30980 this.lastZIndex = index;
30984 * Returns the element for this dialog
30985 * @return {Roo.Element} The underlying dialog Element
30987 getEl : function(){
30993 * @class Roo.DialogManager
30994 * Provides global access to BasicDialogs that have been created and
30995 * support for z-indexing (layering) multiple open dialogs.
30997 Roo.DialogManager = function(){
30999 var accessList = [];
31003 var sortDialogs = function(d1, d2){
31004 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31008 var orderDialogs = function(){
31009 accessList.sort(sortDialogs);
31010 var seed = Roo.DialogManager.zseed;
31011 for(var i = 0, len = accessList.length; i < len; i++){
31012 var dlg = accessList[i];
31014 dlg.setZIndex(seed + (i*10));
31021 * The starting z-index for BasicDialogs (defaults to 9000)
31022 * @type Number The z-index value
31027 register : function(dlg){
31028 list[dlg.id] = dlg;
31029 accessList.push(dlg);
31033 unregister : function(dlg){
31034 delete list[dlg.id];
31037 if(!accessList.indexOf){
31038 for( i = 0, len = accessList.length; i < len; i++){
31039 if(accessList[i] == dlg){
31040 accessList.splice(i, 1);
31045 i = accessList.indexOf(dlg);
31047 accessList.splice(i, 1);
31053 * Gets a registered dialog by id
31054 * @param {String/Object} id The id of the dialog or a dialog
31055 * @return {Roo.BasicDialog} this
31057 get : function(id){
31058 return typeof id == "object" ? id : list[id];
31062 * Brings the specified dialog to the front
31063 * @param {String/Object} dlg The id of the dialog or a dialog
31064 * @return {Roo.BasicDialog} this
31066 bringToFront : function(dlg){
31067 dlg = this.get(dlg);
31070 dlg._lastAccess = new Date().getTime();
31077 * Sends the specified dialog to the back
31078 * @param {String/Object} dlg The id of the dialog or a dialog
31079 * @return {Roo.BasicDialog} this
31081 sendToBack : function(dlg){
31082 dlg = this.get(dlg);
31083 dlg._lastAccess = -(new Date().getTime());
31089 * Hides all dialogs
31091 hideAll : function(){
31092 for(var id in list){
31093 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31102 * @class Roo.LayoutDialog
31103 * @extends Roo.BasicDialog
31104 * Dialog which provides adjustments for working with a layout in a Dialog.
31105 * Add your necessary layout config options to the dialog's config.<br>
31106 * Example usage (including a nested layout):
31109 dialog = new Roo.LayoutDialog("download-dlg", {
31118 // layout config merges with the dialog config
31120 tabPosition: "top",
31121 alwaysShowTabs: true
31124 dialog.addKeyListener(27, dialog.hide, dialog);
31125 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31126 dialog.addButton("Build It!", this.getDownload, this);
31128 // we can even add nested layouts
31129 var innerLayout = new Roo.BorderLayout("dl-inner", {
31139 innerLayout.beginUpdate();
31140 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31141 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31142 innerLayout.endUpdate(true);
31144 var layout = dialog.getLayout();
31145 layout.beginUpdate();
31146 layout.add("center", new Roo.ContentPanel("standard-panel",
31147 {title: "Download the Source", fitToFrame:true}));
31148 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31149 {title: "Build your own roo.js"}));
31150 layout.getRegion("center").showPanel(sp);
31151 layout.endUpdate();
31155 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31156 * @param {Object} config configuration options
31158 Roo.LayoutDialog = function(el, cfg){
31161 if (typeof(cfg) == 'undefined') {
31162 config = Roo.apply({}, el);
31163 // not sure why we use documentElement here.. - it should always be body.
31164 // IE7 borks horribly if we use documentElement.
31165 // webkit also does not like documentElement - it creates a body element...
31166 el = Roo.get( document.body || document.documentElement ).createChild();
31167 //config.autoCreate = true;
31171 config.autoTabs = false;
31172 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31173 this.body.setStyle({overflow:"hidden", position:"relative"});
31174 this.layout = new Roo.BorderLayout(this.body.dom, config);
31175 this.layout.monitorWindowResize = false;
31176 this.el.addClass("x-dlg-auto-layout");
31177 // fix case when center region overwrites center function
31178 this.center = Roo.BasicDialog.prototype.center;
31179 this.on("show", this.layout.layout, this.layout, true);
31180 if (config.items) {
31181 var xitems = config.items;
31182 delete config.items;
31183 Roo.each(xitems, this.addxtype, this);
31188 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31190 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31193 endUpdate : function(){
31194 this.layout.endUpdate();
31198 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31201 beginUpdate : function(){
31202 this.layout.beginUpdate();
31206 * Get the BorderLayout for this dialog
31207 * @return {Roo.BorderLayout}
31209 getLayout : function(){
31210 return this.layout;
31213 showEl : function(){
31214 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31216 this.layout.layout();
31221 // Use the syncHeightBeforeShow config option to control this automatically
31222 syncBodyHeight : function(){
31223 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31224 if(this.layout){this.layout.layout();}
31228 * Add an xtype element (actually adds to the layout.)
31229 * @return {Object} xdata xtype object data.
31232 addxtype : function(c) {
31233 return this.layout.addxtype(c);
31237 * Ext JS Library 1.1.1
31238 * Copyright(c) 2006-2007, Ext JS, LLC.
31240 * Originally Released Under LGPL - original licence link has changed is not relivant.
31243 * <script type="text/javascript">
31247 * @class Roo.MessageBox
31248 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31252 Roo.Msg.alert('Status', 'Changes saved successfully.');
31254 // Prompt for user data:
31255 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31257 // process text value...
31261 // Show a dialog using config options:
31263 title:'Save Changes?',
31264 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31265 buttons: Roo.Msg.YESNOCANCEL,
31272 Roo.MessageBox = function(){
31273 var dlg, opt, mask, waitTimer;
31274 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31275 var buttons, activeTextEl, bwidth;
31278 var handleButton = function(button){
31280 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31284 var handleHide = function(){
31285 if(opt && opt.cls){
31286 dlg.el.removeClass(opt.cls);
31289 Roo.TaskMgr.stop(waitTimer);
31295 var updateButtons = function(b){
31298 buttons["ok"].hide();
31299 buttons["cancel"].hide();
31300 buttons["yes"].hide();
31301 buttons["no"].hide();
31302 dlg.footer.dom.style.display = 'none';
31305 dlg.footer.dom.style.display = '';
31306 for(var k in buttons){
31307 if(typeof buttons[k] != "function"){
31310 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31311 width += buttons[k].el.getWidth()+15;
31321 var handleEsc = function(d, k, e){
31322 if(opt && opt.closable !== false){
31332 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31333 * @return {Roo.BasicDialog} The BasicDialog element
31335 getDialog : function(){
31337 dlg = new Roo.BasicDialog("x-msg-box", {
31342 constraintoviewport:false,
31344 collapsible : false,
31347 width:400, height:100,
31348 buttonAlign:"center",
31349 closeClick : function(){
31350 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31351 handleButton("no");
31353 handleButton("cancel");
31357 dlg.on("hide", handleHide);
31359 dlg.addKeyListener(27, handleEsc);
31361 var bt = this.buttonText;
31362 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31363 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31364 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31365 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31366 bodyEl = dlg.body.createChild({
31368 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>'
31370 msgEl = bodyEl.dom.firstChild;
31371 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31372 textboxEl.enableDisplayMode();
31373 textboxEl.addKeyListener([10,13], function(){
31374 if(dlg.isVisible() && opt && opt.buttons){
31375 if(opt.buttons.ok){
31376 handleButton("ok");
31377 }else if(opt.buttons.yes){
31378 handleButton("yes");
31382 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31383 textareaEl.enableDisplayMode();
31384 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31385 progressEl.enableDisplayMode();
31386 var pf = progressEl.dom.firstChild;
31388 pp = Roo.get(pf.firstChild);
31389 pp.setHeight(pf.offsetHeight);
31397 * Updates the message box body text
31398 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31399 * the XHTML-compliant non-breaking space character '&#160;')
31400 * @return {Roo.MessageBox} This message box
31402 updateText : function(text){
31403 if(!dlg.isVisible() && !opt.width){
31404 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31406 msgEl.innerHTML = text || ' ';
31408 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31409 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31411 Math.min(opt.width || cw , this.maxWidth),
31412 Math.max(opt.minWidth || this.minWidth, bwidth)
31415 activeTextEl.setWidth(w);
31417 if(dlg.isVisible()){
31418 dlg.fixedcenter = false;
31420 // to big, make it scroll. = But as usual stupid IE does not support
31423 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31424 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31425 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31427 bodyEl.dom.style.height = '';
31428 bodyEl.dom.style.overflowY = '';
31431 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31433 bodyEl.dom.style.overflowX = '';
31436 dlg.setContentSize(w, bodyEl.getHeight());
31437 if(dlg.isVisible()){
31438 dlg.fixedcenter = true;
31444 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31445 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31446 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31447 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31448 * @return {Roo.MessageBox} This message box
31450 updateProgress : function(value, text){
31452 this.updateText(text);
31454 if (pp) { // weird bug on my firefox - for some reason this is not defined
31455 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31461 * Returns true if the message box is currently displayed
31462 * @return {Boolean} True if the message box is visible, else false
31464 isVisible : function(){
31465 return dlg && dlg.isVisible();
31469 * Hides the message box if it is displayed
31472 if(this.isVisible()){
31478 * Displays a new message box, or reinitializes an existing message box, based on the config options
31479 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31480 * The following config object properties are supported:
31482 Property Type Description
31483 ---------- --------------- ------------------------------------------------------------------------------------
31484 animEl String/Element An id or Element from which the message box should animate as it opens and
31485 closes (defaults to undefined)
31486 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31487 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31488 closable Boolean False to hide the top-right close button (defaults to true). Note that
31489 progress and wait dialogs will ignore this property and always hide the
31490 close button as they can only be closed programmatically.
31491 cls String A custom CSS class to apply to the message box element
31492 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31493 displayed (defaults to 75)
31494 fn Function A callback function to execute after closing the dialog. The arguments to the
31495 function will be btn (the name of the button that was clicked, if applicable,
31496 e.g. "ok"), and text (the value of the active text field, if applicable).
31497 Progress and wait dialogs will ignore this option since they do not respond to
31498 user actions and can only be closed programmatically, so any required function
31499 should be called by the same code after it closes the dialog.
31500 icon String A CSS class that provides a background image to be used as an icon for
31501 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31502 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31503 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31504 modal Boolean False to allow user interaction with the page while the message box is
31505 displayed (defaults to true)
31506 msg String A string that will replace the existing message box body text (defaults
31507 to the XHTML-compliant non-breaking space character ' ')
31508 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31509 progress Boolean True to display a progress bar (defaults to false)
31510 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31511 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31512 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31513 title String The title text
31514 value String The string value to set into the active textbox element if displayed
31515 wait Boolean True to display a progress bar (defaults to false)
31516 width Number The width of the dialog in pixels
31523 msg: 'Please enter your address:',
31525 buttons: Roo.MessageBox.OKCANCEL,
31528 animEl: 'addAddressBtn'
31531 * @param {Object} config Configuration options
31532 * @return {Roo.MessageBox} This message box
31534 show : function(options)
31537 // this causes nightmares if you show one dialog after another
31538 // especially on callbacks..
31540 if(this.isVisible()){
31543 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31544 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31545 Roo.log("New Dialog Message:" + options.msg )
31546 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31547 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31550 var d = this.getDialog();
31552 d.setTitle(opt.title || " ");
31553 d.close.setDisplayed(opt.closable !== false);
31554 activeTextEl = textboxEl;
31555 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31560 textareaEl.setHeight(typeof opt.multiline == "number" ?
31561 opt.multiline : this.defaultTextHeight);
31562 activeTextEl = textareaEl;
31571 progressEl.setDisplayed(opt.progress === true);
31572 this.updateProgress(0);
31573 activeTextEl.dom.value = opt.value || "";
31575 dlg.setDefaultButton(activeTextEl);
31577 var bs = opt.buttons;
31580 db = buttons["ok"];
31581 }else if(bs && bs.yes){
31582 db = buttons["yes"];
31584 dlg.setDefaultButton(db);
31586 bwidth = updateButtons(opt.buttons);
31587 this.updateText(opt.msg);
31589 d.el.addClass(opt.cls);
31591 d.proxyDrag = opt.proxyDrag === true;
31592 d.modal = opt.modal !== false;
31593 d.mask = opt.modal !== false ? mask : false;
31594 if(!d.isVisible()){
31595 // force it to the end of the z-index stack so it gets a cursor in FF
31596 document.body.appendChild(dlg.el.dom);
31597 d.animateTarget = null;
31598 d.show(options.animEl);
31604 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31605 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31606 * and closing the message box when the process is complete.
31607 * @param {String} title The title bar text
31608 * @param {String} msg The message box body text
31609 * @return {Roo.MessageBox} This message box
31611 progress : function(title, msg){
31618 minWidth: this.minProgressWidth,
31625 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31626 * If a callback function is passed it will be called after the user clicks the button, and the
31627 * id of the button that was clicked will be passed as the only parameter to the callback
31628 * (could also be the top-right close button).
31629 * @param {String} title The title bar text
31630 * @param {String} msg The message box body text
31631 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31632 * @param {Object} scope (optional) The scope of the callback function
31633 * @return {Roo.MessageBox} This message box
31635 alert : function(title, msg, fn, scope){
31648 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31649 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31650 * You are responsible for closing the message box when the process is complete.
31651 * @param {String} msg The message box body text
31652 * @param {String} title (optional) The title bar text
31653 * @return {Roo.MessageBox} This message box
31655 wait : function(msg, title){
31666 waitTimer = Roo.TaskMgr.start({
31668 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31676 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31677 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31678 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31679 * @param {String} title The title bar text
31680 * @param {String} msg The message box body text
31681 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31682 * @param {Object} scope (optional) The scope of the callback function
31683 * @return {Roo.MessageBox} This message box
31685 confirm : function(title, msg, fn, scope){
31689 buttons: this.YESNO,
31698 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31699 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31700 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31701 * (could also be the top-right close button) and the text that was entered will be passed as the two
31702 * parameters to the callback.
31703 * @param {String} title The title bar text
31704 * @param {String} msg The message box body text
31705 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31706 * @param {Object} scope (optional) The scope of the callback function
31707 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31708 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31709 * @return {Roo.MessageBox} This message box
31711 prompt : function(title, msg, fn, scope, multiline){
31715 buttons: this.OKCANCEL,
31720 multiline: multiline,
31727 * Button config that displays a single OK button
31732 * Button config that displays Yes and No buttons
31735 YESNO : {yes:true, no:true},
31737 * Button config that displays OK and Cancel buttons
31740 OKCANCEL : {ok:true, cancel:true},
31742 * Button config that displays Yes, No and Cancel buttons
31745 YESNOCANCEL : {yes:true, no:true, cancel:true},
31748 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31751 defaultTextHeight : 75,
31753 * The maximum width in pixels of the message box (defaults to 600)
31758 * The minimum width in pixels of the message box (defaults to 100)
31763 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31764 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31767 minProgressWidth : 250,
31769 * An object containing the default button text strings that can be overriden for localized language support.
31770 * Supported properties are: ok, cancel, yes and no.
31771 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31784 * Shorthand for {@link Roo.MessageBox}
31786 Roo.Msg = Roo.MessageBox;/*
31788 * Ext JS Library 1.1.1
31789 * Copyright(c) 2006-2007, Ext JS, LLC.
31791 * Originally Released Under LGPL - original licence link has changed is not relivant.
31794 * <script type="text/javascript">
31797 * @class Roo.QuickTips
31798 * Provides attractive and customizable tooltips for any element.
31801 Roo.QuickTips = function(){
31802 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31803 var ce, bd, xy, dd;
31804 var visible = false, disabled = true, inited = false;
31805 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31807 var onOver = function(e){
31811 var t = e.getTarget();
31812 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31815 if(ce && t == ce.el){
31816 clearTimeout(hideProc);
31819 if(t && tagEls[t.id]){
31820 tagEls[t.id].el = t;
31821 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
31824 var ttp, et = Roo.fly(t);
31825 var ns = cfg.namespace;
31826 if(tm.interceptTitles && t.title){
31829 t.removeAttribute("title");
31830 e.preventDefault();
31832 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
31835 showProc = show.defer(tm.showDelay, tm, [{
31838 width: et.getAttributeNS(ns, cfg.width),
31839 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
31840 title: et.getAttributeNS(ns, cfg.title),
31841 cls: et.getAttributeNS(ns, cfg.cls)
31846 var onOut = function(e){
31847 clearTimeout(showProc);
31848 var t = e.getTarget();
31849 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
31850 hideProc = setTimeout(hide, tm.hideDelay);
31854 var onMove = function(e){
31860 if(tm.trackMouse && ce){
31865 var onDown = function(e){
31866 clearTimeout(showProc);
31867 clearTimeout(hideProc);
31869 if(tm.hideOnClick){
31872 tm.enable.defer(100, tm);
31877 var getPad = function(){
31878 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
31881 var show = function(o){
31885 clearTimeout(dismissProc);
31887 if(removeCls){ // in case manually hidden
31888 el.removeClass(removeCls);
31892 el.addClass(ce.cls);
31893 removeCls = ce.cls;
31896 tipTitle.update(ce.title);
31899 tipTitle.update('');
31902 el.dom.style.width = tm.maxWidth+'px';
31903 //tipBody.dom.style.width = '';
31904 tipBodyText.update(o.text);
31905 var p = getPad(), w = ce.width;
31907 var td = tipBodyText.dom;
31908 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
31909 if(aw > tm.maxWidth){
31911 }else if(aw < tm.minWidth){
31917 //tipBody.setWidth(w);
31918 el.setWidth(parseInt(w, 10) + p);
31919 if(ce.autoHide === false){
31920 close.setDisplayed(true);
31925 close.setDisplayed(false);
31931 el.avoidY = xy[1]-18;
31936 el.setStyle("visibility", "visible");
31937 el.fadeIn({callback: afterShow});
31943 var afterShow = function(){
31947 if(tm.autoDismiss && ce.autoHide !== false){
31948 dismissProc = setTimeout(hide, tm.autoDismissDelay);
31953 var hide = function(noanim){
31954 clearTimeout(dismissProc);
31955 clearTimeout(hideProc);
31957 if(el.isVisible()){
31959 if(noanim !== true && tm.animate){
31960 el.fadeOut({callback: afterHide});
31967 var afterHide = function(){
31970 el.removeClass(removeCls);
31977 * @cfg {Number} minWidth
31978 * The minimum width of the quick tip (defaults to 40)
31982 * @cfg {Number} maxWidth
31983 * The maximum width of the quick tip (defaults to 300)
31987 * @cfg {Boolean} interceptTitles
31988 * True to automatically use the element's DOM title value if available (defaults to false)
31990 interceptTitles : false,
31992 * @cfg {Boolean} trackMouse
31993 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
31995 trackMouse : false,
31997 * @cfg {Boolean} hideOnClick
31998 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32000 hideOnClick : true,
32002 * @cfg {Number} showDelay
32003 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32007 * @cfg {Number} hideDelay
32008 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32012 * @cfg {Boolean} autoHide
32013 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32014 * Used in conjunction with hideDelay.
32019 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32020 * (defaults to true). Used in conjunction with autoDismissDelay.
32022 autoDismiss : true,
32025 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32027 autoDismissDelay : 5000,
32029 * @cfg {Boolean} animate
32030 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32035 * @cfg {String} title
32036 * Title text to display (defaults to ''). This can be any valid HTML markup.
32040 * @cfg {String} text
32041 * Body text to display (defaults to ''). This can be any valid HTML markup.
32045 * @cfg {String} cls
32046 * A CSS class to apply to the base quick tip element (defaults to '').
32050 * @cfg {Number} width
32051 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32052 * minWidth or maxWidth.
32057 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32058 * or display QuickTips in a page.
32061 tm = Roo.QuickTips;
32062 cfg = tm.tagConfig;
32064 if(!Roo.isReady){ // allow calling of init() before onReady
32065 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32068 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32069 el.fxDefaults = {stopFx: true};
32070 // maximum custom styling
32071 //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>');
32072 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>');
32073 tipTitle = el.child('h3');
32074 tipTitle.enableDisplayMode("block");
32075 tipBody = el.child('div.x-tip-bd');
32076 tipBodyText = el.child('div.x-tip-bd-inner');
32077 //bdLeft = el.child('div.x-tip-bd-left');
32078 //bdRight = el.child('div.x-tip-bd-right');
32079 close = el.child('div.x-tip-close');
32080 close.enableDisplayMode("block");
32081 close.on("click", hide);
32082 var d = Roo.get(document);
32083 d.on("mousedown", onDown);
32084 d.on("mouseover", onOver);
32085 d.on("mouseout", onOut);
32086 d.on("mousemove", onMove);
32087 esc = d.addKeyListener(27, hide);
32090 dd = el.initDD("default", null, {
32091 onDrag : function(){
32095 dd.setHandleElId(tipTitle.id);
32104 * Configures a new quick tip instance and assigns it to a target element. The following config options
32107 Property Type Description
32108 ---------- --------------------- ------------------------------------------------------------------------
32109 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32111 * @param {Object} config The config object
32113 register : function(config){
32114 var cs = config instanceof Array ? config : arguments;
32115 for(var i = 0, len = cs.length; i < len; i++) {
32117 var target = c.target;
32119 if(target instanceof Array){
32120 for(var j = 0, jlen = target.length; j < jlen; j++){
32121 tagEls[target[j]] = c;
32124 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32131 * Removes this quick tip from its element and destroys it.
32132 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32134 unregister : function(el){
32135 delete tagEls[Roo.id(el)];
32139 * Enable this quick tip.
32141 enable : function(){
32142 if(inited && disabled){
32144 if(locks.length < 1){
32151 * Disable this quick tip.
32153 disable : function(){
32155 clearTimeout(showProc);
32156 clearTimeout(hideProc);
32157 clearTimeout(dismissProc);
32165 * Returns true if the quick tip is enabled, else false.
32167 isEnabled : function(){
32174 attribute : "qtip",
32184 // backwards compat
32185 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32187 * Ext JS Library 1.1.1
32188 * Copyright(c) 2006-2007, Ext JS, LLC.
32190 * Originally Released Under LGPL - original licence link has changed is not relivant.
32193 * <script type="text/javascript">
32198 * @class Roo.tree.TreePanel
32199 * @extends Roo.data.Tree
32201 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32202 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32203 * @cfg {Boolean} enableDD true to enable drag and drop
32204 * @cfg {Boolean} enableDrag true to enable just drag
32205 * @cfg {Boolean} enableDrop true to enable just drop
32206 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32207 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32208 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32209 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32210 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32211 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32212 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32213 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32214 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32215 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32216 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32217 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32218 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32219 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32220 * @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>
32221 * @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>
32224 * @param {String/HTMLElement/Element} el The container element
32225 * @param {Object} config
32227 Roo.tree.TreePanel = function(el, config){
32229 var loader = false;
32231 root = config.root;
32232 delete config.root;
32234 if (config.loader) {
32235 loader = config.loader;
32236 delete config.loader;
32239 Roo.apply(this, config);
32240 Roo.tree.TreePanel.superclass.constructor.call(this);
32241 this.el = Roo.get(el);
32242 this.el.addClass('x-tree');
32243 //console.log(root);
32245 this.setRootNode( Roo.factory(root, Roo.tree));
32248 this.loader = Roo.factory(loader, Roo.tree);
32251 * Read-only. The id of the container element becomes this TreePanel's id.
32253 this.id = this.el.id;
32256 * @event beforeload
32257 * Fires before a node is loaded, return false to cancel
32258 * @param {Node} node The node being loaded
32260 "beforeload" : true,
32263 * Fires when a node is loaded
32264 * @param {Node} node The node that was loaded
32268 * @event textchange
32269 * Fires when the text for a node is changed
32270 * @param {Node} node The node
32271 * @param {String} text The new text
32272 * @param {String} oldText The old text
32274 "textchange" : true,
32276 * @event beforeexpand
32277 * Fires before a node is expanded, return false to cancel.
32278 * @param {Node} node The node
32279 * @param {Boolean} deep
32280 * @param {Boolean} anim
32282 "beforeexpand" : true,
32284 * @event beforecollapse
32285 * Fires before a node is collapsed, return false to cancel.
32286 * @param {Node} node The node
32287 * @param {Boolean} deep
32288 * @param {Boolean} anim
32290 "beforecollapse" : true,
32293 * Fires when a node is expanded
32294 * @param {Node} node The node
32298 * @event disabledchange
32299 * Fires when the disabled status of a node changes
32300 * @param {Node} node The node
32301 * @param {Boolean} disabled
32303 "disabledchange" : true,
32306 * Fires when a node is collapsed
32307 * @param {Node} node The node
32311 * @event beforeclick
32312 * Fires before click processing on a node. Return false to cancel the default action.
32313 * @param {Node} node The node
32314 * @param {Roo.EventObject} e The event object
32316 "beforeclick":true,
32318 * @event checkchange
32319 * Fires when a node with a checkbox's checked property changes
32320 * @param {Node} this This node
32321 * @param {Boolean} checked
32323 "checkchange":true,
32326 * Fires when a node is clicked
32327 * @param {Node} node The node
32328 * @param {Roo.EventObject} e The event object
32333 * Fires when a node is double clicked
32334 * @param {Node} node The node
32335 * @param {Roo.EventObject} e The event object
32339 * @event contextmenu
32340 * Fires when a node is right clicked
32341 * @param {Node} node The node
32342 * @param {Roo.EventObject} e The event object
32344 "contextmenu":true,
32346 * @event beforechildrenrendered
32347 * Fires right before the child nodes for a node are rendered
32348 * @param {Node} node The node
32350 "beforechildrenrendered":true,
32353 * Fires when a node starts being dragged
32354 * @param {Roo.tree.TreePanel} this
32355 * @param {Roo.tree.TreeNode} node
32356 * @param {event} e The raw browser event
32358 "startdrag" : true,
32361 * Fires when a drag operation is complete
32362 * @param {Roo.tree.TreePanel} this
32363 * @param {Roo.tree.TreeNode} node
32364 * @param {event} e The raw browser event
32369 * Fires when a dragged node is dropped on a valid DD target
32370 * @param {Roo.tree.TreePanel} this
32371 * @param {Roo.tree.TreeNode} node
32372 * @param {DD} dd The dd it was dropped on
32373 * @param {event} e The raw browser event
32377 * @event beforenodedrop
32378 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32379 * passed to handlers has the following properties:<br />
32380 * <ul style="padding:5px;padding-left:16px;">
32381 * <li>tree - The TreePanel</li>
32382 * <li>target - The node being targeted for the drop</li>
32383 * <li>data - The drag data from the drag source</li>
32384 * <li>point - The point of the drop - append, above or below</li>
32385 * <li>source - The drag source</li>
32386 * <li>rawEvent - Raw mouse event</li>
32387 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32388 * to be inserted by setting them on this object.</li>
32389 * <li>cancel - Set this to true to cancel the drop.</li>
32391 * @param {Object} dropEvent
32393 "beforenodedrop" : true,
32396 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32397 * passed to handlers has the following properties:<br />
32398 * <ul style="padding:5px;padding-left:16px;">
32399 * <li>tree - The TreePanel</li>
32400 * <li>target - The node being targeted for the drop</li>
32401 * <li>data - The drag data from the drag source</li>
32402 * <li>point - The point of the drop - append, above or below</li>
32403 * <li>source - The drag source</li>
32404 * <li>rawEvent - Raw mouse event</li>
32405 * <li>dropNode - Dropped node(s).</li>
32407 * @param {Object} dropEvent
32411 * @event nodedragover
32412 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32413 * passed to handlers has the following properties:<br />
32414 * <ul style="padding:5px;padding-left:16px;">
32415 * <li>tree - The TreePanel</li>
32416 * <li>target - The node being targeted for the drop</li>
32417 * <li>data - The drag data from the drag source</li>
32418 * <li>point - The point of the drop - append, above or below</li>
32419 * <li>source - The drag source</li>
32420 * <li>rawEvent - Raw mouse event</li>
32421 * <li>dropNode - Drop node(s) provided by the source.</li>
32422 * <li>cancel - Set this to true to signal drop not allowed.</li>
32424 * @param {Object} dragOverEvent
32426 "nodedragover" : true
32429 if(this.singleExpand){
32430 this.on("beforeexpand", this.restrictExpand, this);
32433 this.editor.tree = this;
32434 this.editor = Roo.factory(this.editor, Roo.tree);
32437 if (this.selModel) {
32438 this.selModel = Roo.factory(this.selModel, Roo.tree);
32442 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32443 rootVisible : true,
32444 animate: Roo.enableFx,
32447 hlDrop : Roo.enableFx,
32451 rendererTip: false,
32453 restrictExpand : function(node){
32454 var p = node.parentNode;
32456 if(p.expandedChild && p.expandedChild.parentNode == p){
32457 p.expandedChild.collapse();
32459 p.expandedChild = node;
32463 // private override
32464 setRootNode : function(node){
32465 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32466 if(!this.rootVisible){
32467 node.ui = new Roo.tree.RootTreeNodeUI(node);
32473 * Returns the container element for this TreePanel
32475 getEl : function(){
32480 * Returns the default TreeLoader for this TreePanel
32482 getLoader : function(){
32483 return this.loader;
32489 expandAll : function(){
32490 this.root.expand(true);
32494 * Collapse all nodes
32496 collapseAll : function(){
32497 this.root.collapse(true);
32501 * Returns the selection model used by this TreePanel
32503 getSelectionModel : function(){
32504 if(!this.selModel){
32505 this.selModel = new Roo.tree.DefaultSelectionModel();
32507 return this.selModel;
32511 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32512 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32513 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32516 getChecked : function(a, startNode){
32517 startNode = startNode || this.root;
32519 var f = function(){
32520 if(this.attributes.checked){
32521 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32524 startNode.cascade(f);
32529 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32530 * @param {String} path
32531 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32532 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32533 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32535 expandPath : function(path, attr, callback){
32536 attr = attr || "id";
32537 var keys = path.split(this.pathSeparator);
32538 var curNode = this.root;
32539 if(curNode.attributes[attr] != keys[1]){ // invalid root
32541 callback(false, null);
32546 var f = function(){
32547 if(++index == keys.length){
32549 callback(true, curNode);
32553 var c = curNode.findChild(attr, keys[index]);
32556 callback(false, curNode);
32561 c.expand(false, false, f);
32563 curNode.expand(false, false, f);
32567 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32568 * @param {String} path
32569 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32570 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32571 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32573 selectPath : function(path, attr, callback){
32574 attr = attr || "id";
32575 var keys = path.split(this.pathSeparator);
32576 var v = keys.pop();
32577 if(keys.length > 0){
32578 var f = function(success, node){
32579 if(success && node){
32580 var n = node.findChild(attr, v);
32586 }else if(callback){
32587 callback(false, n);
32591 callback(false, n);
32595 this.expandPath(keys.join(this.pathSeparator), attr, f);
32597 this.root.select();
32599 callback(true, this.root);
32604 getTreeEl : function(){
32609 * Trigger rendering of this TreePanel
32611 render : function(){
32612 if (this.innerCt) {
32613 return this; // stop it rendering more than once!!
32616 this.innerCt = this.el.createChild({tag:"ul",
32617 cls:"x-tree-root-ct " +
32618 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32620 if(this.containerScroll){
32621 Roo.dd.ScrollManager.register(this.el);
32623 if((this.enableDD || this.enableDrop) && !this.dropZone){
32625 * The dropZone used by this tree if drop is enabled
32626 * @type Roo.tree.TreeDropZone
32628 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32629 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32632 if((this.enableDD || this.enableDrag) && !this.dragZone){
32634 * The dragZone used by this tree if drag is enabled
32635 * @type Roo.tree.TreeDragZone
32637 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32638 ddGroup: this.ddGroup || "TreeDD",
32639 scroll: this.ddScroll
32642 this.getSelectionModel().init(this);
32644 Roo.log("ROOT not set in tree");
32647 this.root.render();
32648 if(!this.rootVisible){
32649 this.root.renderChildren();
32655 * Ext JS Library 1.1.1
32656 * Copyright(c) 2006-2007, Ext JS, LLC.
32658 * Originally Released Under LGPL - original licence link has changed is not relivant.
32661 * <script type="text/javascript">
32666 * @class Roo.tree.DefaultSelectionModel
32667 * @extends Roo.util.Observable
32668 * The default single selection for a TreePanel.
32669 * @param {Object} cfg Configuration
32671 Roo.tree.DefaultSelectionModel = function(cfg){
32672 this.selNode = null;
32678 * @event selectionchange
32679 * Fires when the selected node changes
32680 * @param {DefaultSelectionModel} this
32681 * @param {TreeNode} node the new selection
32683 "selectionchange" : true,
32686 * @event beforeselect
32687 * Fires before the selected node changes, return false to cancel the change
32688 * @param {DefaultSelectionModel} this
32689 * @param {TreeNode} node the new selection
32690 * @param {TreeNode} node the old selection
32692 "beforeselect" : true
32695 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32698 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32699 init : function(tree){
32701 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32702 tree.on("click", this.onNodeClick, this);
32705 onNodeClick : function(node, e){
32706 if (e.ctrlKey && this.selNode == node) {
32707 this.unselect(node);
32715 * @param {TreeNode} node The node to select
32716 * @return {TreeNode} The selected node
32718 select : function(node){
32719 var last = this.selNode;
32720 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32722 last.ui.onSelectedChange(false);
32724 this.selNode = node;
32725 node.ui.onSelectedChange(true);
32726 this.fireEvent("selectionchange", this, node, last);
32733 * @param {TreeNode} node The node to unselect
32735 unselect : function(node){
32736 if(this.selNode == node){
32737 this.clearSelections();
32742 * Clear all selections
32744 clearSelections : function(){
32745 var n = this.selNode;
32747 n.ui.onSelectedChange(false);
32748 this.selNode = null;
32749 this.fireEvent("selectionchange", this, null);
32755 * Get the selected node
32756 * @return {TreeNode} The selected node
32758 getSelectedNode : function(){
32759 return this.selNode;
32763 * Returns true if the node is selected
32764 * @param {TreeNode} node The node to check
32765 * @return {Boolean}
32767 isSelected : function(node){
32768 return this.selNode == node;
32772 * Selects the node above the selected node in the tree, intelligently walking the nodes
32773 * @return TreeNode The new selection
32775 selectPrevious : function(){
32776 var s = this.selNode || this.lastSelNode;
32780 var ps = s.previousSibling;
32782 if(!ps.isExpanded() || ps.childNodes.length < 1){
32783 return this.select(ps);
32785 var lc = ps.lastChild;
32786 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32789 return this.select(lc);
32791 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32792 return this.select(s.parentNode);
32798 * Selects the node above the selected node in the tree, intelligently walking the nodes
32799 * @return TreeNode The new selection
32801 selectNext : function(){
32802 var s = this.selNode || this.lastSelNode;
32806 if(s.firstChild && s.isExpanded()){
32807 return this.select(s.firstChild);
32808 }else if(s.nextSibling){
32809 return this.select(s.nextSibling);
32810 }else if(s.parentNode){
32812 s.parentNode.bubble(function(){
32813 if(this.nextSibling){
32814 newS = this.getOwnerTree().selModel.select(this.nextSibling);
32823 onKeyDown : function(e){
32824 var s = this.selNode || this.lastSelNode;
32825 // undesirable, but required
32830 var k = e.getKey();
32838 this.selectPrevious();
32841 e.preventDefault();
32842 if(s.hasChildNodes()){
32843 if(!s.isExpanded()){
32845 }else if(s.firstChild){
32846 this.select(s.firstChild, e);
32851 e.preventDefault();
32852 if(s.hasChildNodes() && s.isExpanded()){
32854 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
32855 this.select(s.parentNode, e);
32863 * @class Roo.tree.MultiSelectionModel
32864 * @extends Roo.util.Observable
32865 * Multi selection for a TreePanel.
32866 * @param {Object} cfg Configuration
32868 Roo.tree.MultiSelectionModel = function(){
32869 this.selNodes = [];
32873 * @event selectionchange
32874 * Fires when the selected nodes change
32875 * @param {MultiSelectionModel} this
32876 * @param {Array} nodes Array of the selected nodes
32878 "selectionchange" : true
32880 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
32884 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
32885 init : function(tree){
32887 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32888 tree.on("click", this.onNodeClick, this);
32891 onNodeClick : function(node, e){
32892 this.select(node, e, e.ctrlKey);
32897 * @param {TreeNode} node The node to select
32898 * @param {EventObject} e (optional) An event associated with the selection
32899 * @param {Boolean} keepExisting True to retain existing selections
32900 * @return {TreeNode} The selected node
32902 select : function(node, e, keepExisting){
32903 if(keepExisting !== true){
32904 this.clearSelections(true);
32906 if(this.isSelected(node)){
32907 this.lastSelNode = node;
32910 this.selNodes.push(node);
32911 this.selMap[node.id] = node;
32912 this.lastSelNode = node;
32913 node.ui.onSelectedChange(true);
32914 this.fireEvent("selectionchange", this, this.selNodes);
32920 * @param {TreeNode} node The node to unselect
32922 unselect : function(node){
32923 if(this.selMap[node.id]){
32924 node.ui.onSelectedChange(false);
32925 var sn = this.selNodes;
32928 index = sn.indexOf(node);
32930 for(var i = 0, len = sn.length; i < len; i++){
32938 this.selNodes.splice(index, 1);
32940 delete this.selMap[node.id];
32941 this.fireEvent("selectionchange", this, this.selNodes);
32946 * Clear all selections
32948 clearSelections : function(suppressEvent){
32949 var sn = this.selNodes;
32951 for(var i = 0, len = sn.length; i < len; i++){
32952 sn[i].ui.onSelectedChange(false);
32954 this.selNodes = [];
32956 if(suppressEvent !== true){
32957 this.fireEvent("selectionchange", this, this.selNodes);
32963 * Returns true if the node is selected
32964 * @param {TreeNode} node The node to check
32965 * @return {Boolean}
32967 isSelected : function(node){
32968 return this.selMap[node.id] ? true : false;
32972 * Returns an array of the selected nodes
32975 getSelectedNodes : function(){
32976 return this.selNodes;
32979 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
32981 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
32983 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
32986 * Ext JS Library 1.1.1
32987 * Copyright(c) 2006-2007, Ext JS, LLC.
32989 * Originally Released Under LGPL - original licence link has changed is not relivant.
32992 * <script type="text/javascript">
32996 * @class Roo.tree.TreeNode
32997 * @extends Roo.data.Node
32998 * @cfg {String} text The text for this node
32999 * @cfg {Boolean} expanded true to start the node expanded
33000 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33001 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33002 * @cfg {Boolean} disabled true to start the node disabled
33003 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33004 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33005 * @cfg {String} cls A css class to be added to the node
33006 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33007 * @cfg {String} href URL of the link used for the node (defaults to #)
33008 * @cfg {String} hrefTarget target frame for the link
33009 * @cfg {String} qtip An Ext QuickTip for the node
33010 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33011 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33012 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33013 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33014 * (defaults to undefined with no checkbox rendered)
33016 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33018 Roo.tree.TreeNode = function(attributes){
33019 attributes = attributes || {};
33020 if(typeof attributes == "string"){
33021 attributes = {text: attributes};
33023 this.childrenRendered = false;
33024 this.rendered = false;
33025 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33026 this.expanded = attributes.expanded === true;
33027 this.isTarget = attributes.isTarget !== false;
33028 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33029 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33032 * Read-only. The text for this node. To change it use setText().
33035 this.text = attributes.text;
33037 * True if this node is disabled.
33040 this.disabled = attributes.disabled === true;
33044 * @event textchange
33045 * Fires when the text for this node is changed
33046 * @param {Node} this This node
33047 * @param {String} text The new text
33048 * @param {String} oldText The old text
33050 "textchange" : true,
33052 * @event beforeexpand
33053 * Fires before this node is expanded, return false to cancel.
33054 * @param {Node} this This node
33055 * @param {Boolean} deep
33056 * @param {Boolean} anim
33058 "beforeexpand" : true,
33060 * @event beforecollapse
33061 * Fires before this node is collapsed, return false to cancel.
33062 * @param {Node} this This node
33063 * @param {Boolean} deep
33064 * @param {Boolean} anim
33066 "beforecollapse" : true,
33069 * Fires when this node is expanded
33070 * @param {Node} this This node
33074 * @event disabledchange
33075 * Fires when the disabled status of this node changes
33076 * @param {Node} this This node
33077 * @param {Boolean} disabled
33079 "disabledchange" : true,
33082 * Fires when this node is collapsed
33083 * @param {Node} this This node
33087 * @event beforeclick
33088 * Fires before click processing. Return false to cancel the default action.
33089 * @param {Node} this This node
33090 * @param {Roo.EventObject} e The event object
33092 "beforeclick":true,
33094 * @event checkchange
33095 * Fires when a node with a checkbox's checked property changes
33096 * @param {Node} this This node
33097 * @param {Boolean} checked
33099 "checkchange":true,
33102 * Fires when this node is clicked
33103 * @param {Node} this This node
33104 * @param {Roo.EventObject} e The event object
33109 * Fires when this node is double clicked
33110 * @param {Node} this This node
33111 * @param {Roo.EventObject} e The event object
33115 * @event contextmenu
33116 * Fires when this node is right clicked
33117 * @param {Node} this This node
33118 * @param {Roo.EventObject} e The event object
33120 "contextmenu":true,
33122 * @event beforechildrenrendered
33123 * Fires right before the child nodes for this node are rendered
33124 * @param {Node} this This node
33126 "beforechildrenrendered":true
33129 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33132 * Read-only. The UI for this node
33135 this.ui = new uiClass(this);
33137 // finally support items[]
33138 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33143 Roo.each(this.attributes.items, function(c) {
33144 this.appendChild(Roo.factory(c,Roo.Tree));
33146 delete this.attributes.items;
33151 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33152 preventHScroll: true,
33154 * Returns true if this node is expanded
33155 * @return {Boolean}
33157 isExpanded : function(){
33158 return this.expanded;
33162 * Returns the UI object for this node
33163 * @return {TreeNodeUI}
33165 getUI : function(){
33169 // private override
33170 setFirstChild : function(node){
33171 var of = this.firstChild;
33172 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33173 if(this.childrenRendered && of && node != of){
33174 of.renderIndent(true, true);
33177 this.renderIndent(true, true);
33181 // private override
33182 setLastChild : function(node){
33183 var ol = this.lastChild;
33184 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33185 if(this.childrenRendered && ol && node != ol){
33186 ol.renderIndent(true, true);
33189 this.renderIndent(true, true);
33193 // these methods are overridden to provide lazy rendering support
33194 // private override
33195 appendChild : function()
33197 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33198 if(node && this.childrenRendered){
33201 this.ui.updateExpandIcon();
33205 // private override
33206 removeChild : function(node){
33207 this.ownerTree.getSelectionModel().unselect(node);
33208 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33209 // if it's been rendered remove dom node
33210 if(this.childrenRendered){
33213 if(this.childNodes.length < 1){
33214 this.collapse(false, false);
33216 this.ui.updateExpandIcon();
33218 if(!this.firstChild) {
33219 this.childrenRendered = false;
33224 // private override
33225 insertBefore : function(node, refNode){
33226 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33227 if(newNode && refNode && this.childrenRendered){
33230 this.ui.updateExpandIcon();
33235 * Sets the text for this node
33236 * @param {String} text
33238 setText : function(text){
33239 var oldText = this.text;
33241 this.attributes.text = text;
33242 if(this.rendered){ // event without subscribing
33243 this.ui.onTextChange(this, text, oldText);
33245 this.fireEvent("textchange", this, text, oldText);
33249 * Triggers selection of this node
33251 select : function(){
33252 this.getOwnerTree().getSelectionModel().select(this);
33256 * Triggers deselection of this node
33258 unselect : function(){
33259 this.getOwnerTree().getSelectionModel().unselect(this);
33263 * Returns true if this node is selected
33264 * @return {Boolean}
33266 isSelected : function(){
33267 return this.getOwnerTree().getSelectionModel().isSelected(this);
33271 * Expand this node.
33272 * @param {Boolean} deep (optional) True to expand all children as well
33273 * @param {Boolean} anim (optional) false to cancel the default animation
33274 * @param {Function} callback (optional) A callback to be called when
33275 * expanding this node completes (does not wait for deep expand to complete).
33276 * Called with 1 parameter, this node.
33278 expand : function(deep, anim, callback){
33279 if(!this.expanded){
33280 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33283 if(!this.childrenRendered){
33284 this.renderChildren();
33286 this.expanded = true;
33287 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33288 this.ui.animExpand(function(){
33289 this.fireEvent("expand", this);
33290 if(typeof callback == "function"){
33294 this.expandChildNodes(true);
33296 }.createDelegate(this));
33300 this.fireEvent("expand", this);
33301 if(typeof callback == "function"){
33306 if(typeof callback == "function"){
33311 this.expandChildNodes(true);
33315 isHiddenRoot : function(){
33316 return this.isRoot && !this.getOwnerTree().rootVisible;
33320 * Collapse this node.
33321 * @param {Boolean} deep (optional) True to collapse all children as well
33322 * @param {Boolean} anim (optional) false to cancel the default animation
33324 collapse : function(deep, anim){
33325 if(this.expanded && !this.isHiddenRoot()){
33326 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33329 this.expanded = false;
33330 if((this.getOwnerTree().animate && anim !== false) || anim){
33331 this.ui.animCollapse(function(){
33332 this.fireEvent("collapse", this);
33334 this.collapseChildNodes(true);
33336 }.createDelegate(this));
33339 this.ui.collapse();
33340 this.fireEvent("collapse", this);
33344 var cs = this.childNodes;
33345 for(var i = 0, len = cs.length; i < len; i++) {
33346 cs[i].collapse(true, false);
33352 delayedExpand : function(delay){
33353 if(!this.expandProcId){
33354 this.expandProcId = this.expand.defer(delay, this);
33359 cancelExpand : function(){
33360 if(this.expandProcId){
33361 clearTimeout(this.expandProcId);
33363 this.expandProcId = false;
33367 * Toggles expanded/collapsed state of the node
33369 toggle : function(){
33378 * Ensures all parent nodes are expanded
33380 ensureVisible : function(callback){
33381 var tree = this.getOwnerTree();
33382 tree.expandPath(this.parentNode.getPath(), false, function(){
33383 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33384 Roo.callback(callback);
33385 }.createDelegate(this));
33389 * Expand all child nodes
33390 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33392 expandChildNodes : function(deep){
33393 var cs = this.childNodes;
33394 for(var i = 0, len = cs.length; i < len; i++) {
33395 cs[i].expand(deep);
33400 * Collapse all child nodes
33401 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33403 collapseChildNodes : function(deep){
33404 var cs = this.childNodes;
33405 for(var i = 0, len = cs.length; i < len; i++) {
33406 cs[i].collapse(deep);
33411 * Disables this node
33413 disable : function(){
33414 this.disabled = true;
33416 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33417 this.ui.onDisableChange(this, true);
33419 this.fireEvent("disabledchange", this, true);
33423 * Enables this node
33425 enable : function(){
33426 this.disabled = false;
33427 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33428 this.ui.onDisableChange(this, false);
33430 this.fireEvent("disabledchange", this, false);
33434 renderChildren : function(suppressEvent){
33435 if(suppressEvent !== false){
33436 this.fireEvent("beforechildrenrendered", this);
33438 var cs = this.childNodes;
33439 for(var i = 0, len = cs.length; i < len; i++){
33440 cs[i].render(true);
33442 this.childrenRendered = true;
33446 sort : function(fn, scope){
33447 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33448 if(this.childrenRendered){
33449 var cs = this.childNodes;
33450 for(var i = 0, len = cs.length; i < len; i++){
33451 cs[i].render(true);
33457 render : function(bulkRender){
33458 this.ui.render(bulkRender);
33459 if(!this.rendered){
33460 this.rendered = true;
33462 this.expanded = false;
33463 this.expand(false, false);
33469 renderIndent : function(deep, refresh){
33471 this.ui.childIndent = null;
33473 this.ui.renderIndent();
33474 if(deep === true && this.childrenRendered){
33475 var cs = this.childNodes;
33476 for(var i = 0, len = cs.length; i < len; i++){
33477 cs[i].renderIndent(true, refresh);
33483 * Ext JS Library 1.1.1
33484 * Copyright(c) 2006-2007, Ext JS, LLC.
33486 * Originally Released Under LGPL - original licence link has changed is not relivant.
33489 * <script type="text/javascript">
33493 * @class Roo.tree.AsyncTreeNode
33494 * @extends Roo.tree.TreeNode
33495 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33497 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33499 Roo.tree.AsyncTreeNode = function(config){
33500 this.loaded = false;
33501 this.loading = false;
33502 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33504 * @event beforeload
33505 * Fires before this node is loaded, return false to cancel
33506 * @param {Node} this This node
33508 this.addEvents({'beforeload':true, 'load': true});
33511 * Fires when this node is loaded
33512 * @param {Node} this This node
33515 * The loader used by this node (defaults to using the tree's defined loader)
33520 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33521 expand : function(deep, anim, callback){
33522 if(this.loading){ // if an async load is already running, waiting til it's done
33524 var f = function(){
33525 if(!this.loading){ // done loading
33526 clearInterval(timer);
33527 this.expand(deep, anim, callback);
33529 }.createDelegate(this);
33530 timer = setInterval(f, 200);
33534 if(this.fireEvent("beforeload", this) === false){
33537 this.loading = true;
33538 this.ui.beforeLoad(this);
33539 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33541 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33545 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33549 * Returns true if this node is currently loading
33550 * @return {Boolean}
33552 isLoading : function(){
33553 return this.loading;
33556 loadComplete : function(deep, anim, callback){
33557 this.loading = false;
33558 this.loaded = true;
33559 this.ui.afterLoad(this);
33560 this.fireEvent("load", this);
33561 this.expand(deep, anim, callback);
33565 * Returns true if this node has been loaded
33566 * @return {Boolean}
33568 isLoaded : function(){
33569 return this.loaded;
33572 hasChildNodes : function(){
33573 if(!this.isLeaf() && !this.loaded){
33576 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33581 * Trigger a reload for this node
33582 * @param {Function} callback
33584 reload : function(callback){
33585 this.collapse(false, false);
33586 while(this.firstChild){
33587 this.removeChild(this.firstChild);
33589 this.childrenRendered = false;
33590 this.loaded = false;
33591 if(this.isHiddenRoot()){
33592 this.expanded = false;
33594 this.expand(false, false, callback);
33598 * Ext JS Library 1.1.1
33599 * Copyright(c) 2006-2007, Ext JS, LLC.
33601 * Originally Released Under LGPL - original licence link has changed is not relivant.
33604 * <script type="text/javascript">
33608 * @class Roo.tree.TreeNodeUI
33610 * @param {Object} node The node to render
33611 * The TreeNode UI implementation is separate from the
33612 * tree implementation. Unless you are customizing the tree UI,
33613 * you should never have to use this directly.
33615 Roo.tree.TreeNodeUI = function(node){
33617 this.rendered = false;
33618 this.animating = false;
33619 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33622 Roo.tree.TreeNodeUI.prototype = {
33623 removeChild : function(node){
33625 this.ctNode.removeChild(node.ui.getEl());
33629 beforeLoad : function(){
33630 this.addClass("x-tree-node-loading");
33633 afterLoad : function(){
33634 this.removeClass("x-tree-node-loading");
33637 onTextChange : function(node, text, oldText){
33639 this.textNode.innerHTML = text;
33643 onDisableChange : function(node, state){
33644 this.disabled = state;
33646 this.addClass("x-tree-node-disabled");
33648 this.removeClass("x-tree-node-disabled");
33652 onSelectedChange : function(state){
33655 this.addClass("x-tree-selected");
33658 this.removeClass("x-tree-selected");
33662 onMove : function(tree, node, oldParent, newParent, index, refNode){
33663 this.childIndent = null;
33665 var targetNode = newParent.ui.getContainer();
33666 if(!targetNode){//target not rendered
33667 this.holder = document.createElement("div");
33668 this.holder.appendChild(this.wrap);
33671 var insertBefore = refNode ? refNode.ui.getEl() : null;
33673 targetNode.insertBefore(this.wrap, insertBefore);
33675 targetNode.appendChild(this.wrap);
33677 this.node.renderIndent(true);
33681 addClass : function(cls){
33683 Roo.fly(this.elNode).addClass(cls);
33687 removeClass : function(cls){
33689 Roo.fly(this.elNode).removeClass(cls);
33693 remove : function(){
33695 this.holder = document.createElement("div");
33696 this.holder.appendChild(this.wrap);
33700 fireEvent : function(){
33701 return this.node.fireEvent.apply(this.node, arguments);
33704 initEvents : function(){
33705 this.node.on("move", this.onMove, this);
33706 var E = Roo.EventManager;
33707 var a = this.anchor;
33709 var el = Roo.fly(a, '_treeui');
33711 if(Roo.isOpera){ // opera render bug ignores the CSS
33712 el.setStyle("text-decoration", "none");
33715 el.on("click", this.onClick, this);
33716 el.on("dblclick", this.onDblClick, this);
33719 Roo.EventManager.on(this.checkbox,
33720 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33723 el.on("contextmenu", this.onContextMenu, this);
33725 var icon = Roo.fly(this.iconNode);
33726 icon.on("click", this.onClick, this);
33727 icon.on("dblclick", this.onDblClick, this);
33728 icon.on("contextmenu", this.onContextMenu, this);
33729 E.on(this.ecNode, "click", this.ecClick, this, true);
33731 if(this.node.disabled){
33732 this.addClass("x-tree-node-disabled");
33734 if(this.node.hidden){
33735 this.addClass("x-tree-node-disabled");
33737 var ot = this.node.getOwnerTree();
33738 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33739 if(dd && (!this.node.isRoot || ot.rootVisible)){
33740 Roo.dd.Registry.register(this.elNode, {
33742 handles: this.getDDHandles(),
33748 getDDHandles : function(){
33749 return [this.iconNode, this.textNode];
33754 this.wrap.style.display = "none";
33760 this.wrap.style.display = "";
33764 onContextMenu : function(e){
33765 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33766 e.preventDefault();
33768 this.fireEvent("contextmenu", this.node, e);
33772 onClick : function(e){
33777 if(this.fireEvent("beforeclick", this.node, e) !== false){
33778 if(!this.disabled && this.node.attributes.href){
33779 this.fireEvent("click", this.node, e);
33782 e.preventDefault();
33787 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33788 this.node.toggle();
33791 this.fireEvent("click", this.node, e);
33797 onDblClick : function(e){
33798 e.preventDefault();
33803 this.toggleCheck();
33805 if(!this.animating && this.node.hasChildNodes()){
33806 this.node.toggle();
33808 this.fireEvent("dblclick", this.node, e);
33811 onCheckChange : function(){
33812 var checked = this.checkbox.checked;
33813 this.node.attributes.checked = checked;
33814 this.fireEvent('checkchange', this.node, checked);
33817 ecClick : function(e){
33818 if(!this.animating && this.node.hasChildNodes()){
33819 this.node.toggle();
33823 startDrop : function(){
33824 this.dropping = true;
33827 // delayed drop so the click event doesn't get fired on a drop
33828 endDrop : function(){
33829 setTimeout(function(){
33830 this.dropping = false;
33831 }.createDelegate(this), 50);
33834 expand : function(){
33835 this.updateExpandIcon();
33836 this.ctNode.style.display = "";
33839 focus : function(){
33840 if(!this.node.preventHScroll){
33841 try{this.anchor.focus();
33843 }else if(!Roo.isIE){
33845 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
33846 var l = noscroll.scrollLeft;
33847 this.anchor.focus();
33848 noscroll.scrollLeft = l;
33853 toggleCheck : function(value){
33854 var cb = this.checkbox;
33856 cb.checked = (value === undefined ? !cb.checked : value);
33862 this.anchor.blur();
33866 animExpand : function(callback){
33867 var ct = Roo.get(this.ctNode);
33869 if(!this.node.hasChildNodes()){
33870 this.updateExpandIcon();
33871 this.ctNode.style.display = "";
33872 Roo.callback(callback);
33875 this.animating = true;
33876 this.updateExpandIcon();
33879 callback : function(){
33880 this.animating = false;
33881 Roo.callback(callback);
33884 duration: this.node.ownerTree.duration || .25
33888 highlight : function(){
33889 var tree = this.node.getOwnerTree();
33890 Roo.fly(this.wrap).highlight(
33891 tree.hlColor || "C3DAF9",
33892 {endColor: tree.hlBaseColor}
33896 collapse : function(){
33897 this.updateExpandIcon();
33898 this.ctNode.style.display = "none";
33901 animCollapse : function(callback){
33902 var ct = Roo.get(this.ctNode);
33903 ct.enableDisplayMode('block');
33906 this.animating = true;
33907 this.updateExpandIcon();
33910 callback : function(){
33911 this.animating = false;
33912 Roo.callback(callback);
33915 duration: this.node.ownerTree.duration || .25
33919 getContainer : function(){
33920 return this.ctNode;
33923 getEl : function(){
33927 appendDDGhost : function(ghostNode){
33928 ghostNode.appendChild(this.elNode.cloneNode(true));
33931 getDDRepairXY : function(){
33932 return Roo.lib.Dom.getXY(this.iconNode);
33935 onRender : function(){
33939 render : function(bulkRender){
33940 var n = this.node, a = n.attributes;
33941 var targetNode = n.parentNode ?
33942 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
33944 if(!this.rendered){
33945 this.rendered = true;
33947 this.renderElements(n, a, targetNode, bulkRender);
33950 if(this.textNode.setAttributeNS){
33951 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
33953 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
33956 this.textNode.setAttribute("ext:qtip", a.qtip);
33958 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
33961 }else if(a.qtipCfg){
33962 a.qtipCfg.target = Roo.id(this.textNode);
33963 Roo.QuickTips.register(a.qtipCfg);
33966 if(!this.node.expanded){
33967 this.updateExpandIcon();
33970 if(bulkRender === true) {
33971 targetNode.appendChild(this.wrap);
33976 renderElements : function(n, a, targetNode, bulkRender)
33978 // add some indent caching, this helps performance when rendering a large tree
33979 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
33980 var t = n.getOwnerTree();
33981 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
33982 if (typeof(n.attributes.html) != 'undefined') {
33983 txt = n.attributes.html;
33985 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
33986 var cb = typeof a.checked == 'boolean';
33987 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
33988 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
33989 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
33990 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
33991 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
33992 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
33993 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
33994 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
33995 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
33996 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
33999 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34000 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34001 n.nextSibling.ui.getEl(), buf.join(""));
34003 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34006 this.elNode = this.wrap.childNodes[0];
34007 this.ctNode = this.wrap.childNodes[1];
34008 var cs = this.elNode.childNodes;
34009 this.indentNode = cs[0];
34010 this.ecNode = cs[1];
34011 this.iconNode = cs[2];
34014 this.checkbox = cs[3];
34017 this.anchor = cs[index];
34018 this.textNode = cs[index].firstChild;
34021 getAnchor : function(){
34022 return this.anchor;
34025 getTextEl : function(){
34026 return this.textNode;
34029 getIconEl : function(){
34030 return this.iconNode;
34033 isChecked : function(){
34034 return this.checkbox ? this.checkbox.checked : false;
34037 updateExpandIcon : function(){
34039 var n = this.node, c1, c2;
34040 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34041 var hasChild = n.hasChildNodes();
34045 c1 = "x-tree-node-collapsed";
34046 c2 = "x-tree-node-expanded";
34049 c1 = "x-tree-node-expanded";
34050 c2 = "x-tree-node-collapsed";
34053 this.removeClass("x-tree-node-leaf");
34054 this.wasLeaf = false;
34056 if(this.c1 != c1 || this.c2 != c2){
34057 Roo.fly(this.elNode).replaceClass(c1, c2);
34058 this.c1 = c1; this.c2 = c2;
34061 // this changes non-leafs into leafs if they have no children.
34062 // it's not very rational behaviour..
34064 if(!this.wasLeaf && this.node.leaf){
34065 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34068 this.wasLeaf = true;
34071 var ecc = "x-tree-ec-icon "+cls;
34072 if(this.ecc != ecc){
34073 this.ecNode.className = ecc;
34079 getChildIndent : function(){
34080 if(!this.childIndent){
34084 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34086 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34088 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34093 this.childIndent = buf.join("");
34095 return this.childIndent;
34098 renderIndent : function(){
34101 var p = this.node.parentNode;
34103 indent = p.ui.getChildIndent();
34105 if(this.indentMarkup != indent){ // don't rerender if not required
34106 this.indentNode.innerHTML = indent;
34107 this.indentMarkup = indent;
34109 this.updateExpandIcon();
34114 Roo.tree.RootTreeNodeUI = function(){
34115 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34117 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34118 render : function(){
34119 if(!this.rendered){
34120 var targetNode = this.node.ownerTree.innerCt.dom;
34121 this.node.expanded = true;
34122 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34123 this.wrap = this.ctNode = targetNode.firstChild;
34126 collapse : function(){
34128 expand : function(){
34132 * Ext JS Library 1.1.1
34133 * Copyright(c) 2006-2007, Ext JS, LLC.
34135 * Originally Released Under LGPL - original licence link has changed is not relivant.
34138 * <script type="text/javascript">
34141 * @class Roo.tree.TreeLoader
34142 * @extends Roo.util.Observable
34143 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34144 * nodes from a specified URL. The response must be a javascript Array definition
34145 * who's elements are node definition objects. eg:
34150 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34151 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34158 * The old style respose with just an array is still supported, but not recommended.
34161 * A server request is sent, and child nodes are loaded only when a node is expanded.
34162 * The loading node's id is passed to the server under the parameter name "node" to
34163 * enable the server to produce the correct child nodes.
34165 * To pass extra parameters, an event handler may be attached to the "beforeload"
34166 * event, and the parameters specified in the TreeLoader's baseParams property:
34168 myTreeLoader.on("beforeload", function(treeLoader, node) {
34169 this.baseParams.category = node.attributes.category;
34172 * This would pass an HTTP parameter called "category" to the server containing
34173 * the value of the Node's "category" attribute.
34175 * Creates a new Treeloader.
34176 * @param {Object} config A config object containing config properties.
34178 Roo.tree.TreeLoader = function(config){
34179 this.baseParams = {};
34180 this.requestMethod = "POST";
34181 Roo.apply(this, config);
34186 * @event beforeload
34187 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34188 * @param {Object} This TreeLoader object.
34189 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34190 * @param {Object} callback The callback function specified in the {@link #load} call.
34195 * Fires when the node has been successfuly loaded.
34196 * @param {Object} This TreeLoader object.
34197 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34198 * @param {Object} response The response object containing the data from the server.
34202 * @event loadexception
34203 * Fires if the network request failed.
34204 * @param {Object} This TreeLoader object.
34205 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34206 * @param {Object} response The response object containing the data from the server.
34208 loadexception : true,
34211 * Fires before a node is created, enabling you to return custom Node types
34212 * @param {Object} This TreeLoader object.
34213 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34218 Roo.tree.TreeLoader.superclass.constructor.call(this);
34221 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34223 * @cfg {String} dataUrl The URL from which to request a Json string which
34224 * specifies an array of node definition object representing the child nodes
34228 * @cfg {String} requestMethod either GET or POST
34229 * defaults to POST (due to BC)
34233 * @cfg {Object} baseParams (optional) An object containing properties which
34234 * specify HTTP parameters to be passed to each request for child nodes.
34237 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34238 * created by this loader. If the attributes sent by the server have an attribute in this object,
34239 * they take priority.
34242 * @cfg {Object} uiProviders (optional) An object containing properties which
34244 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34245 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34246 * <i>uiProvider</i> attribute of a returned child node is a string rather
34247 * than a reference to a TreeNodeUI implementation, this that string value
34248 * is used as a property name in the uiProviders object. You can define the provider named
34249 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34254 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34255 * child nodes before loading.
34257 clearOnLoad : true,
34260 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34261 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34262 * Grid query { data : [ .....] }
34267 * @cfg {String} queryParam (optional)
34268 * Name of the query as it will be passed on the querystring (defaults to 'node')
34269 * eg. the request will be ?node=[id]
34276 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34277 * This is called automatically when a node is expanded, but may be used to reload
34278 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34279 * @param {Roo.tree.TreeNode} node
34280 * @param {Function} callback
34282 load : function(node, callback){
34283 if(this.clearOnLoad){
34284 while(node.firstChild){
34285 node.removeChild(node.firstChild);
34288 if(node.attributes.children){ // preloaded json children
34289 var cs = node.attributes.children;
34290 for(var i = 0, len = cs.length; i < len; i++){
34291 node.appendChild(this.createNode(cs[i]));
34293 if(typeof callback == "function"){
34296 }else if(this.dataUrl){
34297 this.requestData(node, callback);
34301 getParams: function(node){
34302 var buf = [], bp = this.baseParams;
34303 for(var key in bp){
34304 if(typeof bp[key] != "function"){
34305 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34308 var n = this.queryParam === false ? 'node' : this.queryParam;
34309 buf.push(n + "=", encodeURIComponent(node.id));
34310 return buf.join("");
34313 requestData : function(node, callback){
34314 if(this.fireEvent("beforeload", this, node, callback) !== false){
34315 this.transId = Roo.Ajax.request({
34316 method:this.requestMethod,
34317 url: this.dataUrl||this.url,
34318 success: this.handleResponse,
34319 failure: this.handleFailure,
34321 argument: {callback: callback, node: node},
34322 params: this.getParams(node)
34325 // if the load is cancelled, make sure we notify
34326 // the node that we are done
34327 if(typeof callback == "function"){
34333 isLoading : function(){
34334 return this.transId ? true : false;
34337 abort : function(){
34338 if(this.isLoading()){
34339 Roo.Ajax.abort(this.transId);
34344 createNode : function(attr)
34346 // apply baseAttrs, nice idea Corey!
34347 if(this.baseAttrs){
34348 Roo.applyIf(attr, this.baseAttrs);
34350 if(this.applyLoader !== false){
34351 attr.loader = this;
34353 // uiProvider = depreciated..
34355 if(typeof(attr.uiProvider) == 'string'){
34356 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34357 /** eval:var:attr */ eval(attr.uiProvider);
34359 if(typeof(this.uiProviders['default']) != 'undefined') {
34360 attr.uiProvider = this.uiProviders['default'];
34363 this.fireEvent('create', this, attr);
34365 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34367 new Roo.tree.TreeNode(attr) :
34368 new Roo.tree.AsyncTreeNode(attr));
34371 processResponse : function(response, node, callback)
34373 var json = response.responseText;
34376 var o = Roo.decode(json);
34378 if (this.root === false && typeof(o.success) != undefined) {
34379 this.root = 'data'; // the default behaviour for list like data..
34382 if (this.root !== false && !o.success) {
34383 // it's a failure condition.
34384 var a = response.argument;
34385 this.fireEvent("loadexception", this, a.node, response);
34386 Roo.log("Load failed - should have a handler really");
34392 if (this.root !== false) {
34396 for(var i = 0, len = o.length; i < len; i++){
34397 var n = this.createNode(o[i]);
34399 node.appendChild(n);
34402 if(typeof callback == "function"){
34403 callback(this, node);
34406 this.handleFailure(response);
34410 handleResponse : function(response){
34411 this.transId = false;
34412 var a = response.argument;
34413 this.processResponse(response, a.node, a.callback);
34414 this.fireEvent("load", this, a.node, response);
34417 handleFailure : function(response)
34419 // should handle failure better..
34420 this.transId = false;
34421 var a = response.argument;
34422 this.fireEvent("loadexception", this, a.node, response);
34423 if(typeof a.callback == "function"){
34424 a.callback(this, a.node);
34429 * Ext JS Library 1.1.1
34430 * Copyright(c) 2006-2007, Ext JS, LLC.
34432 * Originally Released Under LGPL - original licence link has changed is not relivant.
34435 * <script type="text/javascript">
34439 * @class Roo.tree.TreeFilter
34440 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34441 * @param {TreePanel} tree
34442 * @param {Object} config (optional)
34444 Roo.tree.TreeFilter = function(tree, config){
34446 this.filtered = {};
34447 Roo.apply(this, config);
34450 Roo.tree.TreeFilter.prototype = {
34457 * Filter the data by a specific attribute.
34458 * @param {String/RegExp} value Either string that the attribute value
34459 * should start with or a RegExp to test against the attribute
34460 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34461 * @param {TreeNode} startNode (optional) The node to start the filter at.
34463 filter : function(value, attr, startNode){
34464 attr = attr || "text";
34466 if(typeof value == "string"){
34467 var vlen = value.length;
34468 // auto clear empty filter
34469 if(vlen == 0 && this.clearBlank){
34473 value = value.toLowerCase();
34475 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34477 }else if(value.exec){ // regex?
34479 return value.test(n.attributes[attr]);
34482 throw 'Illegal filter type, must be string or regex';
34484 this.filterBy(f, null, startNode);
34488 * Filter by a function. The passed function will be called with each
34489 * node in the tree (or from the startNode). If the function returns true, the node is kept
34490 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34491 * @param {Function} fn The filter function
34492 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34494 filterBy : function(fn, scope, startNode){
34495 startNode = startNode || this.tree.root;
34496 if(this.autoClear){
34499 var af = this.filtered, rv = this.reverse;
34500 var f = function(n){
34501 if(n == startNode){
34507 var m = fn.call(scope || n, n);
34515 startNode.cascade(f);
34518 if(typeof id != "function"){
34520 if(n && n.parentNode){
34521 n.parentNode.removeChild(n);
34529 * Clears the current filter. Note: with the "remove" option
34530 * set a filter cannot be cleared.
34532 clear : function(){
34534 var af = this.filtered;
34536 if(typeof id != "function"){
34543 this.filtered = {};
34548 * Ext JS Library 1.1.1
34549 * Copyright(c) 2006-2007, Ext JS, LLC.
34551 * Originally Released Under LGPL - original licence link has changed is not relivant.
34554 * <script type="text/javascript">
34559 * @class Roo.tree.TreeSorter
34560 * Provides sorting of nodes in a TreePanel
34562 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34563 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34564 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34565 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34566 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34567 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34569 * @param {TreePanel} tree
34570 * @param {Object} config
34572 Roo.tree.TreeSorter = function(tree, config){
34573 Roo.apply(this, config);
34574 tree.on("beforechildrenrendered", this.doSort, this);
34575 tree.on("append", this.updateSort, this);
34576 tree.on("insert", this.updateSort, this);
34578 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34579 var p = this.property || "text";
34580 var sortType = this.sortType;
34581 var fs = this.folderSort;
34582 var cs = this.caseSensitive === true;
34583 var leafAttr = this.leafAttr || 'leaf';
34585 this.sortFn = function(n1, n2){
34587 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34590 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34594 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34595 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34597 return dsc ? +1 : -1;
34599 return dsc ? -1 : +1;
34606 Roo.tree.TreeSorter.prototype = {
34607 doSort : function(node){
34608 node.sort(this.sortFn);
34611 compareNodes : function(n1, n2){
34612 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34615 updateSort : function(tree, node){
34616 if(node.childrenRendered){
34617 this.doSort.defer(1, this, [node]);
34622 * Ext JS Library 1.1.1
34623 * Copyright(c) 2006-2007, Ext JS, LLC.
34625 * Originally Released Under LGPL - original licence link has changed is not relivant.
34628 * <script type="text/javascript">
34631 if(Roo.dd.DropZone){
34633 Roo.tree.TreeDropZone = function(tree, config){
34634 this.allowParentInsert = false;
34635 this.allowContainerDrop = false;
34636 this.appendOnly = false;
34637 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34639 this.lastInsertClass = "x-tree-no-status";
34640 this.dragOverData = {};
34643 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34644 ddGroup : "TreeDD",
34647 expandDelay : 1000,
34649 expandNode : function(node){
34650 if(node.hasChildNodes() && !node.isExpanded()){
34651 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34655 queueExpand : function(node){
34656 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34659 cancelExpand : function(){
34660 if(this.expandProcId){
34661 clearTimeout(this.expandProcId);
34662 this.expandProcId = false;
34666 isValidDropPoint : function(n, pt, dd, e, data){
34667 if(!n || !data){ return false; }
34668 var targetNode = n.node;
34669 var dropNode = data.node;
34670 // default drop rules
34671 if(!(targetNode && targetNode.isTarget && pt)){
34674 if(pt == "append" && targetNode.allowChildren === false){
34677 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34680 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34683 // reuse the object
34684 var overEvent = this.dragOverData;
34685 overEvent.tree = this.tree;
34686 overEvent.target = targetNode;
34687 overEvent.data = data;
34688 overEvent.point = pt;
34689 overEvent.source = dd;
34690 overEvent.rawEvent = e;
34691 overEvent.dropNode = dropNode;
34692 overEvent.cancel = false;
34693 var result = this.tree.fireEvent("nodedragover", overEvent);
34694 return overEvent.cancel === false && result !== false;
34697 getDropPoint : function(e, n, dd)
34701 return tn.allowChildren !== false ? "append" : false; // always append for root
34703 var dragEl = n.ddel;
34704 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34705 var y = Roo.lib.Event.getPageY(e);
34706 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34708 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34709 var noAppend = tn.allowChildren === false;
34710 if(this.appendOnly || tn.parentNode.allowChildren === false){
34711 return noAppend ? false : "append";
34713 var noBelow = false;
34714 if(!this.allowParentInsert){
34715 noBelow = tn.hasChildNodes() && tn.isExpanded();
34717 var q = (b - t) / (noAppend ? 2 : 3);
34718 if(y >= t && y < (t + q)){
34720 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34727 onNodeEnter : function(n, dd, e, data)
34729 this.cancelExpand();
34732 onNodeOver : function(n, dd, e, data)
34735 var pt = this.getDropPoint(e, n, dd);
34738 // auto node expand check
34739 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34740 this.queueExpand(node);
34741 }else if(pt != "append"){
34742 this.cancelExpand();
34745 // set the insert point style on the target node
34746 var returnCls = this.dropNotAllowed;
34747 if(this.isValidDropPoint(n, pt, dd, e, data)){
34752 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34753 cls = "x-tree-drag-insert-above";
34754 }else if(pt == "below"){
34755 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34756 cls = "x-tree-drag-insert-below";
34758 returnCls = "x-tree-drop-ok-append";
34759 cls = "x-tree-drag-append";
34761 if(this.lastInsertClass != cls){
34762 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34763 this.lastInsertClass = cls;
34770 onNodeOut : function(n, dd, e, data){
34772 this.cancelExpand();
34773 this.removeDropIndicators(n);
34776 onNodeDrop : function(n, dd, e, data){
34777 var point = this.getDropPoint(e, n, dd);
34778 var targetNode = n.node;
34779 targetNode.ui.startDrop();
34780 if(!this.isValidDropPoint(n, point, dd, e, data)){
34781 targetNode.ui.endDrop();
34784 // first try to find the drop node
34785 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34788 target: targetNode,
34793 dropNode: dropNode,
34796 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34797 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34798 targetNode.ui.endDrop();
34801 // allow target changing
34802 targetNode = dropEvent.target;
34803 if(point == "append" && !targetNode.isExpanded()){
34804 targetNode.expand(false, null, function(){
34805 this.completeDrop(dropEvent);
34806 }.createDelegate(this));
34808 this.completeDrop(dropEvent);
34813 completeDrop : function(de){
34814 var ns = de.dropNode, p = de.point, t = de.target;
34815 if(!(ns instanceof Array)){
34819 for(var i = 0, len = ns.length; i < len; i++){
34822 t.parentNode.insertBefore(n, t);
34823 }else if(p == "below"){
34824 t.parentNode.insertBefore(n, t.nextSibling);
34830 if(this.tree.hlDrop){
34834 this.tree.fireEvent("nodedrop", de);
34837 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
34838 if(this.tree.hlDrop){
34839 dropNode.ui.focus();
34840 dropNode.ui.highlight();
34842 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
34845 getTree : function(){
34849 removeDropIndicators : function(n){
34852 Roo.fly(el).removeClass([
34853 "x-tree-drag-insert-above",
34854 "x-tree-drag-insert-below",
34855 "x-tree-drag-append"]);
34856 this.lastInsertClass = "_noclass";
34860 beforeDragDrop : function(target, e, id){
34861 this.cancelExpand();
34865 afterRepair : function(data){
34866 if(data && Roo.enableFx){
34867 data.node.ui.highlight();
34877 * Ext JS Library 1.1.1
34878 * Copyright(c) 2006-2007, Ext JS, LLC.
34880 * Originally Released Under LGPL - original licence link has changed is not relivant.
34883 * <script type="text/javascript">
34887 if(Roo.dd.DragZone){
34888 Roo.tree.TreeDragZone = function(tree, config){
34889 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
34893 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
34894 ddGroup : "TreeDD",
34896 onBeforeDrag : function(data, e){
34898 return n && n.draggable && !n.disabled;
34902 onInitDrag : function(e){
34903 var data = this.dragData;
34904 this.tree.getSelectionModel().select(data.node);
34905 this.proxy.update("");
34906 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
34907 this.tree.fireEvent("startdrag", this.tree, data.node, e);
34910 getRepairXY : function(e, data){
34911 return data.node.ui.getDDRepairXY();
34914 onEndDrag : function(data, e){
34915 this.tree.fireEvent("enddrag", this.tree, data.node, e);
34920 onValidDrop : function(dd, e, id){
34921 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
34925 beforeInvalidDrop : function(e, id){
34926 // this scrolls the original position back into view
34927 var sm = this.tree.getSelectionModel();
34928 sm.clearSelections();
34929 sm.select(this.dragData.node);
34934 * Ext JS Library 1.1.1
34935 * Copyright(c) 2006-2007, Ext JS, LLC.
34937 * Originally Released Under LGPL - original licence link has changed is not relivant.
34940 * <script type="text/javascript">
34943 * @class Roo.tree.TreeEditor
34944 * @extends Roo.Editor
34945 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
34946 * as the editor field.
34948 * @param {Object} config (used to be the tree panel.)
34949 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
34951 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
34952 * @cfg {Roo.form.TextField|Object} field The field configuration
34956 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
34959 if (oldconfig) { // old style..
34960 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
34963 tree = config.tree;
34964 config.field = config.field || {};
34965 config.field.xtype = 'TextField';
34966 field = Roo.factory(config.field, Roo.form);
34968 config = config || {};
34973 * @event beforenodeedit
34974 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
34975 * false from the handler of this event.
34976 * @param {Editor} this
34977 * @param {Roo.tree.Node} node
34979 "beforenodeedit" : true
34983 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
34987 tree.on('beforeclick', this.beforeNodeClick, this);
34988 tree.getTreeEl().on('mousedown', this.hide, this);
34989 this.on('complete', this.updateNode, this);
34990 this.on('beforestartedit', this.fitToTree, this);
34991 this.on('startedit', this.bindScroll, this, {delay:10});
34992 this.on('specialkey', this.onSpecialKey, this);
34995 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
34997 * @cfg {String} alignment
34998 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35004 * @cfg {Boolean} hideEl
35005 * True to hide the bound element while the editor is displayed (defaults to false)
35009 * @cfg {String} cls
35010 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35012 cls: "x-small-editor x-tree-editor",
35014 * @cfg {Boolean} shim
35015 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35021 * @cfg {Number} maxWidth
35022 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35023 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35024 * scroll and client offsets into account prior to each edit.
35031 fitToTree : function(ed, el){
35032 var td = this.tree.getTreeEl().dom, nd = el.dom;
35033 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35034 td.scrollLeft = nd.offsetLeft;
35038 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35039 this.setSize(w, '');
35041 return this.fireEvent('beforenodeedit', this, this.editNode);
35046 triggerEdit : function(node){
35047 this.completeEdit();
35048 this.editNode = node;
35049 this.startEdit(node.ui.textNode, node.text);
35053 bindScroll : function(){
35054 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35058 beforeNodeClick : function(node, e){
35059 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35060 this.lastClick = new Date();
35061 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35063 this.triggerEdit(node);
35070 updateNode : function(ed, value){
35071 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35072 this.editNode.setText(value);
35076 onHide : function(){
35077 Roo.tree.TreeEditor.superclass.onHide.call(this);
35079 this.editNode.ui.focus();
35084 onSpecialKey : function(field, e){
35085 var k = e.getKey();
35089 }else if(k == e.ENTER && !e.hasModifier()){
35091 this.completeEdit();
35094 });//<Script type="text/javascript">
35097 * Ext JS Library 1.1.1
35098 * Copyright(c) 2006-2007, Ext JS, LLC.
35100 * Originally Released Under LGPL - original licence link has changed is not relivant.
35103 * <script type="text/javascript">
35107 * Not documented??? - probably should be...
35110 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35111 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35113 renderElements : function(n, a, targetNode, bulkRender){
35114 //consel.log("renderElements?");
35115 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35117 var t = n.getOwnerTree();
35118 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35120 var cols = t.columns;
35121 var bw = t.borderWidth;
35123 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35124 var cb = typeof a.checked == "boolean";
35125 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35126 var colcls = 'x-t-' + tid + '-c0';
35128 '<li class="x-tree-node">',
35131 '<div class="x-tree-node-el ', a.cls,'">',
35133 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35136 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35137 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35138 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35139 (a.icon ? ' x-tree-node-inline-icon' : ''),
35140 (a.iconCls ? ' '+a.iconCls : ''),
35141 '" unselectable="on" />',
35142 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35143 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35145 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35146 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35147 '<span unselectable="on" qtip="' + tx + '">',
35151 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35152 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35154 for(var i = 1, len = cols.length; i < len; i++){
35156 colcls = 'x-t-' + tid + '-c' +i;
35157 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35158 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35159 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35165 '<div class="x-clear"></div></div>',
35166 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35169 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35170 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35171 n.nextSibling.ui.getEl(), buf.join(""));
35173 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35175 var el = this.wrap.firstChild;
35177 this.elNode = el.firstChild;
35178 this.ranchor = el.childNodes[1];
35179 this.ctNode = this.wrap.childNodes[1];
35180 var cs = el.firstChild.childNodes;
35181 this.indentNode = cs[0];
35182 this.ecNode = cs[1];
35183 this.iconNode = cs[2];
35186 this.checkbox = cs[3];
35189 this.anchor = cs[index];
35191 this.textNode = cs[index].firstChild;
35193 //el.on("click", this.onClick, this);
35194 //el.on("dblclick", this.onDblClick, this);
35197 // console.log(this);
35199 initEvents : function(){
35200 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35203 var a = this.ranchor;
35205 var el = Roo.get(a);
35207 if(Roo.isOpera){ // opera render bug ignores the CSS
35208 el.setStyle("text-decoration", "none");
35211 el.on("click", this.onClick, this);
35212 el.on("dblclick", this.onDblClick, this);
35213 el.on("contextmenu", this.onContextMenu, this);
35217 /*onSelectedChange : function(state){
35220 this.addClass("x-tree-selected");
35223 this.removeClass("x-tree-selected");
35226 addClass : function(cls){
35228 Roo.fly(this.elRow).addClass(cls);
35234 removeClass : function(cls){
35236 Roo.fly(this.elRow).removeClass(cls);
35242 });//<Script type="text/javascript">
35246 * Ext JS Library 1.1.1
35247 * Copyright(c) 2006-2007, Ext JS, LLC.
35249 * Originally Released Under LGPL - original licence link has changed is not relivant.
35252 * <script type="text/javascript">
35257 * @class Roo.tree.ColumnTree
35258 * @extends Roo.data.TreePanel
35259 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35260 * @cfg {int} borderWidth compined right/left border allowance
35262 * @param {String/HTMLElement/Element} el The container element
35263 * @param {Object} config
35265 Roo.tree.ColumnTree = function(el, config)
35267 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35271 * Fire this event on a container when it resizes
35272 * @param {int} w Width
35273 * @param {int} h Height
35277 this.on('resize', this.onResize, this);
35280 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35284 borderWidth: Roo.isBorderBox ? 0 : 2,
35287 render : function(){
35288 // add the header.....
35290 Roo.tree.ColumnTree.superclass.render.apply(this);
35292 this.el.addClass('x-column-tree');
35294 this.headers = this.el.createChild(
35295 {cls:'x-tree-headers'},this.innerCt.dom);
35297 var cols = this.columns, c;
35298 var totalWidth = 0;
35300 var len = cols.length;
35301 for(var i = 0; i < len; i++){
35303 totalWidth += c.width;
35304 this.headEls.push(this.headers.createChild({
35305 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35307 cls:'x-tree-hd-text',
35310 style:'width:'+(c.width-this.borderWidth)+'px;'
35313 this.headers.createChild({cls:'x-clear'});
35314 // prevent floats from wrapping when clipped
35315 this.headers.setWidth(totalWidth);
35316 //this.innerCt.setWidth(totalWidth);
35317 this.innerCt.setStyle({ overflow: 'auto' });
35318 this.onResize(this.width, this.height);
35322 onResize : function(w,h)
35327 this.innerCt.setWidth(this.width);
35328 this.innerCt.setHeight(this.height-20);
35331 var cols = this.columns, c;
35332 var totalWidth = 0;
35334 var len = cols.length;
35335 for(var i = 0; i < len; i++){
35337 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35338 // it's the expander..
35339 expEl = this.headEls[i];
35342 totalWidth += c.width;
35346 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35348 this.headers.setWidth(w-20);
35357 * Ext JS Library 1.1.1
35358 * Copyright(c) 2006-2007, Ext JS, LLC.
35360 * Originally Released Under LGPL - original licence link has changed is not relivant.
35363 * <script type="text/javascript">
35367 * @class Roo.menu.Menu
35368 * @extends Roo.util.Observable
35369 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35370 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35372 * Creates a new Menu
35373 * @param {Object} config Configuration options
35375 Roo.menu.Menu = function(config){
35376 Roo.apply(this, config);
35377 this.id = this.id || Roo.id();
35380 * @event beforeshow
35381 * Fires before this menu is displayed
35382 * @param {Roo.menu.Menu} this
35386 * @event beforehide
35387 * Fires before this menu is hidden
35388 * @param {Roo.menu.Menu} this
35393 * Fires after this menu is displayed
35394 * @param {Roo.menu.Menu} this
35399 * Fires after this menu is hidden
35400 * @param {Roo.menu.Menu} this
35405 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35406 * @param {Roo.menu.Menu} this
35407 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35408 * @param {Roo.EventObject} e
35413 * Fires when the mouse is hovering over this menu
35414 * @param {Roo.menu.Menu} this
35415 * @param {Roo.EventObject} e
35416 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35421 * Fires when the mouse exits this menu
35422 * @param {Roo.menu.Menu} this
35423 * @param {Roo.EventObject} e
35424 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35429 * Fires when a menu item contained in this menu is clicked
35430 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35431 * @param {Roo.EventObject} e
35435 if (this.registerMenu) {
35436 Roo.menu.MenuMgr.register(this);
35439 var mis = this.items;
35440 this.items = new Roo.util.MixedCollection();
35442 this.add.apply(this, mis);
35446 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35448 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35452 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35453 * for bottom-right shadow (defaults to "sides")
35457 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35458 * this menu (defaults to "tl-tr?")
35460 subMenuAlign : "tl-tr?",
35462 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35463 * relative to its element of origin (defaults to "tl-bl?")
35465 defaultAlign : "tl-bl?",
35467 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35469 allowOtherMenus : false,
35471 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35473 registerMenu : true,
35478 render : function(){
35482 var el = this.el = new Roo.Layer({
35484 shadow:this.shadow,
35486 parentEl: this.parentEl || document.body,
35490 this.keyNav = new Roo.menu.MenuNav(this);
35493 el.addClass("x-menu-plain");
35496 el.addClass(this.cls);
35498 // generic focus element
35499 this.focusEl = el.createChild({
35500 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35502 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35503 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35505 ul.on("mouseover", this.onMouseOver, this);
35506 ul.on("mouseout", this.onMouseOut, this);
35507 this.items.each(function(item){
35512 var li = document.createElement("li");
35513 li.className = "x-menu-list-item";
35514 ul.dom.appendChild(li);
35515 item.render(li, this);
35522 autoWidth : function(){
35523 var el = this.el, ul = this.ul;
35527 var w = this.width;
35530 }else if(Roo.isIE){
35531 el.setWidth(this.minWidth);
35532 var t = el.dom.offsetWidth; // force recalc
35533 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35538 delayAutoWidth : function(){
35541 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35543 this.awTask.delay(20);
35548 findTargetItem : function(e){
35549 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35550 if(t && t.menuItemId){
35551 return this.items.get(t.menuItemId);
35556 onClick : function(e){
35557 Roo.log("menu.onClick");
35558 var t = this.findTargetItem(e);
35563 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35564 if(t == this.activeItem && t.shouldDeactivate(e)){
35565 this.activeItem.deactivate();
35566 delete this.activeItem;
35570 this.setActiveItem(t, true);
35578 this.fireEvent("click", this, t, e);
35582 setActiveItem : function(item, autoExpand){
35583 if(item != this.activeItem){
35584 if(this.activeItem){
35585 this.activeItem.deactivate();
35587 this.activeItem = item;
35588 item.activate(autoExpand);
35589 }else if(autoExpand){
35595 tryActivate : function(start, step){
35596 var items = this.items;
35597 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35598 var item = items.get(i);
35599 if(!item.disabled && item.canActivate){
35600 this.setActiveItem(item, false);
35608 onMouseOver : function(e){
35610 if(t = this.findTargetItem(e)){
35611 if(t.canActivate && !t.disabled){
35612 this.setActiveItem(t, true);
35615 this.fireEvent("mouseover", this, e, t);
35619 onMouseOut : function(e){
35621 if(t = this.findTargetItem(e)){
35622 if(t == this.activeItem && t.shouldDeactivate(e)){
35623 this.activeItem.deactivate();
35624 delete this.activeItem;
35627 this.fireEvent("mouseout", this, e, t);
35631 * Read-only. Returns true if the menu is currently displayed, else false.
35634 isVisible : function(){
35635 return this.el && !this.hidden;
35639 * Displays this menu relative to another element
35640 * @param {String/HTMLElement/Roo.Element} element The element to align to
35641 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35642 * the element (defaults to this.defaultAlign)
35643 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35645 show : function(el, pos, parentMenu){
35646 this.parentMenu = parentMenu;
35650 this.fireEvent("beforeshow", this);
35651 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35655 * Displays this menu at a specific xy position
35656 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35657 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35659 showAt : function(xy, parentMenu, /* private: */_e){
35660 this.parentMenu = parentMenu;
35665 this.fireEvent("beforeshow", this);
35666 xy = this.el.adjustForConstraints(xy);
35670 this.hidden = false;
35672 this.fireEvent("show", this);
35675 focus : function(){
35677 this.doFocus.defer(50, this);
35681 doFocus : function(){
35683 this.focusEl.focus();
35688 * Hides this menu and optionally all parent menus
35689 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35691 hide : function(deep){
35692 if(this.el && this.isVisible()){
35693 this.fireEvent("beforehide", this);
35694 if(this.activeItem){
35695 this.activeItem.deactivate();
35696 this.activeItem = null;
35699 this.hidden = true;
35700 this.fireEvent("hide", this);
35702 if(deep === true && this.parentMenu){
35703 this.parentMenu.hide(true);
35708 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35709 * Any of the following are valid:
35711 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35712 * <li>An HTMLElement object which will be converted to a menu item</li>
35713 * <li>A menu item config object that will be created as a new menu item</li>
35714 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35715 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35720 var menu = new Roo.menu.Menu();
35722 // Create a menu item to add by reference
35723 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35725 // Add a bunch of items at once using different methods.
35726 // Only the last item added will be returned.
35727 var item = menu.add(
35728 menuItem, // add existing item by ref
35729 'Dynamic Item', // new TextItem
35730 '-', // new separator
35731 { text: 'Config Item' } // new item by config
35734 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35735 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35738 var a = arguments, l = a.length, item;
35739 for(var i = 0; i < l; i++){
35741 if ((typeof(el) == "object") && el.xtype && el.xns) {
35742 el = Roo.factory(el, Roo.menu);
35745 if(el.render){ // some kind of Item
35746 item = this.addItem(el);
35747 }else if(typeof el == "string"){ // string
35748 if(el == "separator" || el == "-"){
35749 item = this.addSeparator();
35751 item = this.addText(el);
35753 }else if(el.tagName || el.el){ // element
35754 item = this.addElement(el);
35755 }else if(typeof el == "object"){ // must be menu item config?
35756 item = this.addMenuItem(el);
35763 * Returns this menu's underlying {@link Roo.Element} object
35764 * @return {Roo.Element} The element
35766 getEl : function(){
35774 * Adds a separator bar to the menu
35775 * @return {Roo.menu.Item} The menu item that was added
35777 addSeparator : function(){
35778 return this.addItem(new Roo.menu.Separator());
35782 * Adds an {@link Roo.Element} object to the menu
35783 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35784 * @return {Roo.menu.Item} The menu item that was added
35786 addElement : function(el){
35787 return this.addItem(new Roo.menu.BaseItem(el));
35791 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35792 * @param {Roo.menu.Item} item The menu item to add
35793 * @return {Roo.menu.Item} The menu item that was added
35795 addItem : function(item){
35796 this.items.add(item);
35798 var li = document.createElement("li");
35799 li.className = "x-menu-list-item";
35800 this.ul.dom.appendChild(li);
35801 item.render(li, this);
35802 this.delayAutoWidth();
35808 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35809 * @param {Object} config A MenuItem config object
35810 * @return {Roo.menu.Item} The menu item that was added
35812 addMenuItem : function(config){
35813 if(!(config instanceof Roo.menu.Item)){
35814 if(typeof config.checked == "boolean"){ // must be check menu item config?
35815 config = new Roo.menu.CheckItem(config);
35817 config = new Roo.menu.Item(config);
35820 return this.addItem(config);
35824 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
35825 * @param {String} text The text to display in the menu item
35826 * @return {Roo.menu.Item} The menu item that was added
35828 addText : function(text){
35829 return this.addItem(new Roo.menu.TextItem({ text : text }));
35833 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
35834 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
35835 * @param {Roo.menu.Item} item The menu item to add
35836 * @return {Roo.menu.Item} The menu item that was added
35838 insert : function(index, item){
35839 this.items.insert(index, item);
35841 var li = document.createElement("li");
35842 li.className = "x-menu-list-item";
35843 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
35844 item.render(li, this);
35845 this.delayAutoWidth();
35851 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
35852 * @param {Roo.menu.Item} item The menu item to remove
35854 remove : function(item){
35855 this.items.removeKey(item.id);
35860 * Removes and destroys all items in the menu
35862 removeAll : function(){
35864 while(f = this.items.first()){
35870 // MenuNav is a private utility class used internally by the Menu
35871 Roo.menu.MenuNav = function(menu){
35872 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
35873 this.scope = this.menu = menu;
35876 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
35877 doRelay : function(e, h){
35878 var k = e.getKey();
35879 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
35880 this.menu.tryActivate(0, 1);
35883 return h.call(this.scope || this, e, this.menu);
35886 up : function(e, m){
35887 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
35888 m.tryActivate(m.items.length-1, -1);
35892 down : function(e, m){
35893 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
35894 m.tryActivate(0, 1);
35898 right : function(e, m){
35900 m.activeItem.expandMenu(true);
35904 left : function(e, m){
35906 if(m.parentMenu && m.parentMenu.activeItem){
35907 m.parentMenu.activeItem.activate();
35911 enter : function(e, m){
35913 e.stopPropagation();
35914 m.activeItem.onClick(e);
35915 m.fireEvent("click", this, m.activeItem);
35921 * Ext JS Library 1.1.1
35922 * Copyright(c) 2006-2007, Ext JS, LLC.
35924 * Originally Released Under LGPL - original licence link has changed is not relivant.
35927 * <script type="text/javascript">
35931 * @class Roo.menu.MenuMgr
35932 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
35935 Roo.menu.MenuMgr = function(){
35936 var menus, active, groups = {}, attached = false, lastShow = new Date();
35938 // private - called when first menu is created
35941 active = new Roo.util.MixedCollection();
35942 Roo.get(document).addKeyListener(27, function(){
35943 if(active.length > 0){
35950 function hideAll(){
35951 if(active && active.length > 0){
35952 var c = active.clone();
35953 c.each(function(m){
35960 function onHide(m){
35962 if(active.length < 1){
35963 Roo.get(document).un("mousedown", onMouseDown);
35969 function onShow(m){
35970 var last = active.last();
35971 lastShow = new Date();
35974 Roo.get(document).on("mousedown", onMouseDown);
35978 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
35979 m.parentMenu.activeChild = m;
35980 }else if(last && last.isVisible()){
35981 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
35986 function onBeforeHide(m){
35988 m.activeChild.hide();
35990 if(m.autoHideTimer){
35991 clearTimeout(m.autoHideTimer);
35992 delete m.autoHideTimer;
35997 function onBeforeShow(m){
35998 var pm = m.parentMenu;
35999 if(!pm && !m.allowOtherMenus){
36001 }else if(pm && pm.activeChild && active != m){
36002 pm.activeChild.hide();
36007 function onMouseDown(e){
36008 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36014 function onBeforeCheck(mi, state){
36016 var g = groups[mi.group];
36017 for(var i = 0, l = g.length; i < l; i++){
36019 g[i].setChecked(false);
36028 * Hides all menus that are currently visible
36030 hideAll : function(){
36035 register : function(menu){
36039 menus[menu.id] = menu;
36040 menu.on("beforehide", onBeforeHide);
36041 menu.on("hide", onHide);
36042 menu.on("beforeshow", onBeforeShow);
36043 menu.on("show", onShow);
36044 var g = menu.group;
36045 if(g && menu.events["checkchange"]){
36049 groups[g].push(menu);
36050 menu.on("checkchange", onCheck);
36055 * Returns a {@link Roo.menu.Menu} object
36056 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36057 * be used to generate and return a new Menu instance.
36059 get : function(menu){
36060 if(typeof menu == "string"){ // menu id
36061 return menus[menu];
36062 }else if(menu.events){ // menu instance
36064 }else if(typeof menu.length == 'number'){ // array of menu items?
36065 return new Roo.menu.Menu({items:menu});
36066 }else{ // otherwise, must be a config
36067 return new Roo.menu.Menu(menu);
36072 unregister : function(menu){
36073 delete menus[menu.id];
36074 menu.un("beforehide", onBeforeHide);
36075 menu.un("hide", onHide);
36076 menu.un("beforeshow", onBeforeShow);
36077 menu.un("show", onShow);
36078 var g = menu.group;
36079 if(g && menu.events["checkchange"]){
36080 groups[g].remove(menu);
36081 menu.un("checkchange", onCheck);
36086 registerCheckable : function(menuItem){
36087 var g = menuItem.group;
36092 groups[g].push(menuItem);
36093 menuItem.on("beforecheckchange", onBeforeCheck);
36098 unregisterCheckable : function(menuItem){
36099 var g = menuItem.group;
36101 groups[g].remove(menuItem);
36102 menuItem.un("beforecheckchange", onBeforeCheck);
36108 * Ext JS Library 1.1.1
36109 * Copyright(c) 2006-2007, Ext JS, LLC.
36111 * Originally Released Under LGPL - original licence link has changed is not relivant.
36114 * <script type="text/javascript">
36119 * @class Roo.menu.BaseItem
36120 * @extends Roo.Component
36121 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36122 * management and base configuration options shared by all menu components.
36124 * Creates a new BaseItem
36125 * @param {Object} config Configuration options
36127 Roo.menu.BaseItem = function(config){
36128 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36133 * Fires when this item is clicked
36134 * @param {Roo.menu.BaseItem} this
36135 * @param {Roo.EventObject} e
36140 * Fires when this item is activated
36141 * @param {Roo.menu.BaseItem} this
36145 * @event deactivate
36146 * Fires when this item is deactivated
36147 * @param {Roo.menu.BaseItem} this
36153 this.on("click", this.handler, this.scope, true);
36157 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36159 * @cfg {Function} handler
36160 * A function that will handle the click event of this menu item (defaults to undefined)
36163 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36165 canActivate : false,
36168 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36173 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36175 activeClass : "x-menu-item-active",
36177 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36179 hideOnClick : true,
36181 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36186 ctype: "Roo.menu.BaseItem",
36189 actionMode : "container",
36192 render : function(container, parentMenu){
36193 this.parentMenu = parentMenu;
36194 Roo.menu.BaseItem.superclass.render.call(this, container);
36195 this.container.menuItemId = this.id;
36199 onRender : function(container, position){
36200 this.el = Roo.get(this.el);
36201 container.dom.appendChild(this.el.dom);
36205 onClick : function(e){
36206 if(!this.disabled && this.fireEvent("click", this, e) !== false
36207 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36208 this.handleClick(e);
36215 activate : function(){
36219 var li = this.container;
36220 li.addClass(this.activeClass);
36221 this.region = li.getRegion().adjust(2, 2, -2, -2);
36222 this.fireEvent("activate", this);
36227 deactivate : function(){
36228 this.container.removeClass(this.activeClass);
36229 this.fireEvent("deactivate", this);
36233 shouldDeactivate : function(e){
36234 return !this.region || !this.region.contains(e.getPoint());
36238 handleClick : function(e){
36239 if(this.hideOnClick){
36240 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36245 expandMenu : function(autoActivate){
36250 hideMenu : function(){
36255 * Ext JS Library 1.1.1
36256 * Copyright(c) 2006-2007, Ext JS, LLC.
36258 * Originally Released Under LGPL - original licence link has changed is not relivant.
36261 * <script type="text/javascript">
36265 * @class Roo.menu.Adapter
36266 * @extends Roo.menu.BaseItem
36267 * 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.
36268 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36270 * Creates a new Adapter
36271 * @param {Object} config Configuration options
36273 Roo.menu.Adapter = function(component, config){
36274 Roo.menu.Adapter.superclass.constructor.call(this, config);
36275 this.component = component;
36277 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36279 canActivate : true,
36282 onRender : function(container, position){
36283 this.component.render(container);
36284 this.el = this.component.getEl();
36288 activate : function(){
36292 this.component.focus();
36293 this.fireEvent("activate", this);
36298 deactivate : function(){
36299 this.fireEvent("deactivate", this);
36303 disable : function(){
36304 this.component.disable();
36305 Roo.menu.Adapter.superclass.disable.call(this);
36309 enable : function(){
36310 this.component.enable();
36311 Roo.menu.Adapter.superclass.enable.call(this);
36315 * Ext JS Library 1.1.1
36316 * Copyright(c) 2006-2007, Ext JS, LLC.
36318 * Originally Released Under LGPL - original licence link has changed is not relivant.
36321 * <script type="text/javascript">
36325 * @class Roo.menu.TextItem
36326 * @extends Roo.menu.BaseItem
36327 * Adds a static text string to a menu, usually used as either a heading or group separator.
36328 * Note: old style constructor with text is still supported.
36331 * Creates a new TextItem
36332 * @param {Object} cfg Configuration
36334 Roo.menu.TextItem = function(cfg){
36335 if (typeof(cfg) == 'string') {
36338 Roo.apply(this,cfg);
36341 Roo.menu.TextItem.superclass.constructor.call(this);
36344 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36346 * @cfg {Boolean} text Text to show on item.
36351 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36353 hideOnClick : false,
36355 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36357 itemCls : "x-menu-text",
36360 onRender : function(){
36361 var s = document.createElement("span");
36362 s.className = this.itemCls;
36363 s.innerHTML = this.text;
36365 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36369 * Ext JS Library 1.1.1
36370 * Copyright(c) 2006-2007, Ext JS, LLC.
36372 * Originally Released Under LGPL - original licence link has changed is not relivant.
36375 * <script type="text/javascript">
36379 * @class Roo.menu.Separator
36380 * @extends Roo.menu.BaseItem
36381 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36382 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36384 * @param {Object} config Configuration options
36386 Roo.menu.Separator = function(config){
36387 Roo.menu.Separator.superclass.constructor.call(this, config);
36390 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36392 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36394 itemCls : "x-menu-sep",
36396 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36398 hideOnClick : false,
36401 onRender : function(li){
36402 var s = document.createElement("span");
36403 s.className = this.itemCls;
36404 s.innerHTML = " ";
36406 li.addClass("x-menu-sep-li");
36407 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36411 * Ext JS Library 1.1.1
36412 * Copyright(c) 2006-2007, Ext JS, LLC.
36414 * Originally Released Under LGPL - original licence link has changed is not relivant.
36417 * <script type="text/javascript">
36420 * @class Roo.menu.Item
36421 * @extends Roo.menu.BaseItem
36422 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36423 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36424 * activation and click handling.
36426 * Creates a new Item
36427 * @param {Object} config Configuration options
36429 Roo.menu.Item = function(config){
36430 Roo.menu.Item.superclass.constructor.call(this, config);
36432 this.menu = Roo.menu.MenuMgr.get(this.menu);
36435 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36438 * @cfg {String} text
36439 * The text to show on the menu item.
36443 * @cfg {String} HTML to render in menu
36444 * The text to show on the menu item (HTML version).
36448 * @cfg {String} icon
36449 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36453 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36455 itemCls : "x-menu-item",
36457 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36459 canActivate : true,
36461 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36464 // doc'd in BaseItem
36468 ctype: "Roo.menu.Item",
36471 onRender : function(container, position){
36472 var el = document.createElement("a");
36473 el.hideFocus = true;
36474 el.unselectable = "on";
36475 el.href = this.href || "#";
36476 if(this.hrefTarget){
36477 el.target = this.hrefTarget;
36479 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36481 var html = this.html.length ? this.html : String.format('{0}',this.text);
36483 el.innerHTML = String.format(
36484 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36485 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36487 Roo.menu.Item.superclass.onRender.call(this, container, position);
36491 * Sets the text to display in this menu item
36492 * @param {String} text The text to display
36493 * @param {Boolean} isHTML true to indicate text is pure html.
36495 setText : function(text, isHTML){
36503 var html = this.html.length ? this.html : String.format('{0}',this.text);
36505 this.el.update(String.format(
36506 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36507 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36508 this.parentMenu.autoWidth();
36513 handleClick : function(e){
36514 if(!this.href){ // if no link defined, stop the event automatically
36517 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36521 activate : function(autoExpand){
36522 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36532 shouldDeactivate : function(e){
36533 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36534 if(this.menu && this.menu.isVisible()){
36535 return !this.menu.getEl().getRegion().contains(e.getPoint());
36543 deactivate : function(){
36544 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36549 expandMenu : function(autoActivate){
36550 if(!this.disabled && this.menu){
36551 clearTimeout(this.hideTimer);
36552 delete this.hideTimer;
36553 if(!this.menu.isVisible() && !this.showTimer){
36554 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36555 }else if (this.menu.isVisible() && autoActivate){
36556 this.menu.tryActivate(0, 1);
36562 deferExpand : function(autoActivate){
36563 delete this.showTimer;
36564 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36566 this.menu.tryActivate(0, 1);
36571 hideMenu : function(){
36572 clearTimeout(this.showTimer);
36573 delete this.showTimer;
36574 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36575 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36580 deferHide : function(){
36581 delete this.hideTimer;
36586 * Ext JS Library 1.1.1
36587 * Copyright(c) 2006-2007, Ext JS, LLC.
36589 * Originally Released Under LGPL - original licence link has changed is not relivant.
36592 * <script type="text/javascript">
36596 * @class Roo.menu.CheckItem
36597 * @extends Roo.menu.Item
36598 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36600 * Creates a new CheckItem
36601 * @param {Object} config Configuration options
36603 Roo.menu.CheckItem = function(config){
36604 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36607 * @event beforecheckchange
36608 * Fires before the checked value is set, providing an opportunity to cancel if needed
36609 * @param {Roo.menu.CheckItem} this
36610 * @param {Boolean} checked The new checked value that will be set
36612 "beforecheckchange" : true,
36614 * @event checkchange
36615 * Fires after the checked value has been set
36616 * @param {Roo.menu.CheckItem} this
36617 * @param {Boolean} checked The checked value that was set
36619 "checkchange" : true
36621 if(this.checkHandler){
36622 this.on('checkchange', this.checkHandler, this.scope);
36625 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36627 * @cfg {String} group
36628 * All check items with the same group name will automatically be grouped into a single-select
36629 * radio button group (defaults to '')
36632 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36634 itemCls : "x-menu-item x-menu-check-item",
36636 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36638 groupClass : "x-menu-group-item",
36641 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36642 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36643 * initialized with checked = true will be rendered as checked.
36648 ctype: "Roo.menu.CheckItem",
36651 onRender : function(c){
36652 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36654 this.el.addClass(this.groupClass);
36656 Roo.menu.MenuMgr.registerCheckable(this);
36658 this.checked = false;
36659 this.setChecked(true, true);
36664 destroy : function(){
36666 Roo.menu.MenuMgr.unregisterCheckable(this);
36668 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36672 * Set the checked state of this item
36673 * @param {Boolean} checked The new checked value
36674 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36676 setChecked : function(state, suppressEvent){
36677 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36678 if(this.container){
36679 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36681 this.checked = state;
36682 if(suppressEvent !== true){
36683 this.fireEvent("checkchange", this, state);
36689 handleClick : function(e){
36690 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36691 this.setChecked(!this.checked);
36693 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36697 * Ext JS Library 1.1.1
36698 * Copyright(c) 2006-2007, Ext JS, LLC.
36700 * Originally Released Under LGPL - original licence link has changed is not relivant.
36703 * <script type="text/javascript">
36707 * @class Roo.menu.DateItem
36708 * @extends Roo.menu.Adapter
36709 * A menu item that wraps the {@link Roo.DatPicker} component.
36711 * Creates a new DateItem
36712 * @param {Object} config Configuration options
36714 Roo.menu.DateItem = function(config){
36715 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36716 /** The Roo.DatePicker object @type Roo.DatePicker */
36717 this.picker = this.component;
36718 this.addEvents({select: true});
36720 this.picker.on("render", function(picker){
36721 picker.getEl().swallowEvent("click");
36722 picker.container.addClass("x-menu-date-item");
36725 this.picker.on("select", this.onSelect, this);
36728 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36730 onSelect : function(picker, date){
36731 this.fireEvent("select", this, date, picker);
36732 Roo.menu.DateItem.superclass.handleClick.call(this);
36736 * Ext JS Library 1.1.1
36737 * Copyright(c) 2006-2007, Ext JS, LLC.
36739 * Originally Released Under LGPL - original licence link has changed is not relivant.
36742 * <script type="text/javascript">
36746 * @class Roo.menu.ColorItem
36747 * @extends Roo.menu.Adapter
36748 * A menu item that wraps the {@link Roo.ColorPalette} component.
36750 * Creates a new ColorItem
36751 * @param {Object} config Configuration options
36753 Roo.menu.ColorItem = function(config){
36754 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36755 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36756 this.palette = this.component;
36757 this.relayEvents(this.palette, ["select"]);
36758 if(this.selectHandler){
36759 this.on('select', this.selectHandler, this.scope);
36762 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36764 * Ext JS Library 1.1.1
36765 * Copyright(c) 2006-2007, Ext JS, LLC.
36767 * Originally Released Under LGPL - original licence link has changed is not relivant.
36770 * <script type="text/javascript">
36775 * @class Roo.menu.DateMenu
36776 * @extends Roo.menu.Menu
36777 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36779 * Creates a new DateMenu
36780 * @param {Object} config Configuration options
36782 Roo.menu.DateMenu = function(config){
36783 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36785 var di = new Roo.menu.DateItem(config);
36788 * The {@link Roo.DatePicker} instance for this DateMenu
36791 this.picker = di.picker;
36794 * @param {DatePicker} picker
36795 * @param {Date} date
36797 this.relayEvents(di, ["select"]);
36798 this.on('beforeshow', function(){
36800 this.picker.hideMonthPicker(false);
36804 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36808 * Ext JS Library 1.1.1
36809 * Copyright(c) 2006-2007, Ext JS, LLC.
36811 * Originally Released Under LGPL - original licence link has changed is not relivant.
36814 * <script type="text/javascript">
36819 * @class Roo.menu.ColorMenu
36820 * @extends Roo.menu.Menu
36821 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
36823 * Creates a new ColorMenu
36824 * @param {Object} config Configuration options
36826 Roo.menu.ColorMenu = function(config){
36827 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
36829 var ci = new Roo.menu.ColorItem(config);
36832 * The {@link Roo.ColorPalette} instance for this ColorMenu
36833 * @type ColorPalette
36835 this.palette = ci.palette;
36838 * @param {ColorPalette} palette
36839 * @param {String} color
36841 this.relayEvents(ci, ["select"]);
36843 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
36845 * Ext JS Library 1.1.1
36846 * Copyright(c) 2006-2007, Ext JS, LLC.
36848 * Originally Released Under LGPL - original licence link has changed is not relivant.
36851 * <script type="text/javascript">
36855 * @class Roo.form.Field
36856 * @extends Roo.BoxComponent
36857 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
36859 * Creates a new Field
36860 * @param {Object} config Configuration options
36862 Roo.form.Field = function(config){
36863 Roo.form.Field.superclass.constructor.call(this, config);
36866 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
36868 * @cfg {String} fieldLabel Label to use when rendering a form.
36871 * @cfg {String} qtip Mouse over tip
36875 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
36877 invalidClass : "x-form-invalid",
36879 * @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")
36881 invalidText : "The value in this field is invalid",
36883 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
36885 focusClass : "x-form-focus",
36887 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
36888 automatic validation (defaults to "keyup").
36890 validationEvent : "keyup",
36892 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
36894 validateOnBlur : true,
36896 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
36898 validationDelay : 250,
36900 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
36901 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
36903 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
36905 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
36907 fieldClass : "x-form-field",
36909 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
36912 ----------- ----------------------------------------------------------------------
36913 qtip Display a quick tip when the user hovers over the field
36914 title Display a default browser title attribute popup
36915 under Add a block div beneath the field containing the error text
36916 side Add an error icon to the right of the field with a popup on hover
36917 [element id] Add the error text directly to the innerHTML of the specified element
36920 msgTarget : 'qtip',
36922 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
36927 * @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.
36932 * @cfg {Boolean} disabled True to disable the field (defaults to false).
36937 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
36939 inputType : undefined,
36942 * @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).
36944 tabIndex : undefined,
36947 isFormField : true,
36952 * @property {Roo.Element} fieldEl
36953 * Element Containing the rendered Field (with label etc.)
36956 * @cfg {Mixed} value A value to initialize this field with.
36961 * @cfg {String} name The field's HTML name attribute.
36964 * @cfg {String} cls A CSS class to apply to the field's underlying element.
36968 initComponent : function(){
36969 Roo.form.Field.superclass.initComponent.call(this);
36973 * Fires when this field receives input focus.
36974 * @param {Roo.form.Field} this
36979 * Fires when this field loses input focus.
36980 * @param {Roo.form.Field} this
36984 * @event specialkey
36985 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
36986 * {@link Roo.EventObject#getKey} to determine which key was pressed.
36987 * @param {Roo.form.Field} this
36988 * @param {Roo.EventObject} e The event object
36993 * Fires just before the field blurs if the field value has changed.
36994 * @param {Roo.form.Field} this
36995 * @param {Mixed} newValue The new value
36996 * @param {Mixed} oldValue The original value
37001 * Fires after the field has been marked as invalid.
37002 * @param {Roo.form.Field} this
37003 * @param {String} msg The validation message
37008 * Fires after the field has been validated with no errors.
37009 * @param {Roo.form.Field} this
37014 * Fires after the key up
37015 * @param {Roo.form.Field} this
37016 * @param {Roo.EventObject} e The event Object
37023 * Returns the name attribute of the field if available
37024 * @return {String} name The field name
37026 getName: function(){
37027 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37031 onRender : function(ct, position){
37032 Roo.form.Field.superclass.onRender.call(this, ct, position);
37034 var cfg = this.getAutoCreate();
37036 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37038 if (!cfg.name.length) {
37041 if(this.inputType){
37042 cfg.type = this.inputType;
37044 this.el = ct.createChild(cfg, position);
37046 var type = this.el.dom.type;
37048 if(type == 'password'){
37051 this.el.addClass('x-form-'+type);
37054 this.el.dom.readOnly = true;
37056 if(this.tabIndex !== undefined){
37057 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37060 this.el.addClass([this.fieldClass, this.cls]);
37065 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37066 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37067 * @return {Roo.form.Field} this
37069 applyTo : function(target){
37070 this.allowDomMove = false;
37071 this.el = Roo.get(target);
37072 this.render(this.el.dom.parentNode);
37077 initValue : function(){
37078 if(this.value !== undefined){
37079 this.setValue(this.value);
37080 }else if(this.el.dom.value.length > 0){
37081 this.setValue(this.el.dom.value);
37086 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37088 isDirty : function() {
37089 if(this.disabled) {
37092 return String(this.getValue()) !== String(this.originalValue);
37096 afterRender : function(){
37097 Roo.form.Field.superclass.afterRender.call(this);
37102 fireKey : function(e){
37103 //Roo.log('field ' + e.getKey());
37104 if(e.isNavKeyPress()){
37105 this.fireEvent("specialkey", this, e);
37110 * Resets the current field value to the originally loaded value and clears any validation messages
37112 reset : function(){
37113 this.setValue(this.resetValue);
37114 this.clearInvalid();
37118 initEvents : function(){
37119 // safari killled keypress - so keydown is now used..
37120 this.el.on("keydown" , this.fireKey, this);
37121 this.el.on("focus", this.onFocus, this);
37122 this.el.on("blur", this.onBlur, this);
37123 this.el.relayEvent('keyup', this);
37125 // reference to original value for reset
37126 this.originalValue = this.getValue();
37127 this.resetValue = this.getValue();
37131 onFocus : function(){
37132 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37133 this.el.addClass(this.focusClass);
37135 if(!this.hasFocus){
37136 this.hasFocus = true;
37137 this.startValue = this.getValue();
37138 this.fireEvent("focus", this);
37142 beforeBlur : Roo.emptyFn,
37145 onBlur : function(){
37147 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37148 this.el.removeClass(this.focusClass);
37150 this.hasFocus = false;
37151 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37154 var v = this.getValue();
37155 if(String(v) !== String(this.startValue)){
37156 this.fireEvent('change', this, v, this.startValue);
37158 this.fireEvent("blur", this);
37162 * Returns whether or not the field value is currently valid
37163 * @param {Boolean} preventMark True to disable marking the field invalid
37164 * @return {Boolean} True if the value is valid, else false
37166 isValid : function(preventMark){
37170 var restore = this.preventMark;
37171 this.preventMark = preventMark === true;
37172 var v = this.validateValue(this.processValue(this.getRawValue()));
37173 this.preventMark = restore;
37178 * Validates the field value
37179 * @return {Boolean} True if the value is valid, else false
37181 validate : function(){
37182 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37183 this.clearInvalid();
37189 processValue : function(value){
37194 // Subclasses should provide the validation implementation by overriding this
37195 validateValue : function(value){
37200 * Mark this field as invalid
37201 * @param {String} msg The validation message
37203 markInvalid : function(msg){
37204 if(!this.rendered || this.preventMark){ // not rendered
37208 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37210 obj.el.addClass(this.invalidClass);
37211 msg = msg || this.invalidText;
37212 switch(this.msgTarget){
37214 obj.el.dom.qtip = msg;
37215 obj.el.dom.qclass = 'x-form-invalid-tip';
37216 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37217 Roo.QuickTips.enable();
37221 this.el.dom.title = msg;
37225 var elp = this.el.findParent('.x-form-element', 5, true);
37226 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37227 this.errorEl.setWidth(elp.getWidth(true)-20);
37229 this.errorEl.update(msg);
37230 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37233 if(!this.errorIcon){
37234 var elp = this.el.findParent('.x-form-element', 5, true);
37235 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37237 this.alignErrorIcon();
37238 this.errorIcon.dom.qtip = msg;
37239 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37240 this.errorIcon.show();
37241 this.on('resize', this.alignErrorIcon, this);
37244 var t = Roo.getDom(this.msgTarget);
37246 t.style.display = this.msgDisplay;
37249 this.fireEvent('invalid', this, msg);
37253 alignErrorIcon : function(){
37254 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37258 * Clear any invalid styles/messages for this field
37260 clearInvalid : function(){
37261 if(!this.rendered || this.preventMark){ // not rendered
37264 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37266 obj.el.removeClass(this.invalidClass);
37267 switch(this.msgTarget){
37269 obj.el.dom.qtip = '';
37272 this.el.dom.title = '';
37276 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37280 if(this.errorIcon){
37281 this.errorIcon.dom.qtip = '';
37282 this.errorIcon.hide();
37283 this.un('resize', this.alignErrorIcon, this);
37287 var t = Roo.getDom(this.msgTarget);
37289 t.style.display = 'none';
37292 this.fireEvent('valid', this);
37296 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37297 * @return {Mixed} value The field value
37299 getRawValue : function(){
37300 var v = this.el.getValue();
37306 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37307 * @return {Mixed} value The field value
37309 getValue : function(){
37310 var v = this.el.getValue();
37316 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37317 * @param {Mixed} value The value to set
37319 setRawValue : function(v){
37320 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37324 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37325 * @param {Mixed} value The value to set
37327 setValue : function(v){
37330 this.el.dom.value = (v === null || v === undefined ? '' : v);
37335 adjustSize : function(w, h){
37336 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37337 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37341 adjustWidth : function(tag, w){
37342 tag = tag.toLowerCase();
37343 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37344 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37345 if(tag == 'input'){
37348 if(tag == 'textarea'){
37351 }else if(Roo.isOpera){
37352 if(tag == 'input'){
37355 if(tag == 'textarea'){
37365 // anything other than normal should be considered experimental
37366 Roo.form.Field.msgFx = {
37368 show: function(msgEl, f){
37369 msgEl.setDisplayed('block');
37372 hide : function(msgEl, f){
37373 msgEl.setDisplayed(false).update('');
37378 show: function(msgEl, f){
37379 msgEl.slideIn('t', {stopFx:true});
37382 hide : function(msgEl, f){
37383 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37388 show: function(msgEl, f){
37389 msgEl.fixDisplay();
37390 msgEl.alignTo(f.el, 'tl-tr');
37391 msgEl.slideIn('l', {stopFx:true});
37394 hide : function(msgEl, f){
37395 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37400 * Ext JS Library 1.1.1
37401 * Copyright(c) 2006-2007, Ext JS, LLC.
37403 * Originally Released Under LGPL - original licence link has changed is not relivant.
37406 * <script type="text/javascript">
37411 * @class Roo.form.TextField
37412 * @extends Roo.form.Field
37413 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37414 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37416 * Creates a new TextField
37417 * @param {Object} config Configuration options
37419 Roo.form.TextField = function(config){
37420 Roo.form.TextField.superclass.constructor.call(this, config);
37424 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37425 * according to the default logic, but this event provides a hook for the developer to apply additional
37426 * logic at runtime to resize the field if needed.
37427 * @param {Roo.form.Field} this This text field
37428 * @param {Number} width The new field width
37434 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37436 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37440 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37444 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37448 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37452 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37456 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37458 disableKeyFilter : false,
37460 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37464 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37468 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37470 maxLength : Number.MAX_VALUE,
37472 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37474 minLengthText : "The minimum length for this field is {0}",
37476 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37478 maxLengthText : "The maximum length for this field is {0}",
37480 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37482 selectOnFocus : false,
37484 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37486 blankText : "This field is required",
37488 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37489 * If available, this function will be called only after the basic validators all return true, and will be passed the
37490 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37494 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37495 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37496 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37500 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37504 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37510 initEvents : function()
37512 if (this.emptyText) {
37513 this.el.attr('placeholder', this.emptyText);
37516 Roo.form.TextField.superclass.initEvents.call(this);
37517 if(this.validationEvent == 'keyup'){
37518 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37519 this.el.on('keyup', this.filterValidation, this);
37521 else if(this.validationEvent !== false){
37522 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37525 if(this.selectOnFocus){
37526 this.on("focus", this.preFocus, this);
37529 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37530 this.el.on("keypress", this.filterKeys, this);
37533 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37534 this.el.on("click", this.autoSize, this);
37536 if(this.el.is('input[type=password]') && Roo.isSafari){
37537 this.el.on('keydown', this.SafariOnKeyDown, this);
37541 processValue : function(value){
37542 if(this.stripCharsRe){
37543 var newValue = value.replace(this.stripCharsRe, '');
37544 if(newValue !== value){
37545 this.setRawValue(newValue);
37552 filterValidation : function(e){
37553 if(!e.isNavKeyPress()){
37554 this.validationTask.delay(this.validationDelay);
37559 onKeyUp : function(e){
37560 if(!e.isNavKeyPress()){
37566 * Resets the current field value to the originally-loaded value and clears any validation messages.
37569 reset : function(){
37570 Roo.form.TextField.superclass.reset.call(this);
37576 preFocus : function(){
37578 if(this.selectOnFocus){
37579 this.el.dom.select();
37585 filterKeys : function(e){
37586 var k = e.getKey();
37587 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37590 var c = e.getCharCode(), cc = String.fromCharCode(c);
37591 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37594 if(!this.maskRe.test(cc)){
37599 setValue : function(v){
37601 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37607 * Validates a value according to the field's validation rules and marks the field as invalid
37608 * if the validation fails
37609 * @param {Mixed} value The value to validate
37610 * @return {Boolean} True if the value is valid, else false
37612 validateValue : function(value){
37613 if(value.length < 1) { // if it's blank
37614 if(this.allowBlank){
37615 this.clearInvalid();
37618 this.markInvalid(this.blankText);
37622 if(value.length < this.minLength){
37623 this.markInvalid(String.format(this.minLengthText, this.minLength));
37626 if(value.length > this.maxLength){
37627 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37631 var vt = Roo.form.VTypes;
37632 if(!vt[this.vtype](value, this)){
37633 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37637 if(typeof this.validator == "function"){
37638 var msg = this.validator(value);
37640 this.markInvalid(msg);
37644 if(this.regex && !this.regex.test(value)){
37645 this.markInvalid(this.regexText);
37652 * Selects text in this field
37653 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37654 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37656 selectText : function(start, end){
37657 var v = this.getRawValue();
37659 start = start === undefined ? 0 : start;
37660 end = end === undefined ? v.length : end;
37661 var d = this.el.dom;
37662 if(d.setSelectionRange){
37663 d.setSelectionRange(start, end);
37664 }else if(d.createTextRange){
37665 var range = d.createTextRange();
37666 range.moveStart("character", start);
37667 range.moveEnd("character", v.length-end);
37674 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37675 * This only takes effect if grow = true, and fires the autosize event.
37677 autoSize : function(){
37678 if(!this.grow || !this.rendered){
37682 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37685 var v = el.dom.value;
37686 var d = document.createElement('div');
37687 d.appendChild(document.createTextNode(v));
37691 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37692 this.el.setWidth(w);
37693 this.fireEvent("autosize", this, w);
37697 SafariOnKeyDown : function(event)
37699 // this is a workaround for a password hang bug on chrome/ webkit.
37701 var isSelectAll = false;
37703 if(this.el.dom.selectionEnd > 0){
37704 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37706 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37707 event.preventDefault();
37712 if(isSelectAll){ // backspace and delete key
37714 event.preventDefault();
37715 // this is very hacky as keydown always get's upper case.
37717 var cc = String.fromCharCode(event.getCharCode());
37718 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37726 * Ext JS Library 1.1.1
37727 * Copyright(c) 2006-2007, Ext JS, LLC.
37729 * Originally Released Under LGPL - original licence link has changed is not relivant.
37732 * <script type="text/javascript">
37736 * @class Roo.form.Hidden
37737 * @extends Roo.form.TextField
37738 * Simple Hidden element used on forms
37740 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37743 * Creates a new Hidden form element.
37744 * @param {Object} config Configuration options
37749 // easy hidden field...
37750 Roo.form.Hidden = function(config){
37751 Roo.form.Hidden.superclass.constructor.call(this, config);
37754 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37756 inputType: 'hidden',
37759 labelSeparator: '',
37761 itemCls : 'x-form-item-display-none'
37769 * Ext JS Library 1.1.1
37770 * Copyright(c) 2006-2007, Ext JS, LLC.
37772 * Originally Released Under LGPL - original licence link has changed is not relivant.
37775 * <script type="text/javascript">
37779 * @class Roo.form.TriggerField
37780 * @extends Roo.form.TextField
37781 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37782 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37783 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37784 * for which you can provide a custom implementation. For example:
37786 var trigger = new Roo.form.TriggerField();
37787 trigger.onTriggerClick = myTriggerFn;
37788 trigger.applyTo('my-field');
37791 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37792 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37793 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37794 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37796 * Create a new TriggerField.
37797 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37798 * to the base TextField)
37800 Roo.form.TriggerField = function(config){
37801 this.mimicing = false;
37802 Roo.form.TriggerField.superclass.constructor.call(this, config);
37805 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37807 * @cfg {String} triggerClass A CSS class to apply to the trigger
37810 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37811 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37813 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
37815 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
37819 /** @cfg {Boolean} grow @hide */
37820 /** @cfg {Number} growMin @hide */
37821 /** @cfg {Number} growMax @hide */
37827 autoSize: Roo.emptyFn,
37831 deferHeight : true,
37834 actionMode : 'wrap',
37836 onResize : function(w, h){
37837 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
37838 if(typeof w == 'number'){
37839 var x = w - this.trigger.getWidth();
37840 this.el.setWidth(this.adjustWidth('input', x));
37841 this.trigger.setStyle('left', x+'px');
37846 adjustSize : Roo.BoxComponent.prototype.adjustSize,
37849 getResizeEl : function(){
37854 getPositionEl : function(){
37859 alignErrorIcon : function(){
37860 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
37864 onRender : function(ct, position){
37865 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
37866 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
37867 this.trigger = this.wrap.createChild(this.triggerConfig ||
37868 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
37869 if(this.hideTrigger){
37870 this.trigger.setDisplayed(false);
37872 this.initTrigger();
37874 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
37879 initTrigger : function(){
37880 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
37881 this.trigger.addClassOnOver('x-form-trigger-over');
37882 this.trigger.addClassOnClick('x-form-trigger-click');
37886 onDestroy : function(){
37888 this.trigger.removeAllListeners();
37889 this.trigger.remove();
37892 this.wrap.remove();
37894 Roo.form.TriggerField.superclass.onDestroy.call(this);
37898 onFocus : function(){
37899 Roo.form.TriggerField.superclass.onFocus.call(this);
37900 if(!this.mimicing){
37901 this.wrap.addClass('x-trigger-wrap-focus');
37902 this.mimicing = true;
37903 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
37904 if(this.monitorTab){
37905 this.el.on("keydown", this.checkTab, this);
37911 checkTab : function(e){
37912 if(e.getKey() == e.TAB){
37913 this.triggerBlur();
37918 onBlur : function(){
37923 mimicBlur : function(e, t){
37924 if(!this.wrap.contains(t) && this.validateBlur()){
37925 this.triggerBlur();
37930 triggerBlur : function(){
37931 this.mimicing = false;
37932 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
37933 if(this.monitorTab){
37934 this.el.un("keydown", this.checkTab, this);
37936 this.wrap.removeClass('x-trigger-wrap-focus');
37937 Roo.form.TriggerField.superclass.onBlur.call(this);
37941 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
37942 validateBlur : function(e, t){
37947 onDisable : function(){
37948 Roo.form.TriggerField.superclass.onDisable.call(this);
37950 this.wrap.addClass('x-item-disabled');
37955 onEnable : function(){
37956 Roo.form.TriggerField.superclass.onEnable.call(this);
37958 this.wrap.removeClass('x-item-disabled');
37963 onShow : function(){
37964 var ae = this.getActionEl();
37967 ae.dom.style.display = '';
37968 ae.dom.style.visibility = 'visible';
37974 onHide : function(){
37975 var ae = this.getActionEl();
37976 ae.dom.style.display = 'none';
37980 * The function that should handle the trigger's click event. This method does nothing by default until overridden
37981 * by an implementing function.
37983 * @param {EventObject} e
37985 onTriggerClick : Roo.emptyFn
37988 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
37989 // to be extended by an implementing class. For an example of implementing this class, see the custom
37990 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
37991 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
37992 initComponent : function(){
37993 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
37995 this.triggerConfig = {
37996 tag:'span', cls:'x-form-twin-triggers', cn:[
37997 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
37998 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38002 getTrigger : function(index){
38003 return this.triggers[index];
38006 initTrigger : function(){
38007 var ts = this.trigger.select('.x-form-trigger', true);
38008 this.wrap.setStyle('overflow', 'hidden');
38009 var triggerField = this;
38010 ts.each(function(t, all, index){
38011 t.hide = function(){
38012 var w = triggerField.wrap.getWidth();
38013 this.dom.style.display = 'none';
38014 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38016 t.show = function(){
38017 var w = triggerField.wrap.getWidth();
38018 this.dom.style.display = '';
38019 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38021 var triggerIndex = 'Trigger'+(index+1);
38023 if(this['hide'+triggerIndex]){
38024 t.dom.style.display = 'none';
38026 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38027 t.addClassOnOver('x-form-trigger-over');
38028 t.addClassOnClick('x-form-trigger-click');
38030 this.triggers = ts.elements;
38033 onTrigger1Click : Roo.emptyFn,
38034 onTrigger2Click : Roo.emptyFn
38037 * Ext JS Library 1.1.1
38038 * Copyright(c) 2006-2007, Ext JS, LLC.
38040 * Originally Released Under LGPL - original licence link has changed is not relivant.
38043 * <script type="text/javascript">
38047 * @class Roo.form.TextArea
38048 * @extends Roo.form.TextField
38049 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38050 * support for auto-sizing.
38052 * Creates a new TextArea
38053 * @param {Object} config Configuration options
38055 Roo.form.TextArea = function(config){
38056 Roo.form.TextArea.superclass.constructor.call(this, config);
38057 // these are provided exchanges for backwards compat
38058 // minHeight/maxHeight were replaced by growMin/growMax to be
38059 // compatible with TextField growing config values
38060 if(this.minHeight !== undefined){
38061 this.growMin = this.minHeight;
38063 if(this.maxHeight !== undefined){
38064 this.growMax = this.maxHeight;
38068 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38070 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38074 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38078 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38079 * in the field (equivalent to setting overflow: hidden, defaults to false)
38081 preventScrollbars: false,
38083 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38084 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38088 onRender : function(ct, position){
38090 this.defaultAutoCreate = {
38092 style:"width:300px;height:60px;",
38093 autocomplete: "off"
38096 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38098 this.textSizeEl = Roo.DomHelper.append(document.body, {
38099 tag: "pre", cls: "x-form-grow-sizer"
38101 if(this.preventScrollbars){
38102 this.el.setStyle("overflow", "hidden");
38104 this.el.setHeight(this.growMin);
38108 onDestroy : function(){
38109 if(this.textSizeEl){
38110 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38112 Roo.form.TextArea.superclass.onDestroy.call(this);
38116 onKeyUp : function(e){
38117 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38123 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38124 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38126 autoSize : function(){
38127 if(!this.grow || !this.textSizeEl){
38131 var v = el.dom.value;
38132 var ts = this.textSizeEl;
38135 ts.appendChild(document.createTextNode(v));
38138 Roo.fly(ts).setWidth(this.el.getWidth());
38140 v = "  ";
38143 v = v.replace(/\n/g, '<p> </p>');
38145 v += " \n ";
38148 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38149 if(h != this.lastHeight){
38150 this.lastHeight = h;
38151 this.el.setHeight(h);
38152 this.fireEvent("autosize", this, h);
38157 * Ext JS Library 1.1.1
38158 * Copyright(c) 2006-2007, Ext JS, LLC.
38160 * Originally Released Under LGPL - original licence link has changed is not relivant.
38163 * <script type="text/javascript">
38168 * @class Roo.form.NumberField
38169 * @extends Roo.form.TextField
38170 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38172 * Creates a new NumberField
38173 * @param {Object} config Configuration options
38175 Roo.form.NumberField = function(config){
38176 Roo.form.NumberField.superclass.constructor.call(this, config);
38179 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38181 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38183 fieldClass: "x-form-field x-form-num-field",
38185 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38187 allowDecimals : true,
38189 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38191 decimalSeparator : ".",
38193 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38195 decimalPrecision : 2,
38197 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38199 allowNegative : true,
38201 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38203 minValue : Number.NEGATIVE_INFINITY,
38205 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38207 maxValue : Number.MAX_VALUE,
38209 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38211 minText : "The minimum value for this field is {0}",
38213 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38215 maxText : "The maximum value for this field is {0}",
38217 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38218 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38220 nanText : "{0} is not a valid number",
38223 initEvents : function(){
38224 Roo.form.NumberField.superclass.initEvents.call(this);
38225 var allowed = "0123456789";
38226 if(this.allowDecimals){
38227 allowed += this.decimalSeparator;
38229 if(this.allowNegative){
38232 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38233 var keyPress = function(e){
38234 var k = e.getKey();
38235 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38238 var c = e.getCharCode();
38239 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38243 this.el.on("keypress", keyPress, this);
38247 validateValue : function(value){
38248 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38251 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38254 var num = this.parseValue(value);
38256 this.markInvalid(String.format(this.nanText, value));
38259 if(num < this.minValue){
38260 this.markInvalid(String.format(this.minText, this.minValue));
38263 if(num > this.maxValue){
38264 this.markInvalid(String.format(this.maxText, this.maxValue));
38270 getValue : function(){
38271 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38275 parseValue : function(value){
38276 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38277 return isNaN(value) ? '' : value;
38281 fixPrecision : function(value){
38282 var nan = isNaN(value);
38283 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38284 return nan ? '' : value;
38286 return parseFloat(value).toFixed(this.decimalPrecision);
38289 setValue : function(v){
38290 v = this.fixPrecision(v);
38291 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38295 decimalPrecisionFcn : function(v){
38296 return Math.floor(v);
38299 beforeBlur : function(){
38300 var v = this.parseValue(this.getRawValue());
38307 * Ext JS Library 1.1.1
38308 * Copyright(c) 2006-2007, Ext JS, LLC.
38310 * Originally Released Under LGPL - original licence link has changed is not relivant.
38313 * <script type="text/javascript">
38317 * @class Roo.form.DateField
38318 * @extends Roo.form.TriggerField
38319 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38321 * Create a new DateField
38322 * @param {Object} config
38324 Roo.form.DateField = function(config){
38325 Roo.form.DateField.superclass.constructor.call(this, config);
38331 * Fires when a date is selected
38332 * @param {Roo.form.DateField} combo This combo box
38333 * @param {Date} date The date selected
38340 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38341 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38342 this.ddMatch = null;
38343 if(this.disabledDates){
38344 var dd = this.disabledDates;
38346 for(var i = 0; i < dd.length; i++){
38348 if(i != dd.length-1) re += "|";
38350 this.ddMatch = new RegExp(re + ")");
38354 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38356 * @cfg {String} format
38357 * The default date format string which can be overriden for localization support. The format must be
38358 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38362 * @cfg {String} altFormats
38363 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38364 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38366 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38368 * @cfg {Array} disabledDays
38369 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38371 disabledDays : null,
38373 * @cfg {String} disabledDaysText
38374 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38376 disabledDaysText : "Disabled",
38378 * @cfg {Array} disabledDates
38379 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38380 * expression so they are very powerful. Some examples:
38382 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38383 * <li>["03/08", "09/16"] would disable those days for every year</li>
38384 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38385 * <li>["03/../2006"] would disable every day in March 2006</li>
38386 * <li>["^03"] would disable every day in every March</li>
38388 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38389 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38391 disabledDates : null,
38393 * @cfg {String} disabledDatesText
38394 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38396 disabledDatesText : "Disabled",
38398 * @cfg {Date/String} minValue
38399 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38400 * valid format (defaults to null).
38404 * @cfg {Date/String} maxValue
38405 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38406 * valid format (defaults to null).
38410 * @cfg {String} minText
38411 * The error text to display when the date in the cell is before minValue (defaults to
38412 * 'The date in this field must be after {minValue}').
38414 minText : "The date in this field must be equal to or after {0}",
38416 * @cfg {String} maxText
38417 * The error text to display when the date in the cell is after maxValue (defaults to
38418 * 'The date in this field must be before {maxValue}').
38420 maxText : "The date in this field must be equal to or before {0}",
38422 * @cfg {String} invalidText
38423 * The error text to display when the date in the field is invalid (defaults to
38424 * '{value} is not a valid date - it must be in the format {format}').
38426 invalidText : "{0} is not a valid date - it must be in the format {1}",
38428 * @cfg {String} triggerClass
38429 * An additional CSS class used to style the trigger button. The trigger will always get the
38430 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38431 * which displays a calendar icon).
38433 triggerClass : 'x-form-date-trigger',
38437 * @cfg {Boolean} useIso
38438 * if enabled, then the date field will use a hidden field to store the
38439 * real value as iso formated date. default (false)
38443 * @cfg {String/Object} autoCreate
38444 * A DomHelper element spec, or true for a default element spec (defaults to
38445 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38448 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38451 hiddenField: false,
38453 onRender : function(ct, position)
38455 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38457 //this.el.dom.removeAttribute('name');
38458 Roo.log("Changing name?");
38459 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38460 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38462 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38463 // prevent input submission
38464 this.hiddenName = this.name;
38471 validateValue : function(value)
38473 value = this.formatDate(value);
38474 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38475 Roo.log('super failed');
38478 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38481 var svalue = value;
38482 value = this.parseDate(value);
38484 Roo.log('parse date failed' + svalue);
38485 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38488 var time = value.getTime();
38489 if(this.minValue && time < this.minValue.getTime()){
38490 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38493 if(this.maxValue && time > this.maxValue.getTime()){
38494 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38497 if(this.disabledDays){
38498 var day = value.getDay();
38499 for(var i = 0; i < this.disabledDays.length; i++) {
38500 if(day === this.disabledDays[i]){
38501 this.markInvalid(this.disabledDaysText);
38506 var fvalue = this.formatDate(value);
38507 if(this.ddMatch && this.ddMatch.test(fvalue)){
38508 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38515 // Provides logic to override the default TriggerField.validateBlur which just returns true
38516 validateBlur : function(){
38517 return !this.menu || !this.menu.isVisible();
38520 getName: function()
38522 // returns hidden if it's set..
38523 if (!this.rendered) {return ''};
38524 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38529 * Returns the current date value of the date field.
38530 * @return {Date} The date value
38532 getValue : function(){
38534 return this.hiddenField ?
38535 this.hiddenField.value :
38536 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38540 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38541 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38542 * (the default format used is "m/d/y").
38545 //All of these calls set the same date value (May 4, 2006)
38547 //Pass a date object:
38548 var dt = new Date('5/4/06');
38549 dateField.setValue(dt);
38551 //Pass a date string (default format):
38552 dateField.setValue('5/4/06');
38554 //Pass a date string (custom format):
38555 dateField.format = 'Y-m-d';
38556 dateField.setValue('2006-5-4');
38558 * @param {String/Date} date The date or valid date string
38560 setValue : function(date){
38561 if (this.hiddenField) {
38562 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38564 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38565 // make sure the value field is always stored as a date..
38566 this.value = this.parseDate(date);
38572 parseDate : function(value){
38573 if(!value || value instanceof Date){
38576 var v = Date.parseDate(value, this.format);
38577 if (!v && this.useIso) {
38578 v = Date.parseDate(value, 'Y-m-d');
38580 if(!v && this.altFormats){
38581 if(!this.altFormatsArray){
38582 this.altFormatsArray = this.altFormats.split("|");
38584 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38585 v = Date.parseDate(value, this.altFormatsArray[i]);
38592 formatDate : function(date, fmt){
38593 return (!date || !(date instanceof Date)) ?
38594 date : date.dateFormat(fmt || this.format);
38599 select: function(m, d){
38602 this.fireEvent('select', this, d);
38604 show : function(){ // retain focus styling
38608 this.focus.defer(10, this);
38609 var ml = this.menuListeners;
38610 this.menu.un("select", ml.select, this);
38611 this.menu.un("show", ml.show, this);
38612 this.menu.un("hide", ml.hide, this);
38617 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38618 onTriggerClick : function(){
38622 if(this.menu == null){
38623 this.menu = new Roo.menu.DateMenu();
38625 Roo.apply(this.menu.picker, {
38626 showClear: this.allowBlank,
38627 minDate : this.minValue,
38628 maxDate : this.maxValue,
38629 disabledDatesRE : this.ddMatch,
38630 disabledDatesText : this.disabledDatesText,
38631 disabledDays : this.disabledDays,
38632 disabledDaysText : this.disabledDaysText,
38633 format : this.useIso ? 'Y-m-d' : this.format,
38634 minText : String.format(this.minText, this.formatDate(this.minValue)),
38635 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38637 this.menu.on(Roo.apply({}, this.menuListeners, {
38640 this.menu.picker.setValue(this.getValue() || new Date());
38641 this.menu.show(this.el, "tl-bl?");
38644 beforeBlur : function(){
38645 var v = this.parseDate(this.getRawValue());
38655 isDirty : function() {
38656 if(this.disabled) {
38660 if(typeof(this.startValue) === 'undefined'){
38664 return String(this.getValue()) !== String(this.startValue);
38669 * Ext JS Library 1.1.1
38670 * Copyright(c) 2006-2007, Ext JS, LLC.
38672 * Originally Released Under LGPL - original licence link has changed is not relivant.
38675 * <script type="text/javascript">
38679 * @class Roo.form.MonthField
38680 * @extends Roo.form.TriggerField
38681 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38683 * Create a new MonthField
38684 * @param {Object} config
38686 Roo.form.MonthField = function(config){
38688 Roo.form.MonthField.superclass.constructor.call(this, config);
38694 * Fires when a date is selected
38695 * @param {Roo.form.MonthFieeld} combo This combo box
38696 * @param {Date} date The date selected
38703 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38704 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38705 this.ddMatch = null;
38706 if(this.disabledDates){
38707 var dd = this.disabledDates;
38709 for(var i = 0; i < dd.length; i++){
38711 if(i != dd.length-1) re += "|";
38713 this.ddMatch = new RegExp(re + ")");
38717 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38719 * @cfg {String} format
38720 * The default date format string which can be overriden for localization support. The format must be
38721 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38725 * @cfg {String} altFormats
38726 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38727 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38729 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38731 * @cfg {Array} disabledDays
38732 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38734 disabledDays : [0,1,2,3,4,5,6],
38736 * @cfg {String} disabledDaysText
38737 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38739 disabledDaysText : "Disabled",
38741 * @cfg {Array} disabledDates
38742 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38743 * expression so they are very powerful. Some examples:
38745 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38746 * <li>["03/08", "09/16"] would disable those days for every year</li>
38747 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38748 * <li>["03/../2006"] would disable every day in March 2006</li>
38749 * <li>["^03"] would disable every day in every March</li>
38751 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38752 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38754 disabledDates : null,
38756 * @cfg {String} disabledDatesText
38757 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38759 disabledDatesText : "Disabled",
38761 * @cfg {Date/String} minValue
38762 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38763 * valid format (defaults to null).
38767 * @cfg {Date/String} maxValue
38768 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38769 * valid format (defaults to null).
38773 * @cfg {String} minText
38774 * The error text to display when the date in the cell is before minValue (defaults to
38775 * 'The date in this field must be after {minValue}').
38777 minText : "The date in this field must be equal to or after {0}",
38779 * @cfg {String} maxTextf
38780 * The error text to display when the date in the cell is after maxValue (defaults to
38781 * 'The date in this field must be before {maxValue}').
38783 maxText : "The date in this field must be equal to or before {0}",
38785 * @cfg {String} invalidText
38786 * The error text to display when the date in the field is invalid (defaults to
38787 * '{value} is not a valid date - it must be in the format {format}').
38789 invalidText : "{0} is not a valid date - it must be in the format {1}",
38791 * @cfg {String} triggerClass
38792 * An additional CSS class used to style the trigger button. The trigger will always get the
38793 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38794 * which displays a calendar icon).
38796 triggerClass : 'x-form-date-trigger',
38800 * @cfg {Boolean} useIso
38801 * if enabled, then the date field will use a hidden field to store the
38802 * real value as iso formated date. default (true)
38806 * @cfg {String/Object} autoCreate
38807 * A DomHelper element spec, or true for a default element spec (defaults to
38808 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38811 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38814 hiddenField: false,
38816 hideMonthPicker : false,
38818 onRender : function(ct, position)
38820 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
38822 this.el.dom.removeAttribute('name');
38823 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38825 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38826 // prevent input submission
38827 this.hiddenName = this.name;
38834 validateValue : function(value)
38836 value = this.formatDate(value);
38837 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
38840 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38843 var svalue = value;
38844 value = this.parseDate(value);
38846 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38849 var time = value.getTime();
38850 if(this.minValue && time < this.minValue.getTime()){
38851 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38854 if(this.maxValue && time > this.maxValue.getTime()){
38855 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38858 /*if(this.disabledDays){
38859 var day = value.getDay();
38860 for(var i = 0; i < this.disabledDays.length; i++) {
38861 if(day === this.disabledDays[i]){
38862 this.markInvalid(this.disabledDaysText);
38868 var fvalue = this.formatDate(value);
38869 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
38870 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38878 // Provides logic to override the default TriggerField.validateBlur which just returns true
38879 validateBlur : function(){
38880 return !this.menu || !this.menu.isVisible();
38884 * Returns the current date value of the date field.
38885 * @return {Date} The date value
38887 getValue : function(){
38891 return this.hiddenField ?
38892 this.hiddenField.value :
38893 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
38897 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38898 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
38899 * (the default format used is "m/d/y").
38902 //All of these calls set the same date value (May 4, 2006)
38904 //Pass a date object:
38905 var dt = new Date('5/4/06');
38906 monthField.setValue(dt);
38908 //Pass a date string (default format):
38909 monthField.setValue('5/4/06');
38911 //Pass a date string (custom format):
38912 monthField.format = 'Y-m-d';
38913 monthField.setValue('2006-5-4');
38915 * @param {String/Date} date The date or valid date string
38917 setValue : function(date){
38918 Roo.log('month setValue' + date);
38919 // can only be first of month..
38921 var val = this.parseDate(date);
38923 if (this.hiddenField) {
38924 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38926 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38927 this.value = this.parseDate(date);
38931 parseDate : function(value){
38932 if(!value || value instanceof Date){
38933 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
38936 var v = Date.parseDate(value, this.format);
38937 if (!v && this.useIso) {
38938 v = Date.parseDate(value, 'Y-m-d');
38942 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
38946 if(!v && this.altFormats){
38947 if(!this.altFormatsArray){
38948 this.altFormatsArray = this.altFormats.split("|");
38950 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38951 v = Date.parseDate(value, this.altFormatsArray[i]);
38958 formatDate : function(date, fmt){
38959 return (!date || !(date instanceof Date)) ?
38960 date : date.dateFormat(fmt || this.format);
38965 select: function(m, d){
38967 this.fireEvent('select', this, d);
38969 show : function(){ // retain focus styling
38973 this.focus.defer(10, this);
38974 var ml = this.menuListeners;
38975 this.menu.un("select", ml.select, this);
38976 this.menu.un("show", ml.show, this);
38977 this.menu.un("hide", ml.hide, this);
38981 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38982 onTriggerClick : function(){
38986 if(this.menu == null){
38987 this.menu = new Roo.menu.DateMenu();
38991 Roo.apply(this.menu.picker, {
38993 showClear: this.allowBlank,
38994 minDate : this.minValue,
38995 maxDate : this.maxValue,
38996 disabledDatesRE : this.ddMatch,
38997 disabledDatesText : this.disabledDatesText,
38999 format : this.useIso ? 'Y-m-d' : this.format,
39000 minText : String.format(this.minText, this.formatDate(this.minValue)),
39001 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39004 this.menu.on(Roo.apply({}, this.menuListeners, {
39012 // hide month picker get's called when we called by 'before hide';
39014 var ignorehide = true;
39015 p.hideMonthPicker = function(disableAnim){
39019 if(this.monthPicker){
39020 Roo.log("hideMonthPicker called");
39021 if(disableAnim === true){
39022 this.monthPicker.hide();
39024 this.monthPicker.slideOut('t', {duration:.2});
39025 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39026 p.fireEvent("select", this, this.value);
39032 Roo.log('picker set value');
39033 Roo.log(this.getValue());
39034 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39035 m.show(this.el, 'tl-bl?');
39036 ignorehide = false;
39037 // this will trigger hideMonthPicker..
39040 // hidden the day picker
39041 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39047 p.showMonthPicker.defer(100, p);
39053 beforeBlur : function(){
39054 var v = this.parseDate(this.getRawValue());
39060 /** @cfg {Boolean} grow @hide */
39061 /** @cfg {Number} growMin @hide */
39062 /** @cfg {Number} growMax @hide */
39069 * Ext JS Library 1.1.1
39070 * Copyright(c) 2006-2007, Ext JS, LLC.
39072 * Originally Released Under LGPL - original licence link has changed is not relivant.
39075 * <script type="text/javascript">
39080 * @class Roo.form.ComboBox
39081 * @extends Roo.form.TriggerField
39082 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39084 * Create a new ComboBox.
39085 * @param {Object} config Configuration options
39087 Roo.form.ComboBox = function(config){
39088 Roo.form.ComboBox.superclass.constructor.call(this, config);
39092 * Fires when the dropdown list is expanded
39093 * @param {Roo.form.ComboBox} combo This combo box
39098 * Fires when the dropdown list is collapsed
39099 * @param {Roo.form.ComboBox} combo This combo box
39103 * @event beforeselect
39104 * Fires before a list item is selected. Return false to cancel the selection.
39105 * @param {Roo.form.ComboBox} combo This combo box
39106 * @param {Roo.data.Record} record The data record returned from the underlying store
39107 * @param {Number} index The index of the selected item in the dropdown list
39109 'beforeselect' : true,
39112 * Fires when a list item is selected
39113 * @param {Roo.form.ComboBox} combo This combo box
39114 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39115 * @param {Number} index The index of the selected item in the dropdown list
39119 * @event beforequery
39120 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39121 * The event object passed has these properties:
39122 * @param {Roo.form.ComboBox} combo This combo box
39123 * @param {String} query The query
39124 * @param {Boolean} forceAll true to force "all" query
39125 * @param {Boolean} cancel true to cancel the query
39126 * @param {Object} e The query event object
39128 'beforequery': true,
39131 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39132 * @param {Roo.form.ComboBox} combo This combo box
39137 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39138 * @param {Roo.form.ComboBox} combo This combo box
39139 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39145 if(this.transform){
39146 this.allowDomMove = false;
39147 var s = Roo.getDom(this.transform);
39148 if(!this.hiddenName){
39149 this.hiddenName = s.name;
39152 this.mode = 'local';
39153 var d = [], opts = s.options;
39154 for(var i = 0, len = opts.length;i < len; i++){
39156 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39158 this.value = value;
39160 d.push([value, o.text]);
39162 this.store = new Roo.data.SimpleStore({
39164 fields: ['value', 'text'],
39167 this.valueField = 'value';
39168 this.displayField = 'text';
39170 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39171 if(!this.lazyRender){
39172 this.target = true;
39173 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39174 s.parentNode.removeChild(s); // remove it
39175 this.render(this.el.parentNode);
39177 s.parentNode.removeChild(s); // remove it
39182 this.store = Roo.factory(this.store, Roo.data);
39185 this.selectedIndex = -1;
39186 if(this.mode == 'local'){
39187 if(config.queryDelay === undefined){
39188 this.queryDelay = 10;
39190 if(config.minChars === undefined){
39196 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39198 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39201 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39202 * rendering into an Roo.Editor, defaults to false)
39205 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39206 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39209 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39212 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39213 * the dropdown list (defaults to undefined, with no header element)
39217 * @cfg {String/Roo.Template} tpl The template to use to render the output
39221 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39223 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39225 listWidth: undefined,
39227 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39228 * mode = 'remote' or 'text' if mode = 'local')
39230 displayField: undefined,
39232 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39233 * mode = 'remote' or 'value' if mode = 'local').
39234 * Note: use of a valueField requires the user make a selection
39235 * in order for a value to be mapped.
39237 valueField: undefined,
39241 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39242 * field's data value (defaults to the underlying DOM element's name)
39244 hiddenName: undefined,
39246 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39250 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39252 selectedClass: 'x-combo-selected',
39254 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39255 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39256 * which displays a downward arrow icon).
39258 triggerClass : 'x-form-arrow-trigger',
39260 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39264 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39265 * anchor positions (defaults to 'tl-bl')
39267 listAlign: 'tl-bl?',
39269 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39273 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39274 * query specified by the allQuery config option (defaults to 'query')
39276 triggerAction: 'query',
39278 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39279 * (defaults to 4, does not apply if editable = false)
39283 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39284 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39288 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39289 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39293 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39294 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39298 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39299 * when editable = true (defaults to false)
39301 selectOnFocus:false,
39303 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39305 queryParam: 'query',
39307 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39308 * when mode = 'remote' (defaults to 'Loading...')
39310 loadingText: 'Loading...',
39312 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39316 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39320 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39321 * traditional select (defaults to true)
39325 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39329 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39333 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39334 * listWidth has a higher value)
39338 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39339 * allow the user to set arbitrary text into the field (defaults to false)
39341 forceSelection:false,
39343 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39344 * if typeAhead = true (defaults to 250)
39346 typeAheadDelay : 250,
39348 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39349 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39351 valueNotFoundText : undefined,
39353 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39355 blockFocus : false,
39358 * @cfg {Boolean} disableClear Disable showing of clear button.
39360 disableClear : false,
39362 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39364 alwaysQuery : false,
39370 // element that contains real text value.. (when hidden is used..)
39373 onRender : function(ct, position){
39374 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39375 if(this.hiddenName){
39376 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39378 this.hiddenField.value =
39379 this.hiddenValue !== undefined ? this.hiddenValue :
39380 this.value !== undefined ? this.value : '';
39382 // prevent input submission
39383 this.el.dom.removeAttribute('name');
39388 this.el.dom.setAttribute('autocomplete', 'off');
39391 var cls = 'x-combo-list';
39393 this.list = new Roo.Layer({
39394 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39397 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39398 this.list.setWidth(lw);
39399 this.list.swallowEvent('mousewheel');
39400 this.assetHeight = 0;
39403 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39404 this.assetHeight += this.header.getHeight();
39407 this.innerList = this.list.createChild({cls:cls+'-inner'});
39408 this.innerList.on('mouseover', this.onViewOver, this);
39409 this.innerList.on('mousemove', this.onViewMove, this);
39410 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39412 if(this.allowBlank && !this.pageSize && !this.disableClear){
39413 this.footer = this.list.createChild({cls:cls+'-ft'});
39414 this.pageTb = new Roo.Toolbar(this.footer);
39418 this.footer = this.list.createChild({cls:cls+'-ft'});
39419 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39420 {pageSize: this.pageSize});
39424 if (this.pageTb && this.allowBlank && !this.disableClear) {
39426 this.pageTb.add(new Roo.Toolbar.Fill(), {
39427 cls: 'x-btn-icon x-btn-clear',
39429 handler: function()
39432 _this.clearValue();
39433 _this.onSelect(false, -1);
39438 this.assetHeight += this.footer.getHeight();
39443 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39446 this.view = new Roo.View(this.innerList, this.tpl, {
39447 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39450 this.view.on('click', this.onViewClick, this);
39452 this.store.on('beforeload', this.onBeforeLoad, this);
39453 this.store.on('load', this.onLoad, this);
39454 this.store.on('loadexception', this.onLoadException, this);
39456 if(this.resizable){
39457 this.resizer = new Roo.Resizable(this.list, {
39458 pinned:true, handles:'se'
39460 this.resizer.on('resize', function(r, w, h){
39461 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39462 this.listWidth = w;
39463 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39464 this.restrictHeight();
39466 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39468 if(!this.editable){
39469 this.editable = true;
39470 this.setEditable(false);
39474 if (typeof(this.events.add.listeners) != 'undefined') {
39476 this.addicon = this.wrap.createChild(
39477 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39479 this.addicon.on('click', function(e) {
39480 this.fireEvent('add', this);
39483 if (typeof(this.events.edit.listeners) != 'undefined') {
39485 this.editicon = this.wrap.createChild(
39486 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39487 if (this.addicon) {
39488 this.editicon.setStyle('margin-left', '40px');
39490 this.editicon.on('click', function(e) {
39492 // we fire even if inothing is selected..
39493 this.fireEvent('edit', this, this.lastData );
39503 initEvents : function(){
39504 Roo.form.ComboBox.superclass.initEvents.call(this);
39506 this.keyNav = new Roo.KeyNav(this.el, {
39507 "up" : function(e){
39508 this.inKeyMode = true;
39512 "down" : function(e){
39513 if(!this.isExpanded()){
39514 this.onTriggerClick();
39516 this.inKeyMode = true;
39521 "enter" : function(e){
39522 this.onViewClick();
39526 "esc" : function(e){
39530 "tab" : function(e){
39531 this.onViewClick(false);
39532 this.fireEvent("specialkey", this, e);
39538 doRelay : function(foo, bar, hname){
39539 if(hname == 'down' || this.scope.isExpanded()){
39540 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39547 this.queryDelay = Math.max(this.queryDelay || 10,
39548 this.mode == 'local' ? 10 : 250);
39549 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39550 if(this.typeAhead){
39551 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39553 if(this.editable !== false){
39554 this.el.on("keyup", this.onKeyUp, this);
39556 if(this.forceSelection){
39557 this.on('blur', this.doForce, this);
39561 onDestroy : function(){
39563 this.view.setStore(null);
39564 this.view.el.removeAllListeners();
39565 this.view.el.remove();
39566 this.view.purgeListeners();
39569 this.list.destroy();
39572 this.store.un('beforeload', this.onBeforeLoad, this);
39573 this.store.un('load', this.onLoad, this);
39574 this.store.un('loadexception', this.onLoadException, this);
39576 Roo.form.ComboBox.superclass.onDestroy.call(this);
39580 fireKey : function(e){
39581 if(e.isNavKeyPress() && !this.list.isVisible()){
39582 this.fireEvent("specialkey", this, e);
39587 onResize: function(w, h){
39588 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39590 if(typeof w != 'number'){
39591 // we do not handle it!?!?
39594 var tw = this.trigger.getWidth();
39595 tw += this.addicon ? this.addicon.getWidth() : 0;
39596 tw += this.editicon ? this.editicon.getWidth() : 0;
39598 this.el.setWidth( this.adjustWidth('input', x));
39600 this.trigger.setStyle('left', x+'px');
39602 if(this.list && this.listWidth === undefined){
39603 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39604 this.list.setWidth(lw);
39605 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39613 * Allow or prevent the user from directly editing the field text. If false is passed,
39614 * the user will only be able to select from the items defined in the dropdown list. This method
39615 * is the runtime equivalent of setting the 'editable' config option at config time.
39616 * @param {Boolean} value True to allow the user to directly edit the field text
39618 setEditable : function(value){
39619 if(value == this.editable){
39622 this.editable = value;
39624 this.el.dom.setAttribute('readOnly', true);
39625 this.el.on('mousedown', this.onTriggerClick, this);
39626 this.el.addClass('x-combo-noedit');
39628 this.el.dom.setAttribute('readOnly', false);
39629 this.el.un('mousedown', this.onTriggerClick, this);
39630 this.el.removeClass('x-combo-noedit');
39635 onBeforeLoad : function(){
39636 if(!this.hasFocus){
39639 this.innerList.update(this.loadingText ?
39640 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39641 this.restrictHeight();
39642 this.selectedIndex = -1;
39646 onLoad : function(){
39647 if(!this.hasFocus){
39650 if(this.store.getCount() > 0){
39652 this.restrictHeight();
39653 if(this.lastQuery == this.allQuery){
39655 this.el.dom.select();
39657 if(!this.selectByValue(this.value, true)){
39658 this.select(0, true);
39662 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39663 this.taTask.delay(this.typeAheadDelay);
39667 this.onEmptyResults();
39672 onLoadException : function()
39675 Roo.log(this.store.reader.jsonData);
39676 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39677 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39683 onTypeAhead : function(){
39684 if(this.store.getCount() > 0){
39685 var r = this.store.getAt(0);
39686 var newValue = r.data[this.displayField];
39687 var len = newValue.length;
39688 var selStart = this.getRawValue().length;
39689 if(selStart != len){
39690 this.setRawValue(newValue);
39691 this.selectText(selStart, newValue.length);
39697 onSelect : function(record, index){
39698 if(this.fireEvent('beforeselect', this, record, index) !== false){
39699 this.setFromData(index > -1 ? record.data : false);
39701 this.fireEvent('select', this, record, index);
39706 * Returns the currently selected field value or empty string if no value is set.
39707 * @return {String} value The selected value
39709 getValue : function(){
39710 if(this.valueField){
39711 return typeof this.value != 'undefined' ? this.value : '';
39713 return Roo.form.ComboBox.superclass.getValue.call(this);
39718 * Clears any text/value currently set in the field
39720 clearValue : function(){
39721 if(this.hiddenField){
39722 this.hiddenField.value = '';
39725 this.setRawValue('');
39726 this.lastSelectionText = '';
39731 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39732 * will be displayed in the field. If the value does not match the data value of an existing item,
39733 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39734 * Otherwise the field will be blank (although the value will still be set).
39735 * @param {String} value The value to match
39737 setValue : function(v){
39739 if(this.valueField){
39740 var r = this.findRecord(this.valueField, v);
39742 text = r.data[this.displayField];
39743 }else if(this.valueNotFoundText !== undefined){
39744 text = this.valueNotFoundText;
39747 this.lastSelectionText = text;
39748 if(this.hiddenField){
39749 this.hiddenField.value = v;
39751 Roo.form.ComboBox.superclass.setValue.call(this, text);
39755 * @property {Object} the last set data for the element
39760 * Sets the value of the field based on a object which is related to the record format for the store.
39761 * @param {Object} value the value to set as. or false on reset?
39763 setFromData : function(o){
39764 var dv = ''; // display value
39765 var vv = ''; // value value..
39767 if (this.displayField) {
39768 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39770 // this is an error condition!!!
39771 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39774 if(this.valueField){
39775 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39777 if(this.hiddenField){
39778 this.hiddenField.value = vv;
39780 this.lastSelectionText = dv;
39781 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39785 // no hidden field.. - we store the value in 'value', but still display
39786 // display field!!!!
39787 this.lastSelectionText = dv;
39788 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39794 reset : function(){
39795 // overridden so that last data is reset..
39796 this.setValue(this.resetValue);
39797 this.clearInvalid();
39798 this.lastData = false;
39800 this.view.clearSelections();
39804 findRecord : function(prop, value){
39806 if(this.store.getCount() > 0){
39807 this.store.each(function(r){
39808 if(r.data[prop] == value){
39818 getName: function()
39820 // returns hidden if it's set..
39821 if (!this.rendered) {return ''};
39822 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39826 onViewMove : function(e, t){
39827 this.inKeyMode = false;
39831 onViewOver : function(e, t){
39832 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
39835 var item = this.view.findItemFromChild(t);
39837 var index = this.view.indexOf(item);
39838 this.select(index, false);
39843 onViewClick : function(doFocus)
39845 var index = this.view.getSelectedIndexes()[0];
39846 var r = this.store.getAt(index);
39848 this.onSelect(r, index);
39850 if(doFocus !== false && !this.blockFocus){
39856 restrictHeight : function(){
39857 this.innerList.dom.style.height = '';
39858 var inner = this.innerList.dom;
39859 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
39860 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
39861 this.list.beginUpdate();
39862 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
39863 this.list.alignTo(this.el, this.listAlign);
39864 this.list.endUpdate();
39868 onEmptyResults : function(){
39873 * Returns true if the dropdown list is expanded, else false.
39875 isExpanded : function(){
39876 return this.list.isVisible();
39880 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
39881 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39882 * @param {String} value The data value of the item to select
39883 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39884 * selected item if it is not currently in view (defaults to true)
39885 * @return {Boolean} True if the value matched an item in the list, else false
39887 selectByValue : function(v, scrollIntoView){
39888 if(v !== undefined && v !== null){
39889 var r = this.findRecord(this.valueField || this.displayField, v);
39891 this.select(this.store.indexOf(r), scrollIntoView);
39899 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
39900 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
39901 * @param {Number} index The zero-based index of the list item to select
39902 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
39903 * selected item if it is not currently in view (defaults to true)
39905 select : function(index, scrollIntoView){
39906 this.selectedIndex = index;
39907 this.view.select(index);
39908 if(scrollIntoView !== false){
39909 var el = this.view.getNode(index);
39911 this.innerList.scrollChildIntoView(el, false);
39917 selectNext : function(){
39918 var ct = this.store.getCount();
39920 if(this.selectedIndex == -1){
39922 }else if(this.selectedIndex < ct-1){
39923 this.select(this.selectedIndex+1);
39929 selectPrev : function(){
39930 var ct = this.store.getCount();
39932 if(this.selectedIndex == -1){
39934 }else if(this.selectedIndex != 0){
39935 this.select(this.selectedIndex-1);
39941 onKeyUp : function(e){
39942 if(this.editable !== false && !e.isSpecialKey()){
39943 this.lastKey = e.getKey();
39944 this.dqTask.delay(this.queryDelay);
39949 validateBlur : function(){
39950 return !this.list || !this.list.isVisible();
39954 initQuery : function(){
39955 this.doQuery(this.getRawValue());
39959 doForce : function(){
39960 if(this.el.dom.value.length > 0){
39961 this.el.dom.value =
39962 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
39968 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
39969 * query allowing the query action to be canceled if needed.
39970 * @param {String} query The SQL query to execute
39971 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
39972 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
39973 * saved in the current store (defaults to false)
39975 doQuery : function(q, forceAll){
39976 if(q === undefined || q === null){
39981 forceAll: forceAll,
39985 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
39989 forceAll = qe.forceAll;
39990 if(forceAll === true || (q.length >= this.minChars)){
39991 if(this.lastQuery != q || this.alwaysQuery){
39992 this.lastQuery = q;
39993 if(this.mode == 'local'){
39994 this.selectedIndex = -1;
39996 this.store.clearFilter();
39998 this.store.filter(this.displayField, q);
40002 this.store.baseParams[this.queryParam] = q;
40004 params: this.getParams(q)
40009 this.selectedIndex = -1;
40016 getParams : function(q){
40018 //p[this.queryParam] = q;
40021 p.limit = this.pageSize;
40027 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40029 collapse : function(){
40030 if(!this.isExpanded()){
40034 Roo.get(document).un('mousedown', this.collapseIf, this);
40035 Roo.get(document).un('mousewheel', this.collapseIf, this);
40036 if (!this.editable) {
40037 Roo.get(document).un('keydown', this.listKeyPress, this);
40039 this.fireEvent('collapse', this);
40043 collapseIf : function(e){
40044 if(!e.within(this.wrap) && !e.within(this.list)){
40050 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40052 expand : function(){
40053 if(this.isExpanded() || !this.hasFocus){
40056 this.list.alignTo(this.el, this.listAlign);
40058 Roo.get(document).on('mousedown', this.collapseIf, this);
40059 Roo.get(document).on('mousewheel', this.collapseIf, this);
40060 if (!this.editable) {
40061 Roo.get(document).on('keydown', this.listKeyPress, this);
40064 this.fireEvent('expand', this);
40068 // Implements the default empty TriggerField.onTriggerClick function
40069 onTriggerClick : function(){
40073 if(this.isExpanded()){
40075 if (!this.blockFocus) {
40080 this.hasFocus = true;
40081 if(this.triggerAction == 'all') {
40082 this.doQuery(this.allQuery, true);
40084 this.doQuery(this.getRawValue());
40086 if (!this.blockFocus) {
40091 listKeyPress : function(e)
40093 //Roo.log('listkeypress');
40094 // scroll to first matching element based on key pres..
40095 if (e.isSpecialKey()) {
40098 var k = String.fromCharCode(e.getKey()).toUpperCase();
40101 var csel = this.view.getSelectedNodes();
40102 var cselitem = false;
40104 var ix = this.view.indexOf(csel[0]);
40105 cselitem = this.store.getAt(ix);
40106 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40112 this.store.each(function(v) {
40114 // start at existing selection.
40115 if (cselitem.id == v.id) {
40121 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40122 match = this.store.indexOf(v);
40127 if (match === false) {
40128 return true; // no more action?
40131 this.view.select(match);
40132 var sn = Roo.get(this.view.getSelectedNodes()[0])
40133 sn.scrollIntoView(sn.dom.parentNode, false);
40137 * @cfg {Boolean} grow
40141 * @cfg {Number} growMin
40145 * @cfg {Number} growMax
40153 * Copyright(c) 2010-2012, Roo J Solutions Limited
40160 * @class Roo.form.ComboBoxArray
40161 * @extends Roo.form.TextField
40162 * A facebook style adder... for lists of email / people / countries etc...
40163 * pick multiple items from a combo box, and shows each one.
40165 * Fred [x] Brian [x] [Pick another |v]
40168 * For this to work: it needs various extra information
40169 * - normal combo problay has
40171 * + displayField, valueField
40173 * For our purpose...
40176 * If we change from 'extends' to wrapping...
40183 * Create a new ComboBoxArray.
40184 * @param {Object} config Configuration options
40188 Roo.form.ComboBoxArray = function(config)
40193 * Fires when remove the value from the list
40194 * @param {Roo.form.ComboBoxArray} _self This combo box array
40195 * @param {Roo.form.ComboBoxArray.Item} item removed item
40202 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40204 this.items = new Roo.util.MixedCollection(false);
40206 // construct the child combo...
40216 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40219 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40224 // behavies liek a hiddne field
40225 inputType: 'hidden',
40227 * @cfg {Number} width The width of the box that displays the selected element
40234 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40238 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40240 hiddenName : false,
40243 // private the array of items that are displayed..
40245 // private - the hidden field el.
40247 // private - the filed el..
40250 //validateValue : function() { return true; }, // all values are ok!
40251 //onAddClick: function() { },
40253 onRender : function(ct, position)
40256 // create the standard hidden element
40257 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40260 // give fake names to child combo;
40261 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40262 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40264 this.combo = Roo.factory(this.combo, Roo.form);
40265 this.combo.onRender(ct, position);
40266 if (typeof(this.combo.width) != 'undefined') {
40267 this.combo.onResize(this.combo.width,0);
40270 this.combo.initEvents();
40272 // assigned so form know we need to do this..
40273 this.store = this.combo.store;
40274 this.valueField = this.combo.valueField;
40275 this.displayField = this.combo.displayField ;
40278 this.combo.wrap.addClass('x-cbarray-grp');
40280 var cbwrap = this.combo.wrap.createChild(
40281 {tag: 'div', cls: 'x-cbarray-cb'},
40286 this.hiddenEl = this.combo.wrap.createChild({
40287 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40289 this.el = this.combo.wrap.createChild({
40290 tag: 'input', type:'hidden' , name: this.name, value : ''
40292 // this.el.dom.removeAttribute("name");
40295 this.outerWrap = this.combo.wrap;
40296 this.wrap = cbwrap;
40298 this.outerWrap.setWidth(this.width);
40299 this.outerWrap.dom.removeChild(this.el.dom);
40301 this.wrap.dom.appendChild(this.el.dom);
40302 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40303 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40305 this.combo.trigger.setStyle('position','relative');
40306 this.combo.trigger.setStyle('left', '0px');
40307 this.combo.trigger.setStyle('top', '2px');
40309 this.combo.el.setStyle('vertical-align', 'text-bottom');
40311 //this.trigger.setStyle('vertical-align', 'top');
40313 // this should use the code from combo really... on('add' ....)
40317 this.adder = this.outerWrap.createChild(
40318 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40320 this.adder.on('click', function(e) {
40321 _t.fireEvent('adderclick', this, e);
40325 //this.adder.on('click', this.onAddClick, _t);
40328 this.combo.on('select', function(cb, rec, ix) {
40329 this.addItem(rec.data);
40332 cb.el.dom.value = '';
40333 //cb.lastData = rec.data;
40342 getName: function()
40344 // returns hidden if it's set..
40345 if (!this.rendered) {return ''};
40346 return this.hiddenName ? this.hiddenName : this.name;
40351 onResize: function(w, h){
40354 // not sure if this is needed..
40355 //this.combo.onResize(w,h);
40357 if(typeof w != 'number'){
40358 // we do not handle it!?!?
40361 var tw = this.combo.trigger.getWidth();
40362 tw += this.addicon ? this.addicon.getWidth() : 0;
40363 tw += this.editicon ? this.editicon.getWidth() : 0;
40365 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40367 this.combo.trigger.setStyle('left', '0px');
40369 if(this.list && this.listWidth === undefined){
40370 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40371 this.list.setWidth(lw);
40372 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40379 addItem: function(rec)
40381 var valueField = this.combo.valueField;
40382 var displayField = this.combo.displayField;
40383 if (this.items.indexOfKey(rec[valueField]) > -1) {
40384 //console.log("GOT " + rec.data.id);
40388 var x = new Roo.form.ComboBoxArray.Item({
40389 //id : rec[this.idField],
40391 displayField : displayField ,
40392 tipField : displayField ,
40396 this.items.add(rec[valueField],x);
40397 // add it before the element..
40398 this.updateHiddenEl();
40399 x.render(this.outerWrap, this.wrap.dom);
40400 // add the image handler..
40403 updateHiddenEl : function()
40406 if (!this.hiddenEl) {
40410 var idField = this.combo.valueField;
40412 this.items.each(function(f) {
40413 ar.push(f.data[idField]);
40416 this.hiddenEl.dom.value = ar.join(',');
40422 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40423 this.items.each(function(f) {
40426 this.el.dom.value = '';
40427 if (this.hiddenEl) {
40428 this.hiddenEl.dom.value = '';
40432 getValue: function()
40434 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40436 setValue: function(v) // not a valid action - must use addItems..
40443 if (this.store.isLocal && (typeof(v) == 'string')) {
40444 // then we can use the store to find the values..
40445 // comma seperated at present.. this needs to allow JSON based encoding..
40446 this.hiddenEl.value = v;
40448 Roo.each(v.split(','), function(k) {
40449 Roo.log("CHECK " + this.valueField + ',' + k);
40450 var li = this.store.query(this.valueField, k);
40455 add[this.valueField] = k;
40456 add[this.displayField] = li.item(0).data[this.displayField];
40462 if (typeof(v) == 'object') {
40463 // then let's assume it's an array of objects..
40464 Roo.each(v, function(l) {
40472 setFromData: function(v)
40474 // this recieves an object, if setValues is called.
40476 this.el.dom.value = v[this.displayField];
40477 this.hiddenEl.dom.value = v[this.valueField];
40478 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40481 var kv = v[this.valueField];
40482 var dv = v[this.displayField];
40483 kv = typeof(kv) != 'string' ? '' : kv;
40484 dv = typeof(dv) != 'string' ? '' : dv;
40487 var keys = kv.split(',');
40488 var display = dv.split(',');
40489 for (var i = 0 ; i < keys.length; i++) {
40492 add[this.valueField] = keys[i];
40493 add[this.displayField] = display[i];
40501 * Validates the combox array value
40502 * @return {Boolean} True if the value is valid, else false
40504 validate : function(){
40505 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40506 this.clearInvalid();
40512 validateValue : function(value){
40513 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40521 isDirty : function() {
40522 if(this.disabled) {
40527 var d = Roo.decode(String(this.originalValue));
40529 return String(this.getValue()) !== String(this.originalValue);
40532 var originalValue = [];
40534 for (var i = 0; i < d.length; i++){
40535 originalValue.push(d[i][this.valueField]);
40538 return String(this.getValue()) !== String(originalValue.join(','));
40547 * @class Roo.form.ComboBoxArray.Item
40548 * @extends Roo.BoxComponent
40549 * A selected item in the list
40550 * Fred [x] Brian [x] [Pick another |v]
40553 * Create a new item.
40554 * @param {Object} config Configuration options
40557 Roo.form.ComboBoxArray.Item = function(config) {
40558 config.id = Roo.id();
40559 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40562 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40565 displayField : false,
40569 defaultAutoCreate : {
40571 cls: 'x-cbarray-item',
40578 src : Roo.BLANK_IMAGE_URL ,
40586 onRender : function(ct, position)
40588 Roo.form.Field.superclass.onRender.call(this, ct, position);
40591 var cfg = this.getAutoCreate();
40592 this.el = ct.createChild(cfg, position);
40595 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40597 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40598 this.cb.renderer(this.data) :
40599 String.format('{0}',this.data[this.displayField]);
40602 this.el.child('div').dom.setAttribute('qtip',
40603 String.format('{0}',this.data[this.tipField])
40606 this.el.child('img').on('click', this.remove, this);
40610 remove : function()
40612 this.cb.items.remove(this);
40613 this.el.child('img').un('click', this.remove, this);
40615 this.cb.updateHiddenEl();
40617 this.cb.fireEvent('remove', this.cb, this);
40621 * Ext JS Library 1.1.1
40622 * Copyright(c) 2006-2007, Ext JS, LLC.
40624 * Originally Released Under LGPL - original licence link has changed is not relivant.
40627 * <script type="text/javascript">
40630 * @class Roo.form.Checkbox
40631 * @extends Roo.form.Field
40632 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40634 * Creates a new Checkbox
40635 * @param {Object} config Configuration options
40637 Roo.form.Checkbox = function(config){
40638 Roo.form.Checkbox.superclass.constructor.call(this, config);
40642 * Fires when the checkbox is checked or unchecked.
40643 * @param {Roo.form.Checkbox} this This checkbox
40644 * @param {Boolean} checked The new checked value
40650 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40652 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40654 focusClass : undefined,
40656 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40658 fieldClass: "x-form-field",
40660 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40664 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40665 * {tag: "input", type: "checkbox", autocomplete: "off"})
40667 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40669 * @cfg {String} boxLabel The text that appears beside the checkbox
40673 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40677 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40679 valueOff: '0', // value when not checked..
40681 actionMode : 'viewEl',
40684 itemCls : 'x-menu-check-item x-form-item',
40685 groupClass : 'x-menu-group-item',
40686 inputType : 'hidden',
40689 inSetChecked: false, // check that we are not calling self...
40691 inputElement: false, // real input element?
40692 basedOn: false, // ????
40694 isFormField: true, // not sure where this is needed!!!!
40696 onResize : function(){
40697 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40698 if(!this.boxLabel){
40699 this.el.alignTo(this.wrap, 'c-c');
40703 initEvents : function(){
40704 Roo.form.Checkbox.superclass.initEvents.call(this);
40705 this.el.on("click", this.onClick, this);
40706 this.el.on("change", this.onClick, this);
40710 getResizeEl : function(){
40714 getPositionEl : function(){
40719 onRender : function(ct, position){
40720 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40722 if(this.inputValue !== undefined){
40723 this.el.dom.value = this.inputValue;
40726 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40727 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40728 var viewEl = this.wrap.createChild({
40729 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40730 this.viewEl = viewEl;
40731 this.wrap.on('click', this.onClick, this);
40733 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40734 this.el.on('propertychange', this.setFromHidden, this); //ie
40739 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40740 // viewEl.on('click', this.onClick, this);
40742 //if(this.checked){
40743 this.setChecked(this.checked);
40745 //this.checked = this.el.dom;
40751 initValue : Roo.emptyFn,
40754 * Returns the checked state of the checkbox.
40755 * @return {Boolean} True if checked, else false
40757 getValue : function(){
40759 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40761 return this.valueOff;
40766 onClick : function(){
40767 this.setChecked(!this.checked);
40769 //if(this.el.dom.checked != this.checked){
40770 // this.setValue(this.el.dom.checked);
40775 * Sets the checked state of the checkbox.
40776 * On is always based on a string comparison between inputValue and the param.
40777 * @param {Boolean/String} value - the value to set
40778 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40780 setValue : function(v,suppressEvent){
40783 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40784 //if(this.el && this.el.dom){
40785 // this.el.dom.checked = this.checked;
40786 // this.el.dom.defaultChecked = this.checked;
40788 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40789 //this.fireEvent("check", this, this.checked);
40792 setChecked : function(state,suppressEvent)
40794 if (this.inSetChecked) {
40795 this.checked = state;
40801 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
40803 this.checked = state;
40804 if(suppressEvent !== true){
40805 this.fireEvent('check', this, state);
40807 this.inSetChecked = true;
40808 this.el.dom.value = state ? this.inputValue : this.valueOff;
40809 this.inSetChecked = false;
40812 // handle setting of hidden value by some other method!!?!?
40813 setFromHidden: function()
40818 //console.log("SET FROM HIDDEN");
40819 //alert('setFrom hidden');
40820 this.setValue(this.el.dom.value);
40823 onDestroy : function()
40826 Roo.get(this.viewEl).remove();
40829 Roo.form.Checkbox.superclass.onDestroy.call(this);
40834 * Ext JS Library 1.1.1
40835 * Copyright(c) 2006-2007, Ext JS, LLC.
40837 * Originally Released Under LGPL - original licence link has changed is not relivant.
40840 * <script type="text/javascript">
40844 * @class Roo.form.Radio
40845 * @extends Roo.form.Checkbox
40846 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
40847 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
40849 * Creates a new Radio
40850 * @param {Object} config Configuration options
40852 Roo.form.Radio = function(){
40853 Roo.form.Radio.superclass.constructor.apply(this, arguments);
40855 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
40856 inputType: 'radio',
40859 * If this radio is part of a group, it will return the selected value
40862 getGroupValue : function(){
40863 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
40867 onRender : function(ct, position){
40868 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40870 if(this.inputValue !== undefined){
40871 this.el.dom.value = this.inputValue;
40874 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40875 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40876 //var viewEl = this.wrap.createChild({
40877 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40878 //this.viewEl = viewEl;
40879 //this.wrap.on('click', this.onClick, this);
40881 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40882 //this.el.on('propertychange', this.setFromHidden, this); //ie
40887 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40888 // viewEl.on('click', this.onClick, this);
40891 this.el.dom.checked = 'checked' ;
40897 });//<script type="text/javascript">
40900 * Based Ext JS Library 1.1.1
40901 * Copyright(c) 2006-2007, Ext JS, LLC.
40907 * @class Roo.HtmlEditorCore
40908 * @extends Roo.Component
40909 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
40911 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
40914 Roo.HtmlEditorCore = function(config){
40917 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
40920 * @event initialize
40921 * Fires when the editor is fully initialized (including the iframe)
40922 * @param {Roo.HtmlEditorCore} this
40927 * Fires when the editor is first receives the focus. Any insertion must wait
40928 * until after this event.
40929 * @param {Roo.HtmlEditorCore} this
40933 * @event beforesync
40934 * Fires before the textarea is updated with content from the editor iframe. Return false
40935 * to cancel the sync.
40936 * @param {Roo.HtmlEditorCore} this
40937 * @param {String} html
40941 * @event beforepush
40942 * Fires before the iframe editor is updated with content from the textarea. Return false
40943 * to cancel the push.
40944 * @param {Roo.HtmlEditorCore} this
40945 * @param {String} html
40950 * Fires when the textarea is updated with content from the editor iframe.
40951 * @param {Roo.HtmlEditorCore} this
40952 * @param {String} html
40957 * Fires when the iframe editor is updated with content from the textarea.
40958 * @param {Roo.HtmlEditorCore} this
40959 * @param {String} html
40964 * @event editorevent
40965 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
40966 * @param {Roo.HtmlEditorCore} this
40974 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
40978 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
40984 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
40989 * @cfg {Number} height (in pixels)
40993 * @cfg {Number} width (in pixels)
40998 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41001 stylesheets: false,
41006 // private properties
41007 validationEvent : false,
41009 initialized : false,
41011 sourceEditMode : false,
41012 onFocus : Roo.emptyFn,
41014 hideMode:'offsets',
41022 * Protected method that will not generally be called directly. It
41023 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41024 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41026 getDocMarkup : function(){
41029 Roo.log(this.stylesheets);
41031 // inherit styels from page...??
41032 if (this.stylesheets === false) {
41034 Roo.get(document.head).select('style').each(function(node) {
41035 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41038 Roo.get(document.head).select('link').each(function(node) {
41039 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41042 } else if (!this.stylesheets.length) {
41044 st = '<style type="text/css">' +
41045 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41048 Roo.each(this.stylesheets, function(s) {
41049 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
41054 st += '<style type="text/css">' +
41055 'IMG { cursor: pointer } ' +
41059 return '<html><head>' + st +
41060 //<style type="text/css">' +
41061 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41063 ' </head><body class="roo-htmleditor-body"></body></html>';
41067 onRender : function(ct, position)
41070 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41071 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41074 this.el.dom.style.border = '0 none';
41075 this.el.dom.setAttribute('tabIndex', -1);
41076 this.el.addClass('x-hidden hide');
41080 if(Roo.isIE){ // fix IE 1px bogus margin
41081 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41085 this.frameId = Roo.id();
41089 var iframe = this.owner.wrap.createChild({
41091 cls: 'form-control', // bootstrap..
41093 name: this.frameId,
41094 frameBorder : 'no',
41095 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41100 this.iframe = iframe.dom;
41102 this.assignDocWin();
41104 this.doc.designMode = 'on';
41107 this.doc.write(this.getDocMarkup());
41111 var task = { // must defer to wait for browser to be ready
41113 //console.log("run task?" + this.doc.readyState);
41114 this.assignDocWin();
41115 if(this.doc.body || this.doc.readyState == 'complete'){
41117 this.doc.designMode="on";
41121 Roo.TaskMgr.stop(task);
41122 this.initEditor.defer(10, this);
41129 Roo.TaskMgr.start(task);
41136 onResize : function(w, h)
41138 Roo.log('resize: ' +w + ',' + h );
41139 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41143 if(typeof w == 'number'){
41145 this.iframe.style.width = w + 'px';
41147 if(typeof h == 'number'){
41149 this.iframe.style.height = h + 'px';
41151 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41158 * Toggles the editor between standard and source edit mode.
41159 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41161 toggleSourceEdit : function(sourceEditMode){
41163 this.sourceEditMode = sourceEditMode === true;
41165 if(this.sourceEditMode){
41167 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41170 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41171 //this.iframe.className = '';
41174 //this.setSize(this.owner.wrap.getSize());
41175 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41182 * Protected method that will not generally be called directly. If you need/want
41183 * custom HTML cleanup, this is the method you should override.
41184 * @param {String} html The HTML to be cleaned
41185 * return {String} The cleaned HTML
41187 cleanHtml : function(html){
41188 html = String(html);
41189 if(html.length > 5){
41190 if(Roo.isSafari){ // strip safari nonsense
41191 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41194 if(html == ' '){
41201 * HTML Editor -> Textarea
41202 * Protected method that will not generally be called directly. Syncs the contents
41203 * of the editor iframe with the textarea.
41205 syncValue : function(){
41206 if(this.initialized){
41207 var bd = (this.doc.body || this.doc.documentElement);
41208 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41209 var html = bd.innerHTML;
41211 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41212 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41214 html = '<div style="'+m[0]+'">' + html + '</div>';
41217 html = this.cleanHtml(html);
41218 // fix up the special chars.. normaly like back quotes in word...
41219 // however we do not want to do this with chinese..
41220 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41221 var cc = b.charCodeAt();
41223 (cc >= 0x4E00 && cc < 0xA000 ) ||
41224 (cc >= 0x3400 && cc < 0x4E00 ) ||
41225 (cc >= 0xf900 && cc < 0xfb00 )
41231 if(this.owner.fireEvent('beforesync', this, html) !== false){
41232 this.el.dom.value = html;
41233 this.owner.fireEvent('sync', this, html);
41239 * Protected method that will not generally be called directly. Pushes the value of the textarea
41240 * into the iframe editor.
41242 pushValue : function(){
41243 if(this.initialized){
41244 var v = this.el.dom.value.trim();
41246 // if(v.length < 1){
41250 if(this.owner.fireEvent('beforepush', this, v) !== false){
41251 var d = (this.doc.body || this.doc.documentElement);
41253 this.cleanUpPaste();
41254 this.el.dom.value = d.innerHTML;
41255 this.owner.fireEvent('push', this, v);
41261 deferFocus : function(){
41262 this.focus.defer(10, this);
41266 focus : function(){
41267 if(this.win && !this.sourceEditMode){
41274 assignDocWin: function()
41276 var iframe = this.iframe;
41279 this.doc = iframe.contentWindow.document;
41280 this.win = iframe.contentWindow;
41282 if (!Roo.get(this.frameId)) {
41285 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41286 this.win = Roo.get(this.frameId).dom.contentWindow;
41291 initEditor : function(){
41292 //console.log("INIT EDITOR");
41293 this.assignDocWin();
41297 this.doc.designMode="on";
41299 this.doc.write(this.getDocMarkup());
41302 var dbody = (this.doc.body || this.doc.documentElement);
41303 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41304 // this copies styles from the containing element into thsi one..
41305 // not sure why we need all of this..
41306 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41307 ss['background-attachment'] = 'fixed'; // w3c
41308 dbody.bgProperties = 'fixed'; // ie
41309 Roo.DomHelper.applyStyles(dbody, ss);
41310 Roo.EventManager.on(this.doc, {
41311 //'mousedown': this.onEditorEvent,
41312 'mouseup': this.onEditorEvent,
41313 'dblclick': this.onEditorEvent,
41314 'click': this.onEditorEvent,
41315 'keyup': this.onEditorEvent,
41320 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41322 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41323 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41325 this.initialized = true;
41327 this.owner.fireEvent('initialize', this);
41332 onDestroy : function(){
41338 //for (var i =0; i < this.toolbars.length;i++) {
41339 // // fixme - ask toolbars for heights?
41340 // this.toolbars[i].onDestroy();
41343 //this.wrap.dom.innerHTML = '';
41344 //this.wrap.remove();
41349 onFirstFocus : function(){
41351 this.assignDocWin();
41354 this.activated = true;
41357 if(Roo.isGecko){ // prevent silly gecko errors
41359 var s = this.win.getSelection();
41360 if(!s.focusNode || s.focusNode.nodeType != 3){
41361 var r = s.getRangeAt(0);
41362 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41367 this.execCmd('useCSS', true);
41368 this.execCmd('styleWithCSS', false);
41371 this.owner.fireEvent('activate', this);
41375 adjustFont: function(btn){
41376 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41377 //if(Roo.isSafari){ // safari
41380 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41381 if(Roo.isSafari){ // safari
41382 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41383 v = (v < 10) ? 10 : v;
41384 v = (v > 48) ? 48 : v;
41385 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41390 v = Math.max(1, v+adjust);
41392 this.execCmd('FontSize', v );
41395 onEditorEvent : function(e){
41396 this.owner.fireEvent('editorevent', this, e);
41397 // this.updateToolbar();
41398 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41401 insertTag : function(tg)
41403 // could be a bit smarter... -> wrap the current selected tRoo..
41404 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41406 range = this.createRange(this.getSelection());
41407 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41408 wrappingNode.appendChild(range.extractContents());
41409 range.insertNode(wrappingNode);
41416 this.execCmd("formatblock", tg);
41420 insertText : function(txt)
41424 var range = this.createRange();
41425 range.deleteContents();
41426 //alert(Sender.getAttribute('label'));
41428 range.insertNode(this.doc.createTextNode(txt));
41434 * Executes a Midas editor command on the editor document and performs necessary focus and
41435 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41436 * @param {String} cmd The Midas command
41437 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41439 relayCmd : function(cmd, value){
41441 this.execCmd(cmd, value);
41442 this.owner.fireEvent('editorevent', this);
41443 //this.updateToolbar();
41444 this.owner.deferFocus();
41448 * Executes a Midas editor command directly on the editor document.
41449 * For visual commands, you should use {@link #relayCmd} instead.
41450 * <b>This should only be called after the editor is initialized.</b>
41451 * @param {String} cmd The Midas command
41452 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41454 execCmd : function(cmd, value){
41455 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41462 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41464 * @param {String} text | dom node..
41466 insertAtCursor : function(text)
41471 if(!this.activated){
41477 var r = this.doc.selection.createRange();
41488 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41492 // from jquery ui (MIT licenced)
41494 var win = this.win;
41496 if (win.getSelection && win.getSelection().getRangeAt) {
41497 range = win.getSelection().getRangeAt(0);
41498 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41499 range.insertNode(node);
41500 } else if (win.document.selection && win.document.selection.createRange) {
41501 // no firefox support
41502 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41503 win.document.selection.createRange().pasteHTML(txt);
41505 // no firefox support
41506 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41507 this.execCmd('InsertHTML', txt);
41516 mozKeyPress : function(e){
41518 var c = e.getCharCode(), cmd;
41521 c = String.fromCharCode(c).toLowerCase();
41535 this.cleanUpPaste.defer(100, this);
41543 e.preventDefault();
41551 fixKeys : function(){ // load time branching for fastest keydown performance
41553 return function(e){
41554 var k = e.getKey(), r;
41557 r = this.doc.selection.createRange();
41560 r.pasteHTML('    ');
41567 r = this.doc.selection.createRange();
41569 var target = r.parentElement();
41570 if(!target || target.tagName.toLowerCase() != 'li'){
41572 r.pasteHTML('<br />');
41578 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41579 this.cleanUpPaste.defer(100, this);
41585 }else if(Roo.isOpera){
41586 return function(e){
41587 var k = e.getKey();
41591 this.execCmd('InsertHTML','    ');
41594 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41595 this.cleanUpPaste.defer(100, this);
41600 }else if(Roo.isSafari){
41601 return function(e){
41602 var k = e.getKey();
41606 this.execCmd('InsertText','\t');
41610 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41611 this.cleanUpPaste.defer(100, this);
41619 getAllAncestors: function()
41621 var p = this.getSelectedNode();
41624 a.push(p); // push blank onto stack..
41625 p = this.getParentElement();
41629 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41633 a.push(this.doc.body);
41637 lastSelNode : false,
41640 getSelection : function()
41642 this.assignDocWin();
41643 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41646 getSelectedNode: function()
41648 // this may only work on Gecko!!!
41650 // should we cache this!!!!
41655 var range = this.createRange(this.getSelection()).cloneRange();
41658 var parent = range.parentElement();
41660 var testRange = range.duplicate();
41661 testRange.moveToElementText(parent);
41662 if (testRange.inRange(range)) {
41665 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41668 parent = parent.parentElement;
41673 // is ancestor a text element.
41674 var ac = range.commonAncestorContainer;
41675 if (ac.nodeType == 3) {
41676 ac = ac.parentNode;
41679 var ar = ac.childNodes;
41682 var other_nodes = [];
41683 var has_other_nodes = false;
41684 for (var i=0;i<ar.length;i++) {
41685 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41688 // fullly contained node.
41690 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41695 // probably selected..
41696 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41697 other_nodes.push(ar[i]);
41701 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41706 has_other_nodes = true;
41708 if (!nodes.length && other_nodes.length) {
41709 nodes= other_nodes;
41711 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41717 createRange: function(sel)
41719 // this has strange effects when using with
41720 // top toolbar - not sure if it's a great idea.
41721 //this.editor.contentWindow.focus();
41722 if (typeof sel != "undefined") {
41724 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41726 return this.doc.createRange();
41729 return this.doc.createRange();
41732 getParentElement: function()
41735 this.assignDocWin();
41736 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41738 var range = this.createRange(sel);
41741 var p = range.commonAncestorContainer;
41742 while (p.nodeType == 3) { // text node
41753 * Range intersection.. the hard stuff...
41757 * [ -- selected range --- ]
41761 * if end is before start or hits it. fail.
41762 * if start is after end or hits it fail.
41764 * if either hits (but other is outside. - then it's not
41770 // @see http://www.thismuchiknow.co.uk/?p=64.
41771 rangeIntersectsNode : function(range, node)
41773 var nodeRange = node.ownerDocument.createRange();
41775 nodeRange.selectNode(node);
41777 nodeRange.selectNodeContents(node);
41780 var rangeStartRange = range.cloneRange();
41781 rangeStartRange.collapse(true);
41783 var rangeEndRange = range.cloneRange();
41784 rangeEndRange.collapse(false);
41786 var nodeStartRange = nodeRange.cloneRange();
41787 nodeStartRange.collapse(true);
41789 var nodeEndRange = nodeRange.cloneRange();
41790 nodeEndRange.collapse(false);
41792 return rangeStartRange.compareBoundaryPoints(
41793 Range.START_TO_START, nodeEndRange) == -1 &&
41794 rangeEndRange.compareBoundaryPoints(
41795 Range.START_TO_START, nodeStartRange) == 1;
41799 rangeCompareNode : function(range, node)
41801 var nodeRange = node.ownerDocument.createRange();
41803 nodeRange.selectNode(node);
41805 nodeRange.selectNodeContents(node);
41809 range.collapse(true);
41811 nodeRange.collapse(true);
41813 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
41814 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
41816 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
41818 var nodeIsBefore = ss == 1;
41819 var nodeIsAfter = ee == -1;
41821 if (nodeIsBefore && nodeIsAfter)
41823 if (!nodeIsBefore && nodeIsAfter)
41824 return 1; //right trailed.
41826 if (nodeIsBefore && !nodeIsAfter)
41827 return 2; // left trailed.
41832 // private? - in a new class?
41833 cleanUpPaste : function()
41835 // cleans up the whole document..
41836 Roo.log('cleanuppaste');
41838 this.cleanUpChildren(this.doc.body);
41839 var clean = this.cleanWordChars(this.doc.body.innerHTML);
41840 if (clean != this.doc.body.innerHTML) {
41841 this.doc.body.innerHTML = clean;
41846 cleanWordChars : function(input) {// change the chars to hex code
41847 var he = Roo.HtmlEditorCore;
41849 var output = input;
41850 Roo.each(he.swapCodes, function(sw) {
41851 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
41853 output = output.replace(swapper, sw[1]);
41860 cleanUpChildren : function (n)
41862 if (!n.childNodes.length) {
41865 for (var i = n.childNodes.length-1; i > -1 ; i--) {
41866 this.cleanUpChild(n.childNodes[i]);
41873 cleanUpChild : function (node)
41876 //console.log(node);
41877 if (node.nodeName == "#text") {
41878 // clean up silly Windows -- stuff?
41881 if (node.nodeName == "#comment") {
41882 node.parentNode.removeChild(node);
41883 // clean up silly Windows -- stuff?
41887 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
41889 node.parentNode.removeChild(node);
41894 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
41896 // remove <a name=....> as rendering on yahoo mailer is borked with this.
41897 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
41899 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
41900 // remove_keep_children = true;
41903 if (remove_keep_children) {
41904 this.cleanUpChildren(node);
41905 // inserts everything just before this node...
41906 while (node.childNodes.length) {
41907 var cn = node.childNodes[0];
41908 node.removeChild(cn);
41909 node.parentNode.insertBefore(cn, node);
41911 node.parentNode.removeChild(node);
41915 if (!node.attributes || !node.attributes.length) {
41916 this.cleanUpChildren(node);
41920 function cleanAttr(n,v)
41923 if (v.match(/^\./) || v.match(/^\//)) {
41926 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
41929 if (v.match(/^#/)) {
41932 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
41933 node.removeAttribute(n);
41937 function cleanStyle(n,v)
41939 if (v.match(/expression/)) { //XSS?? should we even bother..
41940 node.removeAttribute(n);
41943 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
41944 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
41947 var parts = v.split(/;/);
41950 Roo.each(parts, function(p) {
41951 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
41955 var l = p.split(':').shift().replace(/\s+/g,'');
41956 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
41958 if ( cblack.indexOf(l) > -1) {
41959 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41960 //node.removeAttribute(n);
41964 // only allow 'c whitelisted system attributes'
41965 if ( cwhite.length && cwhite.indexOf(l) < 0) {
41966 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
41967 //node.removeAttribute(n);
41977 if (clean.length) {
41978 node.setAttribute(n, clean.join(';'));
41980 node.removeAttribute(n);
41986 for (var i = node.attributes.length-1; i > -1 ; i--) {
41987 var a = node.attributes[i];
41990 if (a.name.toLowerCase().substr(0,2)=='on') {
41991 node.removeAttribute(a.name);
41994 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
41995 node.removeAttribute(a.name);
41998 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
41999 cleanAttr(a.name,a.value); // fixme..
42002 if (a.name == 'style') {
42003 cleanStyle(a.name,a.value);
42006 /// clean up MS crap..
42007 // tecnically this should be a list of valid class'es..
42010 if (a.name == 'class') {
42011 if (a.value.match(/^Mso/)) {
42012 node.className = '';
42015 if (a.value.match(/body/)) {
42016 node.className = '';
42027 this.cleanUpChildren(node);
42032 * Clean up MS wordisms...
42034 cleanWord : function(node)
42037 var cleanWordChildren = function()
42039 if (!node.childNodes.length) {
42042 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42043 _t.cleanWord(node.childNodes[i]);
42049 this.cleanWord(this.doc.body);
42052 if (node.nodeName == "#text") {
42053 // clean up silly Windows -- stuff?
42056 if (node.nodeName == "#comment") {
42057 node.parentNode.removeChild(node);
42058 // clean up silly Windows -- stuff?
42062 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42063 node.parentNode.removeChild(node);
42067 // remove - but keep children..
42068 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42069 while (node.childNodes.length) {
42070 var cn = node.childNodes[0];
42071 node.removeChild(cn);
42072 node.parentNode.insertBefore(cn, node);
42074 node.parentNode.removeChild(node);
42075 cleanWordChildren();
42079 if (node.className.length) {
42081 var cn = node.className.split(/\W+/);
42083 Roo.each(cn, function(cls) {
42084 if (cls.match(/Mso[a-zA-Z]+/)) {
42089 node.className = cna.length ? cna.join(' ') : '';
42091 node.removeAttribute("class");
42095 if (node.hasAttribute("lang")) {
42096 node.removeAttribute("lang");
42099 if (node.hasAttribute("style")) {
42101 var styles = node.getAttribute("style").split(";");
42103 Roo.each(styles, function(s) {
42104 if (!s.match(/:/)) {
42107 var kv = s.split(":");
42108 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42111 // what ever is left... we allow.
42114 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42115 if (!nstyle.length) {
42116 node.removeAttribute('style');
42120 cleanWordChildren();
42124 domToHTML : function(currentElement, depth, nopadtext) {
42126 depth = depth || 0;
42127 nopadtext = nopadtext || false;
42129 if (!currentElement) {
42130 return this.domToHTML(this.doc.body);
42133 //Roo.log(currentElement);
42135 var allText = false;
42136 var nodeName = currentElement.nodeName;
42137 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42139 if (nodeName == '#text') {
42140 return currentElement.nodeValue;
42145 if (nodeName != 'BODY') {
42148 // Prints the node tagName, such as <A>, <IMG>, etc
42151 for(i = 0; i < currentElement.attributes.length;i++) {
42153 var aname = currentElement.attributes.item(i).name;
42154 if (!currentElement.attributes.item(i).value.length) {
42157 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42160 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42169 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42172 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42177 // Traverse the tree
42179 var currentElementChild = currentElement.childNodes.item(i);
42180 var allText = true;
42181 var innerHTML = '';
42183 while (currentElementChild) {
42184 // Formatting code (indent the tree so it looks nice on the screen)
42185 var nopad = nopadtext;
42186 if (lastnode == 'SPAN') {
42190 if (currentElementChild.nodeName == '#text') {
42191 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42192 if (!nopad && toadd.length > 80) {
42193 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42195 innerHTML += toadd;
42198 currentElementChild = currentElement.childNodes.item(i);
42204 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42206 // Recursively traverse the tree structure of the child node
42207 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42208 lastnode = currentElementChild.nodeName;
42210 currentElementChild=currentElement.childNodes.item(i);
42216 // The remaining code is mostly for formatting the tree
42217 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42222 ret+= "</"+tagName+">";
42228 // hide stuff that is not compatible
42242 * @event specialkey
42246 * @cfg {String} fieldClass @hide
42249 * @cfg {String} focusClass @hide
42252 * @cfg {String} autoCreate @hide
42255 * @cfg {String} inputType @hide
42258 * @cfg {String} invalidClass @hide
42261 * @cfg {String} invalidText @hide
42264 * @cfg {String} msgFx @hide
42267 * @cfg {String} validateOnBlur @hide
42271 Roo.HtmlEditorCore.white = [
42272 'area', 'br', 'img', 'input', 'hr', 'wbr',
42274 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42275 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42276 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42277 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42278 'table', 'ul', 'xmp',
42280 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42283 'dir', 'menu', 'ol', 'ul', 'dl',
42289 Roo.HtmlEditorCore.black = [
42290 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42292 'base', 'basefont', 'bgsound', 'blink', 'body',
42293 'frame', 'frameset', 'head', 'html', 'ilayer',
42294 'iframe', 'layer', 'link', 'meta', 'object',
42295 'script', 'style' ,'title', 'xml' // clean later..
42297 Roo.HtmlEditorCore.clean = [
42298 'script', 'style', 'title', 'xml'
42300 Roo.HtmlEditorCore.remove = [
42305 Roo.HtmlEditorCore.ablack = [
42309 Roo.HtmlEditorCore.aclean = [
42310 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42314 Roo.HtmlEditorCore.pwhite= [
42315 'http', 'https', 'mailto'
42318 // white listed style attributes.
42319 Roo.HtmlEditorCore.cwhite= [
42320 // 'text-align', /// default is to allow most things..
42326 // black listed style attributes.
42327 Roo.HtmlEditorCore.cblack= [
42328 // 'font-size' -- this can be set by the project
42332 Roo.HtmlEditorCore.swapCodes =[
42343 //<script type="text/javascript">
42346 * Ext JS Library 1.1.1
42347 * Copyright(c) 2006-2007, Ext JS, LLC.
42353 Roo.form.HtmlEditor = function(config){
42357 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42359 if (!this.toolbars) {
42360 this.toolbars = [];
42362 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42368 * @class Roo.form.HtmlEditor
42369 * @extends Roo.form.Field
42370 * Provides a lightweight HTML Editor component.
42372 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42374 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42375 * supported by this editor.</b><br/><br/>
42376 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42377 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42379 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42381 * @cfg {Boolean} clearUp
42385 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42390 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42395 * @cfg {Number} height (in pixels)
42399 * @cfg {Number} width (in pixels)
42404 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42407 stylesheets: false,
42412 // private properties
42413 validationEvent : false,
42415 initialized : false,
42418 onFocus : Roo.emptyFn,
42420 hideMode:'offsets',
42422 defaultAutoCreate : { // modified by initCompnoent..
42424 style:"width:500px;height:300px;",
42425 autocomplete: "off"
42429 initComponent : function(){
42432 * @event initialize
42433 * Fires when the editor is fully initialized (including the iframe)
42434 * @param {HtmlEditor} this
42439 * Fires when the editor is first receives the focus. Any insertion must wait
42440 * until after this event.
42441 * @param {HtmlEditor} this
42445 * @event beforesync
42446 * Fires before the textarea is updated with content from the editor iframe. Return false
42447 * to cancel the sync.
42448 * @param {HtmlEditor} this
42449 * @param {String} html
42453 * @event beforepush
42454 * Fires before the iframe editor is updated with content from the textarea. Return false
42455 * to cancel the push.
42456 * @param {HtmlEditor} this
42457 * @param {String} html
42462 * Fires when the textarea is updated with content from the editor iframe.
42463 * @param {HtmlEditor} this
42464 * @param {String} html
42469 * Fires when the iframe editor is updated with content from the textarea.
42470 * @param {HtmlEditor} this
42471 * @param {String} html
42475 * @event editmodechange
42476 * Fires when the editor switches edit modes
42477 * @param {HtmlEditor} this
42478 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42480 editmodechange: true,
42482 * @event editorevent
42483 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42484 * @param {HtmlEditor} this
42488 * @event firstfocus
42489 * Fires when on first focus - needed by toolbars..
42490 * @param {HtmlEditor} this
42495 * Auto save the htmlEditor value as a file into Events
42496 * @param {HtmlEditor} this
42500 * @event savedpreview
42501 * preview the saved version of htmlEditor
42502 * @param {HtmlEditor} this
42506 this.defaultAutoCreate = {
42508 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42509 autocomplete: "off"
42514 * Protected method that will not generally be called directly. It
42515 * is called when the editor creates its toolbar. Override this method if you need to
42516 * add custom toolbar buttons.
42517 * @param {HtmlEditor} editor
42519 createToolbar : function(editor){
42520 Roo.log("create toolbars");
42521 if (!editor.toolbars || !editor.toolbars.length) {
42522 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42525 for (var i =0 ; i < editor.toolbars.length;i++) {
42526 editor.toolbars[i] = Roo.factory(
42527 typeof(editor.toolbars[i]) == 'string' ?
42528 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42529 Roo.form.HtmlEditor);
42530 editor.toolbars[i].init(editor);
42538 onRender : function(ct, position)
42541 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42543 this.wrap = this.el.wrap({
42544 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42547 this.editorcore.onRender(ct, position);
42549 if (this.resizable) {
42550 this.resizeEl = new Roo.Resizable(this.wrap, {
42554 minHeight : this.height,
42555 height: this.height,
42556 handles : this.resizable,
42559 resize : function(r, w, h) {
42560 _t.onResize(w,h); // -something
42566 this.createToolbar(this);
42570 this.setSize(this.wrap.getSize());
42572 if (this.resizeEl) {
42573 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42574 // should trigger onReize..
42577 // if(this.autosave && this.w){
42578 // this.autoSaveFn = setInterval(this.autosave, 1000);
42583 onResize : function(w, h)
42585 //Roo.log('resize: ' +w + ',' + h );
42586 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
42591 if(typeof w == 'number'){
42592 var aw = w - this.wrap.getFrameWidth('lr');
42593 this.el.setWidth(this.adjustWidth('textarea', aw));
42596 if(typeof h == 'number'){
42598 for (var i =0; i < this.toolbars.length;i++) {
42599 // fixme - ask toolbars for heights?
42600 tbh += this.toolbars[i].tb.el.getHeight();
42601 if (this.toolbars[i].footer) {
42602 tbh += this.toolbars[i].footer.el.getHeight();
42609 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
42610 ah -= 5; // knock a few pixes off for look..
42611 this.el.setHeight(this.adjustWidth('textarea', ah));
42615 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
42616 this.editorcore.onResize(ew,eh);
42621 * Toggles the editor between standard and source edit mode.
42622 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42624 toggleSourceEdit : function(sourceEditMode)
42626 this.editorcore.toggleSourceEdit(sourceEditMode);
42628 if(this.editorcore.sourceEditMode){
42629 Roo.log('editor - showing textarea');
42632 // Roo.log(this.syncValue());
42633 this.editorcore.syncValue();
42634 this.el.removeClass('x-hidden');
42635 this.el.dom.removeAttribute('tabIndex');
42638 Roo.log('editor - hiding textarea');
42640 // Roo.log(this.pushValue());
42641 this.editorcore.pushValue();
42643 this.el.addClass('x-hidden');
42644 this.el.dom.setAttribute('tabIndex', -1);
42645 //this.deferFocus();
42648 this.setSize(this.wrap.getSize());
42649 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
42652 // private (for BoxComponent)
42653 adjustSize : Roo.BoxComponent.prototype.adjustSize,
42655 // private (for BoxComponent)
42656 getResizeEl : function(){
42660 // private (for BoxComponent)
42661 getPositionEl : function(){
42666 initEvents : function(){
42667 this.originalValue = this.getValue();
42671 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42674 markInvalid : Roo.emptyFn,
42676 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
42679 clearInvalid : Roo.emptyFn,
42681 setValue : function(v){
42682 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
42683 this.editorcore.pushValue();
42688 deferFocus : function(){
42689 this.focus.defer(10, this);
42693 focus : function(){
42694 this.editorcore.focus();
42700 onDestroy : function(){
42706 for (var i =0; i < this.toolbars.length;i++) {
42707 // fixme - ask toolbars for heights?
42708 this.toolbars[i].onDestroy();
42711 this.wrap.dom.innerHTML = '';
42712 this.wrap.remove();
42717 onFirstFocus : function(){
42718 //Roo.log("onFirstFocus");
42719 this.editorcore.onFirstFocus();
42720 for (var i =0; i < this.toolbars.length;i++) {
42721 this.toolbars[i].onFirstFocus();
42727 syncValue : function()
42729 this.editorcore.syncValue();
42732 pushValue : function()
42734 this.editorcore.pushValue();
42738 // hide stuff that is not compatible
42752 * @event specialkey
42756 * @cfg {String} fieldClass @hide
42759 * @cfg {String} focusClass @hide
42762 * @cfg {String} autoCreate @hide
42765 * @cfg {String} inputType @hide
42768 * @cfg {String} invalidClass @hide
42771 * @cfg {String} invalidText @hide
42774 * @cfg {String} msgFx @hide
42777 * @cfg {String} validateOnBlur @hide
42781 // <script type="text/javascript">
42784 * Ext JS Library 1.1.1
42785 * Copyright(c) 2006-2007, Ext JS, LLC.
42791 * @class Roo.form.HtmlEditorToolbar1
42796 new Roo.form.HtmlEditor({
42799 new Roo.form.HtmlEditorToolbar1({
42800 disable : { fonts: 1 , format: 1, ..., ... , ...],
42806 * @cfg {Object} disable List of elements to disable..
42807 * @cfg {Array} btns List of additional buttons.
42811 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
42814 Roo.form.HtmlEditor.ToolbarStandard = function(config)
42817 Roo.apply(this, config);
42819 // default disabled, based on 'good practice'..
42820 this.disable = this.disable || {};
42821 Roo.applyIf(this.disable, {
42824 specialElements : true
42828 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
42829 // dont call parent... till later.
42832 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
42839 editorcore : false,
42841 * @cfg {Object} disable List of toolbar elements to disable
42848 * @cfg {String} createLinkText The default text for the create link prompt
42850 createLinkText : 'Please enter the URL for the link:',
42852 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
42854 defaultLinkValue : 'http:/'+'/',
42858 * @cfg {Array} fontFamilies An array of available font families
42876 // "á" , ?? a acute?
42881 "°" // , // degrees
42883 // "é" , // e ecute
42884 // "ú" , // u ecute?
42887 specialElements : [
42889 text: "Insert Table",
42892 ihtml : '<table><tr><td>Cell</td></tr></table>'
42896 text: "Insert Image",
42899 ihtml : '<img src="about:blank"/>'
42908 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
42909 "input:submit", "input:button", "select", "textarea", "label" ],
42912 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
42914 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
42922 * @cfg {String} defaultFont default font to use.
42924 defaultFont: 'tahoma',
42926 fontSelect : false,
42929 formatCombo : false,
42931 init : function(editor)
42933 this.editor = editor;
42934 this.editorcore = editor.editorcore ? editor.editorcore : editor;
42935 var editorcore = this.editorcore;
42939 var fid = editorcore.frameId;
42941 function btn(id, toggle, handler){
42942 var xid = fid + '-'+ id ;
42946 cls : 'x-btn-icon x-edit-'+id,
42947 enableToggle:toggle !== false,
42948 scope: _t, // was editor...
42949 handler:handler||_t.relayBtnCmd,
42950 clickEvent:'mousedown',
42951 tooltip: etb.buttonTips[id] || undefined, ///tips ???
42958 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
42960 // stop form submits
42961 tb.el.on('click', function(e){
42962 e.preventDefault(); // what does this do?
42965 if(!this.disable.font) { // && !Roo.isSafari){
42966 /* why no safari for fonts
42967 editor.fontSelect = tb.el.createChild({
42970 cls:'x-font-select',
42971 html: this.createFontOptions()
42974 editor.fontSelect.on('change', function(){
42975 var font = editor.fontSelect.dom.value;
42976 editor.relayCmd('fontname', font);
42977 editor.deferFocus();
42981 editor.fontSelect.dom,
42987 if(!this.disable.formats){
42988 this.formatCombo = new Roo.form.ComboBox({
42989 store: new Roo.data.SimpleStore({
42992 data : this.formats // from states.js
42996 //autoCreate : {tag: "div", size: "20"},
42997 displayField:'tag',
43001 triggerAction: 'all',
43002 emptyText:'Add tag',
43003 selectOnFocus:true,
43006 'select': function(c, r, i) {
43007 editorcore.insertTag(r.get('tag'));
43013 tb.addField(this.formatCombo);
43017 if(!this.disable.format){
43024 if(!this.disable.fontSize){
43029 btn('increasefontsize', false, editorcore.adjustFont),
43030 btn('decreasefontsize', false, editorcore.adjustFont)
43035 if(!this.disable.colors){
43038 id:editorcore.frameId +'-forecolor',
43039 cls:'x-btn-icon x-edit-forecolor',
43040 clickEvent:'mousedown',
43041 tooltip: this.buttonTips['forecolor'] || undefined,
43043 menu : new Roo.menu.ColorMenu({
43044 allowReselect: true,
43045 focus: Roo.emptyFn,
43048 selectHandler: function(cp, color){
43049 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43050 editor.deferFocus();
43053 clickEvent:'mousedown'
43056 id:editorcore.frameId +'backcolor',
43057 cls:'x-btn-icon x-edit-backcolor',
43058 clickEvent:'mousedown',
43059 tooltip: this.buttonTips['backcolor'] || undefined,
43061 menu : new Roo.menu.ColorMenu({
43062 focus: Roo.emptyFn,
43065 allowReselect: true,
43066 selectHandler: function(cp, color){
43068 editorcore.execCmd('useCSS', false);
43069 editorcore.execCmd('hilitecolor', color);
43070 editorcore.execCmd('useCSS', true);
43071 editor.deferFocus();
43073 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43074 Roo.isSafari || Roo.isIE ? '#'+color : color);
43075 editor.deferFocus();
43079 clickEvent:'mousedown'
43084 // now add all the items...
43087 if(!this.disable.alignments){
43090 btn('justifyleft'),
43091 btn('justifycenter'),
43092 btn('justifyright')
43096 //if(!Roo.isSafari){
43097 if(!this.disable.links){
43100 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43104 if(!this.disable.lists){
43107 btn('insertorderedlist'),
43108 btn('insertunorderedlist')
43111 if(!this.disable.sourceEdit){
43114 btn('sourceedit', true, function(btn){
43116 this.toggleSourceEdit(btn.pressed);
43123 // special menu.. - needs to be tidied up..
43124 if (!this.disable.special) {
43127 cls: 'x-edit-none',
43133 for (var i =0; i < this.specialChars.length; i++) {
43134 smenu.menu.items.push({
43136 html: this.specialChars[i],
43137 handler: function(a,b) {
43138 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43139 //editor.insertAtCursor(a.html);
43153 if (!this.disable.cleanStyles) {
43155 cls: 'x-btn-icon x-btn-clear',
43161 for (var i =0; i < this.cleanStyles.length; i++) {
43162 cmenu.menu.items.push({
43163 actiontype : this.cleanStyles[i],
43164 html: 'Remove ' + this.cleanStyles[i],
43165 handler: function(a,b) {
43168 var c = Roo.get(editorcore.doc.body);
43169 c.select('[style]').each(function(s) {
43170 s.dom.style.removeProperty(a.actiontype);
43172 editorcore.syncValue();
43177 cmenu.menu.items.push({
43178 actiontype : 'word',
43179 html: 'Remove MS Word Formating',
43180 handler: function(a,b) {
43181 editorcore.cleanWord();
43182 editorcore.syncValue();
43187 cmenu.menu.items.push({
43188 actiontype : 'all',
43189 html: 'Remove All Styles',
43190 handler: function(a,b) {
43192 var c = Roo.get(editorcore.doc.body);
43193 c.select('[style]').each(function(s) {
43194 s.dom.removeAttribute('style');
43196 editorcore.syncValue();
43200 cmenu.menu.items.push({
43201 actiontype : 'word',
43202 html: 'Tidy HTML Source',
43203 handler: function(a,b) {
43204 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43205 editorcore.syncValue();
43214 if (!this.disable.specialElements) {
43217 cls: 'x-edit-none',
43222 for (var i =0; i < this.specialElements.length; i++) {
43223 semenu.menu.items.push(
43225 handler: function(a,b) {
43226 editor.insertAtCursor(this.ihtml);
43228 }, this.specialElements[i])
43240 for(var i =0; i< this.btns.length;i++) {
43241 var b = Roo.factory(this.btns[i],Roo.form);
43242 b.cls = 'x-edit-none';
43243 b.scope = editorcore;
43251 // disable everything...
43253 this.tb.items.each(function(item){
43254 if(item.id != editorcore.frameId+ '-sourceedit'){
43258 this.rendered = true;
43260 // the all the btns;
43261 editor.on('editorevent', this.updateToolbar, this);
43262 // other toolbars need to implement this..
43263 //editor.on('editmodechange', this.updateToolbar, this);
43267 relayBtnCmd : function(btn) {
43268 this.editorcore.relayCmd(btn.cmd);
43270 // private used internally
43271 createLink : function(){
43272 Roo.log("create link?");
43273 var url = prompt(this.createLinkText, this.defaultLinkValue);
43274 if(url && url != 'http:/'+'/'){
43275 this.editorcore.relayCmd('createlink', url);
43281 * Protected method that will not generally be called directly. It triggers
43282 * a toolbar update by reading the markup state of the current selection in the editor.
43284 updateToolbar: function(){
43286 if(!this.editorcore.activated){
43287 this.editor.onFirstFocus();
43291 var btns = this.tb.items.map,
43292 doc = this.editorcore.doc,
43293 frameId = this.editorcore.frameId;
43295 if(!this.disable.font && !Roo.isSafari){
43297 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43298 if(name != this.fontSelect.dom.value){
43299 this.fontSelect.dom.value = name;
43303 if(!this.disable.format){
43304 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43305 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43306 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43308 if(!this.disable.alignments){
43309 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43310 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43311 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43313 if(!Roo.isSafari && !this.disable.lists){
43314 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43315 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43318 var ans = this.editorcore.getAllAncestors();
43319 if (this.formatCombo) {
43322 var store = this.formatCombo.store;
43323 this.formatCombo.setValue("");
43324 for (var i =0; i < ans.length;i++) {
43325 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43327 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43335 // hides menus... - so this cant be on a menu...
43336 Roo.menu.MenuMgr.hideAll();
43338 //this.editorsyncValue();
43342 createFontOptions : function(){
43343 var buf = [], fs = this.fontFamilies, ff, lc;
43347 for(var i = 0, len = fs.length; i< len; i++){
43349 lc = ff.toLowerCase();
43351 '<option value="',lc,'" style="font-family:',ff,';"',
43352 (this.defaultFont == lc ? ' selected="true">' : '>'),
43357 return buf.join('');
43360 toggleSourceEdit : function(sourceEditMode){
43362 Roo.log("toolbar toogle");
43363 if(sourceEditMode === undefined){
43364 sourceEditMode = !this.sourceEditMode;
43366 this.sourceEditMode = sourceEditMode === true;
43367 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43368 // just toggle the button?
43369 if(btn.pressed !== this.sourceEditMode){
43370 btn.toggle(this.sourceEditMode);
43374 if(sourceEditMode){
43375 Roo.log("disabling buttons");
43376 this.tb.items.each(function(item){
43377 if(item.cmd != 'sourceedit'){
43383 Roo.log("enabling buttons");
43384 if(this.editorcore.initialized){
43385 this.tb.items.each(function(item){
43391 Roo.log("calling toggole on editor");
43392 // tell the editor that it's been pressed..
43393 this.editor.toggleSourceEdit(sourceEditMode);
43397 * Object collection of toolbar tooltips for the buttons in the editor. The key
43398 * is the command id associated with that button and the value is a valid QuickTips object.
43403 title: 'Bold (Ctrl+B)',
43404 text: 'Make the selected text bold.',
43405 cls: 'x-html-editor-tip'
43408 title: 'Italic (Ctrl+I)',
43409 text: 'Make the selected text italic.',
43410 cls: 'x-html-editor-tip'
43418 title: 'Bold (Ctrl+B)',
43419 text: 'Make the selected text bold.',
43420 cls: 'x-html-editor-tip'
43423 title: 'Italic (Ctrl+I)',
43424 text: 'Make the selected text italic.',
43425 cls: 'x-html-editor-tip'
43428 title: 'Underline (Ctrl+U)',
43429 text: 'Underline the selected text.',
43430 cls: 'x-html-editor-tip'
43432 increasefontsize : {
43433 title: 'Grow Text',
43434 text: 'Increase the font size.',
43435 cls: 'x-html-editor-tip'
43437 decreasefontsize : {
43438 title: 'Shrink Text',
43439 text: 'Decrease the font size.',
43440 cls: 'x-html-editor-tip'
43443 title: 'Text Highlight Color',
43444 text: 'Change the background color of the selected text.',
43445 cls: 'x-html-editor-tip'
43448 title: 'Font Color',
43449 text: 'Change the color of the selected text.',
43450 cls: 'x-html-editor-tip'
43453 title: 'Align Text Left',
43454 text: 'Align text to the left.',
43455 cls: 'x-html-editor-tip'
43458 title: 'Center Text',
43459 text: 'Center text in the editor.',
43460 cls: 'x-html-editor-tip'
43463 title: 'Align Text Right',
43464 text: 'Align text to the right.',
43465 cls: 'x-html-editor-tip'
43467 insertunorderedlist : {
43468 title: 'Bullet List',
43469 text: 'Start a bulleted list.',
43470 cls: 'x-html-editor-tip'
43472 insertorderedlist : {
43473 title: 'Numbered List',
43474 text: 'Start a numbered list.',
43475 cls: 'x-html-editor-tip'
43478 title: 'Hyperlink',
43479 text: 'Make the selected text a hyperlink.',
43480 cls: 'x-html-editor-tip'
43483 title: 'Source Edit',
43484 text: 'Switch to source editing mode.',
43485 cls: 'x-html-editor-tip'
43489 onDestroy : function(){
43492 this.tb.items.each(function(item){
43494 item.menu.removeAll();
43496 item.menu.el.destroy();
43504 onFirstFocus: function() {
43505 this.tb.items.each(function(item){
43514 // <script type="text/javascript">
43517 * Ext JS Library 1.1.1
43518 * Copyright(c) 2006-2007, Ext JS, LLC.
43525 * @class Roo.form.HtmlEditor.ToolbarContext
43530 new Roo.form.HtmlEditor({
43533 { xtype: 'ToolbarStandard', styles : {} }
43534 { xtype: 'ToolbarContext', disable : {} }
43540 * @config : {Object} disable List of elements to disable.. (not done yet.)
43541 * @config : {Object} styles Map of styles available.
43545 Roo.form.HtmlEditor.ToolbarContext = function(config)
43548 Roo.apply(this, config);
43549 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43550 // dont call parent... till later.
43551 this.styles = this.styles || {};
43556 Roo.form.HtmlEditor.ToolbarContext.types = {
43568 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
43634 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
43639 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
43649 style : 'fontFamily',
43650 displayField: 'display',
43651 optname : 'font-family',
43700 // should we really allow this??
43701 // should this just be
43712 style : 'fontFamily',
43713 displayField: 'display',
43714 optname : 'font-family',
43721 style : 'fontFamily',
43722 displayField: 'display',
43723 optname : 'font-family',
43730 style : 'fontFamily',
43731 displayField: 'display',
43732 optname : 'font-family',
43743 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
43744 Roo.form.HtmlEditor.ToolbarContext.stores = false;
43746 Roo.form.HtmlEditor.ToolbarContext.options = {
43748 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
43749 [ 'Courier New', 'Courier New'],
43750 [ 'Tahoma', 'Tahoma'],
43751 [ 'Times New Roman,serif', 'Times'],
43752 [ 'Verdana','Verdana' ]
43756 // fixme - these need to be configurable..
43759 Roo.form.HtmlEditor.ToolbarContext.types
43762 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
43769 editorcore : false,
43771 * @cfg {Object} disable List of toolbar elements to disable
43776 * @cfg {Object} styles List of styles
43777 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
43779 * These must be defined in the page, so they get rendered correctly..
43790 init : function(editor)
43792 this.editor = editor;
43793 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43794 var editorcore = this.editorcore;
43796 var fid = editorcore.frameId;
43798 function btn(id, toggle, handler){
43799 var xid = fid + '-'+ id ;
43803 cls : 'x-btn-icon x-edit-'+id,
43804 enableToggle:toggle !== false,
43805 scope: editorcore, // was editor...
43806 handler:handler||editorcore.relayBtnCmd,
43807 clickEvent:'mousedown',
43808 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43812 // create a new element.
43813 var wdiv = editor.wrap.createChild({
43815 }, editor.wrap.dom.firstChild.nextSibling, true);
43817 // can we do this more than once??
43819 // stop form submits
43822 // disable everything...
43823 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43824 this.toolbars = {};
43826 for (var i in ty) {
43828 this.toolbars[i] = this.buildToolbar(ty[i],i);
43830 this.tb = this.toolbars.BODY;
43832 this.buildFooter();
43833 this.footer.show();
43834 editor.on('hide', function( ) { this.footer.hide() }, this);
43835 editor.on('show', function( ) { this.footer.show() }, this);
43838 this.rendered = true;
43840 // the all the btns;
43841 editor.on('editorevent', this.updateToolbar, this);
43842 // other toolbars need to implement this..
43843 //editor.on('editmodechange', this.updateToolbar, this);
43849 * Protected method that will not generally be called directly. It triggers
43850 * a toolbar update by reading the markup state of the current selection in the editor.
43852 updateToolbar: function(editor,ev,sel){
43855 // capture mouse up - this is handy for selecting images..
43856 // perhaps should go somewhere else...
43857 if(!this.editorcore.activated){
43858 this.editor.onFirstFocus();
43862 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
43863 // selectNode - might want to handle IE?
43865 (ev.type == 'mouseup' || ev.type == 'click' ) &&
43866 ev.target && ev.target.tagName == 'IMG') {
43867 // they have click on an image...
43868 // let's see if we can change the selection...
43871 var nodeRange = sel.ownerDocument.createRange();
43873 nodeRange.selectNode(sel);
43875 nodeRange.selectNodeContents(sel);
43877 //nodeRange.collapse(true);
43878 var s = this.editorcore.win.getSelection();
43879 s.removeAllRanges();
43880 s.addRange(nodeRange);
43884 var updateFooter = sel ? false : true;
43887 var ans = this.editorcore.getAllAncestors();
43890 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
43893 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
43894 sel = sel ? sel : this.editorcore.doc.body;
43895 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
43898 // pick a menu that exists..
43899 var tn = sel.tagName.toUpperCase();
43900 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
43902 tn = sel.tagName.toUpperCase();
43904 var lastSel = this.tb.selectedNode
43906 this.tb.selectedNode = sel;
43908 // if current menu does not match..
43909 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
43912 ///console.log("show: " + tn);
43913 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
43916 this.tb.items.first().el.innerHTML = tn + ': ';
43919 // update attributes
43920 if (this.tb.fields) {
43921 this.tb.fields.each(function(e) {
43923 e.setValue(sel.style[e.stylename]);
43926 e.setValue(sel.getAttribute(e.attrname));
43930 var hasStyles = false;
43931 for(var i in this.styles) {
43938 var st = this.tb.fields.item(0);
43940 st.store.removeAll();
43943 var cn = sel.className.split(/\s+/);
43946 if (this.styles['*']) {
43948 Roo.each(this.styles['*'], function(v) {
43949 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43952 if (this.styles[tn]) {
43953 Roo.each(this.styles[tn], function(v) {
43954 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
43958 st.store.loadData(avs);
43962 // flag our selected Node.
43963 this.tb.selectedNode = sel;
43966 Roo.menu.MenuMgr.hideAll();
43970 if (!updateFooter) {
43971 //this.footDisp.dom.innerHTML = '';
43974 // update the footer
43978 this.footerEls = ans.reverse();
43979 Roo.each(this.footerEls, function(a,i) {
43980 if (!a) { return; }
43981 html += html.length ? ' > ' : '';
43983 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
43988 var sz = this.footDisp.up('td').getSize();
43989 this.footDisp.dom.style.width = (sz.width -10) + 'px';
43990 this.footDisp.dom.style.marginLeft = '5px';
43992 this.footDisp.dom.style.overflow = 'hidden';
43994 this.footDisp.dom.innerHTML = html;
43996 //this.editorsyncValue();
44003 onDestroy : function(){
44006 this.tb.items.each(function(item){
44008 item.menu.removeAll();
44010 item.menu.el.destroy();
44018 onFirstFocus: function() {
44019 // need to do this for all the toolbars..
44020 this.tb.items.each(function(item){
44024 buildToolbar: function(tlist, nm)
44026 var editor = this.editor;
44027 var editorcore = this.editorcore;
44028 // create a new element.
44029 var wdiv = editor.wrap.createChild({
44031 }, editor.wrap.dom.firstChild.nextSibling, true);
44034 var tb = new Roo.Toolbar(wdiv);
44037 tb.add(nm+ ": ");
44040 for(var i in this.styles) {
44045 if (styles && styles.length) {
44047 // this needs a multi-select checkbox...
44048 tb.addField( new Roo.form.ComboBox({
44049 store: new Roo.data.SimpleStore({
44051 fields: ['val', 'selected'],
44054 name : '-roo-edit-className',
44055 attrname : 'className',
44056 displayField: 'val',
44060 triggerAction: 'all',
44061 emptyText:'Select Style',
44062 selectOnFocus:true,
44065 'select': function(c, r, i) {
44066 // initial support only for on class per el..
44067 tb.selectedNode.className = r ? r.get('val') : '';
44068 editorcore.syncValue();
44075 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44076 var tbops = tbc.options;
44078 for (var i in tlist) {
44080 var item = tlist[i];
44081 tb.add(item.title + ": ");
44084 //optname == used so you can configure the options available..
44085 var opts = item.opts ? item.opts : false;
44086 if (item.optname) {
44087 opts = tbops[item.optname];
44092 // opts == pulldown..
44093 tb.addField( new Roo.form.ComboBox({
44094 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44096 fields: ['val', 'display'],
44099 name : '-roo-edit-' + i,
44101 stylename : item.style ? item.style : false,
44102 displayField: item.displayField ? item.displayField : 'val',
44103 valueField : 'val',
44105 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44107 triggerAction: 'all',
44108 emptyText:'Select',
44109 selectOnFocus:true,
44110 width: item.width ? item.width : 130,
44112 'select': function(c, r, i) {
44114 tb.selectedNode.style[c.stylename] = r.get('val');
44117 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44126 tb.addField( new Roo.form.TextField({
44129 //allowBlank:false,
44134 tb.addField( new Roo.form.TextField({
44135 name: '-roo-edit-' + i,
44142 'change' : function(f, nv, ov) {
44143 tb.selectedNode.setAttribute(f.attrname, nv);
44152 text: 'Remove Tag',
44155 click : function ()
44158 // undo does not work.
44160 var sn = tb.selectedNode;
44162 var pn = sn.parentNode;
44164 var stn = sn.childNodes[0];
44165 var en = sn.childNodes[sn.childNodes.length - 1 ];
44166 while (sn.childNodes.length) {
44167 var node = sn.childNodes[0];
44168 sn.removeChild(node);
44170 pn.insertBefore(node, sn);
44173 pn.removeChild(sn);
44174 var range = editorcore.createRange();
44176 range.setStart(stn,0);
44177 range.setEnd(en,0); //????
44178 //range.selectNode(sel);
44181 var selection = editorcore.getSelection();
44182 selection.removeAllRanges();
44183 selection.addRange(range);
44187 //_this.updateToolbar(null, null, pn);
44188 _this.updateToolbar(null, null, null);
44189 _this.footDisp.dom.innerHTML = '';
44199 tb.el.on('click', function(e){
44200 e.preventDefault(); // what does this do?
44202 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44205 // dont need to disable them... as they will get hidden
44210 buildFooter : function()
44213 var fel = this.editor.wrap.createChild();
44214 this.footer = new Roo.Toolbar(fel);
44215 // toolbar has scrolly on left / right?
44216 var footDisp= new Roo.Toolbar.Fill();
44222 handler : function() {
44223 _t.footDisp.scrollTo('left',0,true)
44227 this.footer.add( footDisp );
44232 handler : function() {
44234 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44238 var fel = Roo.get(footDisp.el);
44239 fel.addClass('x-editor-context');
44240 this.footDispWrap = fel;
44241 this.footDispWrap.overflow = 'hidden';
44243 this.footDisp = fel.createChild();
44244 this.footDispWrap.on('click', this.onContextClick, this)
44248 onContextClick : function (ev,dom)
44250 ev.preventDefault();
44251 var cn = dom.className;
44253 if (!cn.match(/x-ed-loc-/)) {
44256 var n = cn.split('-').pop();
44257 var ans = this.footerEls;
44261 var range = this.editorcore.createRange();
44263 range.selectNodeContents(sel);
44264 //range.selectNode(sel);
44267 var selection = this.editorcore.getSelection();
44268 selection.removeAllRanges();
44269 selection.addRange(range);
44273 this.updateToolbar(null, null, sel);
44290 * Ext JS Library 1.1.1
44291 * Copyright(c) 2006-2007, Ext JS, LLC.
44293 * Originally Released Under LGPL - original licence link has changed is not relivant.
44296 * <script type="text/javascript">
44300 * @class Roo.form.BasicForm
44301 * @extends Roo.util.Observable
44302 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44304 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44305 * @param {Object} config Configuration options
44307 Roo.form.BasicForm = function(el, config){
44308 this.allItems = [];
44309 this.childForms = [];
44310 Roo.apply(this, config);
44312 * The Roo.form.Field items in this form.
44313 * @type MixedCollection
44317 this.items = new Roo.util.MixedCollection(false, function(o){
44318 return o.id || (o.id = Roo.id());
44322 * @event beforeaction
44323 * Fires before any action is performed. Return false to cancel the action.
44324 * @param {Form} this
44325 * @param {Action} action The action to be performed
44327 beforeaction: true,
44329 * @event actionfailed
44330 * Fires when an action fails.
44331 * @param {Form} this
44332 * @param {Action} action The action that failed
44334 actionfailed : true,
44336 * @event actioncomplete
44337 * Fires when an action is completed.
44338 * @param {Form} this
44339 * @param {Action} action The action that completed
44341 actioncomplete : true
44346 Roo.form.BasicForm.superclass.constructor.call(this);
44349 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44351 * @cfg {String} method
44352 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44355 * @cfg {DataReader} reader
44356 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44357 * This is optional as there is built-in support for processing JSON.
44360 * @cfg {DataReader} errorReader
44361 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44362 * This is completely optional as there is built-in support for processing JSON.
44365 * @cfg {String} url
44366 * The URL to use for form actions if one isn't supplied in the action options.
44369 * @cfg {Boolean} fileUpload
44370 * Set to true if this form is a file upload.
44374 * @cfg {Object} baseParams
44375 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44380 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44385 activeAction : null,
44388 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44389 * or setValues() data instead of when the form was first created.
44391 trackResetOnLoad : false,
44395 * childForms - used for multi-tab forms
44398 childForms : false,
44401 * allItems - full list of fields.
44407 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44408 * element by passing it or its id or mask the form itself by passing in true.
44411 waitMsgTarget : false,
44414 initEl : function(el){
44415 this.el = Roo.get(el);
44416 this.id = this.el.id || Roo.id();
44417 this.el.on('submit', this.onSubmit, this);
44418 this.el.addClass('x-form');
44422 onSubmit : function(e){
44427 * Returns true if client-side validation on the form is successful.
44430 isValid : function(){
44432 this.items.each(function(f){
44441 * Returns true if any fields in this form have changed since their original load.
44444 isDirty : function(){
44446 this.items.each(function(f){
44456 * Performs a predefined action (submit or load) or custom actions you define on this form.
44457 * @param {String} actionName The name of the action type
44458 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
44459 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
44460 * accept other config options):
44462 Property Type Description
44463 ---------------- --------------- ----------------------------------------------------------------------------------
44464 url String The url for the action (defaults to the form's url)
44465 method String The form method to use (defaults to the form's method, or POST if not defined)
44466 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
44467 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
44468 validate the form on the client (defaults to false)
44470 * @return {BasicForm} this
44472 doAction : function(action, options){
44473 if(typeof action == 'string'){
44474 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
44476 if(this.fireEvent('beforeaction', this, action) !== false){
44477 this.beforeAction(action);
44478 action.run.defer(100, action);
44484 * Shortcut to do a submit action.
44485 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44486 * @return {BasicForm} this
44488 submit : function(options){
44489 this.doAction('submit', options);
44494 * Shortcut to do a load action.
44495 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
44496 * @return {BasicForm} this
44498 load : function(options){
44499 this.doAction('load', options);
44504 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
44505 * @param {Record} record The record to edit
44506 * @return {BasicForm} this
44508 updateRecord : function(record){
44509 record.beginEdit();
44510 var fs = record.fields;
44511 fs.each(function(f){
44512 var field = this.findField(f.name);
44514 record.set(f.name, field.getValue());
44522 * Loads an Roo.data.Record into this form.
44523 * @param {Record} record The record to load
44524 * @return {BasicForm} this
44526 loadRecord : function(record){
44527 this.setValues(record.data);
44532 beforeAction : function(action){
44533 var o = action.options;
44536 if(this.waitMsgTarget === true){
44537 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
44538 }else if(this.waitMsgTarget){
44539 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
44540 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
44542 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
44548 afterAction : function(action, success){
44549 this.activeAction = null;
44550 var o = action.options;
44552 if(this.waitMsgTarget === true){
44554 }else if(this.waitMsgTarget){
44555 this.waitMsgTarget.unmask();
44557 Roo.MessageBox.updateProgress(1);
44558 Roo.MessageBox.hide();
44565 Roo.callback(o.success, o.scope, [this, action]);
44566 this.fireEvent('actioncomplete', this, action);
44570 // failure condition..
44571 // we have a scenario where updates need confirming.
44572 // eg. if a locking scenario exists..
44573 // we look for { errors : { needs_confirm : true }} in the response.
44575 (typeof(action.result) != 'undefined') &&
44576 (typeof(action.result.errors) != 'undefined') &&
44577 (typeof(action.result.errors.needs_confirm) != 'undefined')
44580 Roo.MessageBox.confirm(
44581 "Change requires confirmation",
44582 action.result.errorMsg,
44587 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
44597 Roo.callback(o.failure, o.scope, [this, action]);
44598 // show an error message if no failed handler is set..
44599 if (!this.hasListener('actionfailed')) {
44600 Roo.MessageBox.alert("Error",
44601 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
44602 action.result.errorMsg :
44603 "Saving Failed, please check your entries or try again"
44607 this.fireEvent('actionfailed', this, action);
44613 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
44614 * @param {String} id The value to search for
44617 findField : function(id){
44618 var field = this.items.get(id);
44620 this.items.each(function(f){
44621 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
44627 return field || null;
44631 * Add a secondary form to this one,
44632 * Used to provide tabbed forms. One form is primary, with hidden values
44633 * which mirror the elements from the other forms.
44635 * @param {Roo.form.Form} form to add.
44638 addForm : function(form)
44641 if (this.childForms.indexOf(form) > -1) {
44645 this.childForms.push(form);
44647 Roo.each(form.allItems, function (fe) {
44649 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
44650 if (this.findField(n)) { // already added..
44653 var add = new Roo.form.Hidden({
44656 add.render(this.el);
44663 * Mark fields in this form invalid in bulk.
44664 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
44665 * @return {BasicForm} this
44667 markInvalid : function(errors){
44668 if(errors instanceof Array){
44669 for(var i = 0, len = errors.length; i < len; i++){
44670 var fieldError = errors[i];
44671 var f = this.findField(fieldError.id);
44673 f.markInvalid(fieldError.msg);
44679 if(typeof errors[id] != 'function' && (field = this.findField(id))){
44680 field.markInvalid(errors[id]);
44684 Roo.each(this.childForms || [], function (f) {
44685 f.markInvalid(errors);
44692 * Set values for fields in this form in bulk.
44693 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
44694 * @return {BasicForm} this
44696 setValues : function(values){
44697 if(values instanceof Array){ // array of objects
44698 for(var i = 0, len = values.length; i < len; i++){
44700 var f = this.findField(v.id);
44702 f.setValue(v.value);
44703 if(this.trackResetOnLoad){
44704 f.originalValue = f.getValue();
44708 }else{ // object hash
44711 if(typeof values[id] != 'function' && (field = this.findField(id))){
44713 if (field.setFromData &&
44714 field.valueField &&
44715 field.displayField &&
44716 // combos' with local stores can
44717 // be queried via setValue()
44718 // to set their value..
44719 (field.store && !field.store.isLocal)
44723 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
44724 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
44725 field.setFromData(sd);
44728 field.setValue(values[id]);
44732 if(this.trackResetOnLoad){
44733 field.originalValue = field.getValue();
44739 Roo.each(this.childForms || [], function (f) {
44740 f.setValues(values);
44747 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
44748 * they are returned as an array.
44749 * @param {Boolean} asString
44752 getValues : function(asString){
44753 if (this.childForms) {
44754 // copy values from the child forms
44755 Roo.each(this.childForms, function (f) {
44756 this.setValues(f.getValues());
44762 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
44763 if(asString === true){
44766 return Roo.urlDecode(fs);
44770 * Returns the fields in this form as an object with key/value pairs.
44771 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
44774 getFieldValues : function(with_hidden)
44776 if (this.childForms) {
44777 // copy values from the child forms
44778 // should this call getFieldValues - probably not as we do not currently copy
44779 // hidden fields when we generate..
44780 Roo.each(this.childForms, function (f) {
44781 this.setValues(f.getValues());
44786 this.items.each(function(f){
44787 if (!f.getName()) {
44790 var v = f.getValue();
44791 if (f.inputType =='radio') {
44792 if (typeof(ret[f.getName()]) == 'undefined') {
44793 ret[f.getName()] = ''; // empty..
44796 if (!f.el.dom.checked) {
44800 v = f.el.dom.value;
44804 // not sure if this supported any more..
44805 if ((typeof(v) == 'object') && f.getRawValue) {
44806 v = f.getRawValue() ; // dates..
44808 // combo boxes where name != hiddenName...
44809 if (f.name != f.getName()) {
44810 ret[f.name] = f.getRawValue();
44812 ret[f.getName()] = v;
44819 * Clears all invalid messages in this form.
44820 * @return {BasicForm} this
44822 clearInvalid : function(){
44823 this.items.each(function(f){
44827 Roo.each(this.childForms || [], function (f) {
44836 * Resets this form.
44837 * @return {BasicForm} this
44839 reset : function(){
44840 this.items.each(function(f){
44844 Roo.each(this.childForms || [], function (f) {
44853 * Add Roo.form components to this form.
44854 * @param {Field} field1
44855 * @param {Field} field2 (optional)
44856 * @param {Field} etc (optional)
44857 * @return {BasicForm} this
44860 this.items.addAll(Array.prototype.slice.call(arguments, 0));
44866 * Removes a field from the items collection (does NOT remove its markup).
44867 * @param {Field} field
44868 * @return {BasicForm} this
44870 remove : function(field){
44871 this.items.remove(field);
44876 * Looks at the fields in this form, checks them for an id attribute,
44877 * and calls applyTo on the existing dom element with that id.
44878 * @return {BasicForm} this
44880 render : function(){
44881 this.items.each(function(f){
44882 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
44890 * Calls {@link Ext#apply} for all fields in this form with the passed object.
44891 * @param {Object} values
44892 * @return {BasicForm} this
44894 applyToFields : function(o){
44895 this.items.each(function(f){
44902 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
44903 * @param {Object} values
44904 * @return {BasicForm} this
44906 applyIfToFields : function(o){
44907 this.items.each(function(f){
44915 Roo.BasicForm = Roo.form.BasicForm;/*
44917 * Ext JS Library 1.1.1
44918 * Copyright(c) 2006-2007, Ext JS, LLC.
44920 * Originally Released Under LGPL - original licence link has changed is not relivant.
44923 * <script type="text/javascript">
44927 * @class Roo.form.Form
44928 * @extends Roo.form.BasicForm
44929 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
44931 * @param {Object} config Configuration options
44933 Roo.form.Form = function(config){
44935 if (config.items) {
44936 xitems = config.items;
44937 delete config.items;
44941 Roo.form.Form.superclass.constructor.call(this, null, config);
44942 this.url = this.url || this.action;
44944 this.root = new Roo.form.Layout(Roo.applyIf({
44948 this.active = this.root;
44950 * Array of all the buttons that have been added to this form via {@link addButton}
44954 this.allItems = [];
44957 * @event clientvalidation
44958 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
44959 * @param {Form} this
44960 * @param {Boolean} valid true if the form has passed client-side validation
44962 clientvalidation: true,
44965 * Fires when the form is rendered
44966 * @param {Roo.form.Form} form
44971 if (this.progressUrl) {
44972 // push a hidden field onto the list of fields..
44976 name : 'UPLOAD_IDENTIFIER'
44981 Roo.each(xitems, this.addxtype, this);
44987 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
44989 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
44992 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
44995 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
44997 buttonAlign:'center',
45000 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45005 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45006 * This property cascades to child containers if not set.
45011 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45012 * fires a looping event with that state. This is required to bind buttons to the valid
45013 * state using the config value formBind:true on the button.
45015 monitorValid : false,
45018 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45023 * @cfg {String} progressUrl - Url to return progress data
45026 progressUrl : false,
45029 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45030 * fields are added and the column is closed. If no fields are passed the column remains open
45031 * until end() is called.
45032 * @param {Object} config The config to pass to the column
45033 * @param {Field} field1 (optional)
45034 * @param {Field} field2 (optional)
45035 * @param {Field} etc (optional)
45036 * @return Column The column container object
45038 column : function(c){
45039 var col = new Roo.form.Column(c);
45041 if(arguments.length > 1){ // duplicate code required because of Opera
45042 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45049 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45050 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45051 * until end() is called.
45052 * @param {Object} config The config to pass to the fieldset
45053 * @param {Field} field1 (optional)
45054 * @param {Field} field2 (optional)
45055 * @param {Field} etc (optional)
45056 * @return FieldSet The fieldset container object
45058 fieldset : function(c){
45059 var fs = new Roo.form.FieldSet(c);
45061 if(arguments.length > 1){ // duplicate code required because of Opera
45062 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45069 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45070 * fields are added and the container is closed. If no fields are passed the container remains open
45071 * until end() is called.
45072 * @param {Object} config The config to pass to the Layout
45073 * @param {Field} field1 (optional)
45074 * @param {Field} field2 (optional)
45075 * @param {Field} etc (optional)
45076 * @return Layout The container object
45078 container : function(c){
45079 var l = new Roo.form.Layout(c);
45081 if(arguments.length > 1){ // duplicate code required because of Opera
45082 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45089 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45090 * @param {Object} container A Roo.form.Layout or subclass of Layout
45091 * @return {Form} this
45093 start : function(c){
45094 // cascade label info
45095 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45096 this.active.stack.push(c);
45097 c.ownerCt = this.active;
45103 * Closes the current open container
45104 * @return {Form} this
45107 if(this.active == this.root){
45110 this.active = this.active.ownerCt;
45115 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45116 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45117 * as the label of the field.
45118 * @param {Field} field1
45119 * @param {Field} field2 (optional)
45120 * @param {Field} etc. (optional)
45121 * @return {Form} this
45124 this.active.stack.push.apply(this.active.stack, arguments);
45125 this.allItems.push.apply(this.allItems,arguments);
45127 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45128 if(a[i].isFormField){
45133 Roo.form.Form.superclass.add.apply(this, r);
45143 * Find any element that has been added to a form, using it's ID or name
45144 * This can include framesets, columns etc. along with regular fields..
45145 * @param {String} id - id or name to find.
45147 * @return {Element} e - or false if nothing found.
45149 findbyId : function(id)
45155 Roo.each(this.allItems, function(f){
45156 if (f.id == id || f.name == id ){
45167 * Render this form into the passed container. This should only be called once!
45168 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45169 * @return {Form} this
45171 render : function(ct)
45177 var o = this.autoCreate || {
45179 method : this.method || 'POST',
45180 id : this.id || Roo.id()
45182 this.initEl(ct.createChild(o));
45184 this.root.render(this.el);
45188 this.items.each(function(f){
45189 f.render('x-form-el-'+f.id);
45192 if(this.buttons.length > 0){
45193 // tables are required to maintain order and for correct IE layout
45194 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45195 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45196 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45198 var tr = tb.getElementsByTagName('tr')[0];
45199 for(var i = 0, len = this.buttons.length; i < len; i++) {
45200 var b = this.buttons[i];
45201 var td = document.createElement('td');
45202 td.className = 'x-form-btn-td';
45203 b.render(tr.appendChild(td));
45206 if(this.monitorValid){ // initialize after render
45207 this.startMonitoring();
45209 this.fireEvent('rendered', this);
45214 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45215 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45216 * object or a valid Roo.DomHelper element config
45217 * @param {Function} handler The function called when the button is clicked
45218 * @param {Object} scope (optional) The scope of the handler function
45219 * @return {Roo.Button}
45221 addButton : function(config, handler, scope){
45225 minWidth: this.minButtonWidth,
45228 if(typeof config == "string"){
45231 Roo.apply(bc, config);
45233 var btn = new Roo.Button(null, bc);
45234 this.buttons.push(btn);
45239 * Adds a series of form elements (using the xtype property as the factory method.
45240 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45241 * @param {Object} config
45244 addxtype : function()
45246 var ar = Array.prototype.slice.call(arguments, 0);
45248 for(var i = 0; i < ar.length; i++) {
45250 continue; // skip -- if this happends something invalid got sent, we
45251 // should ignore it, as basically that interface element will not show up
45252 // and that should be pretty obvious!!
45255 if (Roo.form[ar[i].xtype]) {
45257 var fe = Roo.factory(ar[i], Roo.form);
45263 fe.store.form = this;
45268 this.allItems.push(fe);
45269 if (fe.items && fe.addxtype) {
45270 fe.addxtype.apply(fe, fe.items);
45280 // console.log('adding ' + ar[i].xtype);
45282 if (ar[i].xtype == 'Button') {
45283 //console.log('adding button');
45284 //console.log(ar[i]);
45285 this.addButton(ar[i]);
45286 this.allItems.push(fe);
45290 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45291 alert('end is not supported on xtype any more, use items');
45293 // //console.log('adding end');
45301 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45302 * option "monitorValid"
45304 startMonitoring : function(){
45307 Roo.TaskMgr.start({
45308 run : this.bindHandler,
45309 interval : this.monitorPoll || 200,
45316 * Stops monitoring of the valid state of this form
45318 stopMonitoring : function(){
45319 this.bound = false;
45323 bindHandler : function(){
45325 return false; // stops binding
45328 this.items.each(function(f){
45329 if(!f.isValid(true)){
45334 for(var i = 0, len = this.buttons.length; i < len; i++){
45335 var btn = this.buttons[i];
45336 if(btn.formBind === true && btn.disabled === valid){
45337 btn.setDisabled(!valid);
45340 this.fireEvent('clientvalidation', this, valid);
45354 Roo.Form = Roo.form.Form;
45357 * Ext JS Library 1.1.1
45358 * Copyright(c) 2006-2007, Ext JS, LLC.
45360 * Originally Released Under LGPL - original licence link has changed is not relivant.
45363 * <script type="text/javascript">
45366 // as we use this in bootstrap.
45367 Roo.namespace('Roo.form');
45369 * @class Roo.form.Action
45370 * Internal Class used to handle form actions
45372 * @param {Roo.form.BasicForm} el The form element or its id
45373 * @param {Object} config Configuration options
45378 // define the action interface
45379 Roo.form.Action = function(form, options){
45381 this.options = options || {};
45384 * Client Validation Failed
45387 Roo.form.Action.CLIENT_INVALID = 'client';
45389 * Server Validation Failed
45392 Roo.form.Action.SERVER_INVALID = 'server';
45394 * Connect to Server Failed
45397 Roo.form.Action.CONNECT_FAILURE = 'connect';
45399 * Reading Data from Server Failed
45402 Roo.form.Action.LOAD_FAILURE = 'load';
45404 Roo.form.Action.prototype = {
45406 failureType : undefined,
45407 response : undefined,
45408 result : undefined,
45410 // interface method
45411 run : function(options){
45415 // interface method
45416 success : function(response){
45420 // interface method
45421 handleResponse : function(response){
45425 // default connection failure
45426 failure : function(response){
45428 this.response = response;
45429 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45430 this.form.afterAction(this, false);
45433 processResponse : function(response){
45434 this.response = response;
45435 if(!response.responseText){
45438 this.result = this.handleResponse(response);
45439 return this.result;
45442 // utility functions used internally
45443 getUrl : function(appendParams){
45444 var url = this.options.url || this.form.url || this.form.el.dom.action;
45446 var p = this.getParams();
45448 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
45454 getMethod : function(){
45455 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
45458 getParams : function(){
45459 var bp = this.form.baseParams;
45460 var p = this.options.params;
45462 if(typeof p == "object"){
45463 p = Roo.urlEncode(Roo.applyIf(p, bp));
45464 }else if(typeof p == 'string' && bp){
45465 p += '&' + Roo.urlEncode(bp);
45468 p = Roo.urlEncode(bp);
45473 createCallback : function(){
45475 success: this.success,
45476 failure: this.failure,
45478 timeout: (this.form.timeout*1000),
45479 upload: this.form.fileUpload ? this.success : undefined
45484 Roo.form.Action.Submit = function(form, options){
45485 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
45488 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
45491 haveProgress : false,
45492 uploadComplete : false,
45494 // uploadProgress indicator.
45495 uploadProgress : function()
45497 if (!this.form.progressUrl) {
45501 if (!this.haveProgress) {
45502 Roo.MessageBox.progress("Uploading", "Uploading");
45504 if (this.uploadComplete) {
45505 Roo.MessageBox.hide();
45509 this.haveProgress = true;
45511 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
45513 var c = new Roo.data.Connection();
45515 url : this.form.progressUrl,
45520 success : function(req){
45521 //console.log(data);
45525 rdata = Roo.decode(req.responseText)
45527 Roo.log("Invalid data from server..");
45531 if (!rdata || !rdata.success) {
45533 Roo.MessageBox.alert(Roo.encode(rdata));
45536 var data = rdata.data;
45538 if (this.uploadComplete) {
45539 Roo.MessageBox.hide();
45544 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
45545 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
45548 this.uploadProgress.defer(2000,this);
45551 failure: function(data) {
45552 Roo.log('progress url failed ');
45563 // run get Values on the form, so it syncs any secondary forms.
45564 this.form.getValues();
45566 var o = this.options;
45567 var method = this.getMethod();
45568 var isPost = method == 'POST';
45569 if(o.clientValidation === false || this.form.isValid()){
45571 if (this.form.progressUrl) {
45572 this.form.findField('UPLOAD_IDENTIFIER').setValue(
45573 (new Date() * 1) + '' + Math.random());
45578 Roo.Ajax.request(Roo.apply(this.createCallback(), {
45579 form:this.form.el.dom,
45580 url:this.getUrl(!isPost),
45582 params:isPost ? this.getParams() : null,
45583 isUpload: this.form.fileUpload
45586 this.uploadProgress();
45588 }else if (o.clientValidation !== false){ // client validation failed
45589 this.failureType = Roo.form.Action.CLIENT_INVALID;
45590 this.form.afterAction(this, false);
45594 success : function(response)
45596 this.uploadComplete= true;
45597 if (this.haveProgress) {
45598 Roo.MessageBox.hide();
45602 var result = this.processResponse(response);
45603 if(result === true || result.success){
45604 this.form.afterAction(this, true);
45608 this.form.markInvalid(result.errors);
45609 this.failureType = Roo.form.Action.SERVER_INVALID;
45611 this.form.afterAction(this, false);
45613 failure : function(response)
45615 this.uploadComplete= true;
45616 if (this.haveProgress) {
45617 Roo.MessageBox.hide();
45620 this.response = response;
45621 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45622 this.form.afterAction(this, false);
45625 handleResponse : function(response){
45626 if(this.form.errorReader){
45627 var rs = this.form.errorReader.read(response);
45630 for(var i = 0, len = rs.records.length; i < len; i++) {
45631 var r = rs.records[i];
45632 errors[i] = r.data;
45635 if(errors.length < 1){
45639 success : rs.success,
45645 ret = Roo.decode(response.responseText);
45649 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
45659 Roo.form.Action.Load = function(form, options){
45660 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
45661 this.reader = this.form.reader;
45664 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
45669 Roo.Ajax.request(Roo.apply(
45670 this.createCallback(), {
45671 method:this.getMethod(),
45672 url:this.getUrl(false),
45673 params:this.getParams()
45677 success : function(response){
45679 var result = this.processResponse(response);
45680 if(result === true || !result.success || !result.data){
45681 this.failureType = Roo.form.Action.LOAD_FAILURE;
45682 this.form.afterAction(this, false);
45685 this.form.clearInvalid();
45686 this.form.setValues(result.data);
45687 this.form.afterAction(this, true);
45690 handleResponse : function(response){
45691 if(this.form.reader){
45692 var rs = this.form.reader.read(response);
45693 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
45695 success : rs.success,
45699 return Roo.decode(response.responseText);
45703 Roo.form.Action.ACTION_TYPES = {
45704 'load' : Roo.form.Action.Load,
45705 'submit' : Roo.form.Action.Submit
45708 * Ext JS Library 1.1.1
45709 * Copyright(c) 2006-2007, Ext JS, LLC.
45711 * Originally Released Under LGPL - original licence link has changed is not relivant.
45714 * <script type="text/javascript">
45718 * @class Roo.form.Layout
45719 * @extends Roo.Component
45720 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
45722 * @param {Object} config Configuration options
45724 Roo.form.Layout = function(config){
45726 if (config.items) {
45727 xitems = config.items;
45728 delete config.items;
45730 Roo.form.Layout.superclass.constructor.call(this, config);
45732 Roo.each(xitems, this.addxtype, this);
45736 Roo.extend(Roo.form.Layout, Roo.Component, {
45738 * @cfg {String/Object} autoCreate
45739 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
45742 * @cfg {String/Object/Function} style
45743 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
45744 * a function which returns such a specification.
45747 * @cfg {String} labelAlign
45748 * Valid values are "left," "top" and "right" (defaults to "left")
45751 * @cfg {Number} labelWidth
45752 * Fixed width in pixels of all field labels (defaults to undefined)
45755 * @cfg {Boolean} clear
45756 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
45760 * @cfg {String} labelSeparator
45761 * The separator to use after field labels (defaults to ':')
45763 labelSeparator : ':',
45765 * @cfg {Boolean} hideLabels
45766 * True to suppress the display of field labels in this layout (defaults to false)
45768 hideLabels : false,
45771 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
45776 onRender : function(ct, position){
45777 if(this.el){ // from markup
45778 this.el = Roo.get(this.el);
45779 }else { // generate
45780 var cfg = this.getAutoCreate();
45781 this.el = ct.createChild(cfg, position);
45784 this.el.applyStyles(this.style);
45786 if(this.labelAlign){
45787 this.el.addClass('x-form-label-'+this.labelAlign);
45789 if(this.hideLabels){
45790 this.labelStyle = "display:none";
45791 this.elementStyle = "padding-left:0;";
45793 if(typeof this.labelWidth == 'number'){
45794 this.labelStyle = "width:"+this.labelWidth+"px;";
45795 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
45797 if(this.labelAlign == 'top'){
45798 this.labelStyle = "width:auto;";
45799 this.elementStyle = "padding-left:0;";
45802 var stack = this.stack;
45803 var slen = stack.length;
45805 if(!this.fieldTpl){
45806 var t = new Roo.Template(
45807 '<div class="x-form-item {5}">',
45808 '<label for="{0}" style="{2}">{1}{4}</label>',
45809 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45811 '</div><div class="x-form-clear-left"></div>'
45813 t.disableFormats = true;
45815 Roo.form.Layout.prototype.fieldTpl = t;
45817 for(var i = 0; i < slen; i++) {
45818 if(stack[i].isFormField){
45819 this.renderField(stack[i]);
45821 this.renderComponent(stack[i]);
45826 this.el.createChild({cls:'x-form-clear'});
45831 renderField : function(f){
45832 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
45835 f.labelStyle||this.labelStyle||'', //2
45836 this.elementStyle||'', //3
45837 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
45838 f.itemCls||this.itemCls||'' //5
45839 ], true).getPrevSibling());
45843 renderComponent : function(c){
45844 c.render(c.isLayout ? this.el : this.el.createChild());
45847 * Adds a object form elements (using the xtype property as the factory method.)
45848 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
45849 * @param {Object} config
45851 addxtype : function(o)
45853 // create the lement.
45854 o.form = this.form;
45855 var fe = Roo.factory(o, Roo.form);
45856 this.form.allItems.push(fe);
45857 this.stack.push(fe);
45859 if (fe.isFormField) {
45860 this.form.items.add(fe);
45868 * @class Roo.form.Column
45869 * @extends Roo.form.Layout
45870 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
45872 * @param {Object} config Configuration options
45874 Roo.form.Column = function(config){
45875 Roo.form.Column.superclass.constructor.call(this, config);
45878 Roo.extend(Roo.form.Column, Roo.form.Layout, {
45880 * @cfg {Number/String} width
45881 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45884 * @cfg {String/Object} autoCreate
45885 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
45889 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
45892 onRender : function(ct, position){
45893 Roo.form.Column.superclass.onRender.call(this, ct, position);
45895 this.el.setWidth(this.width);
45902 * @class Roo.form.Row
45903 * @extends Roo.form.Layout
45904 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
45906 * @param {Object} config Configuration options
45910 Roo.form.Row = function(config){
45911 Roo.form.Row.superclass.constructor.call(this, config);
45914 Roo.extend(Roo.form.Row, Roo.form.Layout, {
45916 * @cfg {Number/String} width
45917 * The fixed width of the column in pixels or CSS value (defaults to "auto")
45920 * @cfg {Number/String} height
45921 * The fixed height of the column in pixels or CSS value (defaults to "auto")
45923 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
45927 onRender : function(ct, position){
45928 //console.log('row render');
45930 var t = new Roo.Template(
45931 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
45932 '<label for="{0}" style="{2}">{1}{4}</label>',
45933 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
45937 t.disableFormats = true;
45939 Roo.form.Layout.prototype.rowTpl = t;
45941 this.fieldTpl = this.rowTpl;
45943 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
45944 var labelWidth = 100;
45946 if ((this.labelAlign != 'top')) {
45947 if (typeof this.labelWidth == 'number') {
45948 labelWidth = this.labelWidth
45950 this.padWidth = 20 + labelWidth;
45954 Roo.form.Column.superclass.onRender.call(this, ct, position);
45956 this.el.setWidth(this.width);
45959 this.el.setHeight(this.height);
45964 renderField : function(f){
45965 f.fieldEl = this.fieldTpl.append(this.el, [
45966 f.id, f.fieldLabel,
45967 f.labelStyle||this.labelStyle||'',
45968 this.elementStyle||'',
45969 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
45970 f.itemCls||this.itemCls||'',
45971 f.width ? f.width + this.padWidth : 160 + this.padWidth
45978 * @class Roo.form.FieldSet
45979 * @extends Roo.form.Layout
45980 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
45982 * @param {Object} config Configuration options
45984 Roo.form.FieldSet = function(config){
45985 Roo.form.FieldSet.superclass.constructor.call(this, config);
45988 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
45990 * @cfg {String} legend
45991 * The text to display as the legend for the FieldSet (defaults to '')
45994 * @cfg {String/Object} autoCreate
45995 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
45999 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46002 onRender : function(ct, position){
46003 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46005 this.setLegend(this.legend);
46010 setLegend : function(text){
46012 this.el.child('legend').update(text);
46017 * Ext JS Library 1.1.1
46018 * Copyright(c) 2006-2007, Ext JS, LLC.
46020 * Originally Released Under LGPL - original licence link has changed is not relivant.
46023 * <script type="text/javascript">
46026 * @class Roo.form.VTypes
46027 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46030 Roo.form.VTypes = function(){
46031 // closure these in so they are only created once.
46032 var alpha = /^[a-zA-Z_]+$/;
46033 var alphanum = /^[a-zA-Z0-9_]+$/;
46034 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46035 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46037 // All these messages and functions are configurable
46040 * The function used to validate email addresses
46041 * @param {String} value The email address
46043 'email' : function(v){
46044 return email.test(v);
46047 * The error text to display when the email validation function returns false
46050 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46052 * The keystroke filter mask to be applied on email input
46055 'emailMask' : /[a-z0-9_\.\-@]/i,
46058 * The function used to validate URLs
46059 * @param {String} value The URL
46061 'url' : function(v){
46062 return url.test(v);
46065 * The error text to display when the url validation function returns false
46068 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46071 * The function used to validate alpha values
46072 * @param {String} value The value
46074 'alpha' : function(v){
46075 return alpha.test(v);
46078 * The error text to display when the alpha validation function returns false
46081 'alphaText' : 'This field should only contain letters and _',
46083 * The keystroke filter mask to be applied on alpha input
46086 'alphaMask' : /[a-z_]/i,
46089 * The function used to validate alphanumeric values
46090 * @param {String} value The value
46092 'alphanum' : function(v){
46093 return alphanum.test(v);
46096 * The error text to display when the alphanumeric validation function returns false
46099 'alphanumText' : 'This field should only contain letters, numbers and _',
46101 * The keystroke filter mask to be applied on alphanumeric input
46104 'alphanumMask' : /[a-z0-9_]/i
46106 }();//<script type="text/javascript">
46109 * @class Roo.form.FCKeditor
46110 * @extends Roo.form.TextArea
46111 * Wrapper around the FCKEditor http://www.fckeditor.net
46113 * Creates a new FCKeditor
46114 * @param {Object} config Configuration options
46116 Roo.form.FCKeditor = function(config){
46117 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46120 * @event editorinit
46121 * Fired when the editor is initialized - you can add extra handlers here..
46122 * @param {FCKeditor} this
46123 * @param {Object} the FCK object.
46130 Roo.form.FCKeditor.editors = { };
46131 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46133 //defaultAutoCreate : {
46134 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46138 * @cfg {Object} fck options - see fck manual for details.
46143 * @cfg {Object} fck toolbar set (Basic or Default)
46145 toolbarSet : 'Basic',
46147 * @cfg {Object} fck BasePath
46149 basePath : '/fckeditor/',
46157 onRender : function(ct, position)
46160 this.defaultAutoCreate = {
46162 style:"width:300px;height:60px;",
46163 autocomplete: "off"
46166 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46169 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46170 if(this.preventScrollbars){
46171 this.el.setStyle("overflow", "hidden");
46173 this.el.setHeight(this.growMin);
46176 //console.log('onrender' + this.getId() );
46177 Roo.form.FCKeditor.editors[this.getId()] = this;
46180 this.replaceTextarea() ;
46184 getEditor : function() {
46185 return this.fckEditor;
46188 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46189 * @param {Mixed} value The value to set
46193 setValue : function(value)
46195 //console.log('setValue: ' + value);
46197 if(typeof(value) == 'undefined') { // not sure why this is happending...
46200 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46202 //if(!this.el || !this.getEditor()) {
46203 // this.value = value;
46204 //this.setValue.defer(100,this,[value]);
46208 if(!this.getEditor()) {
46212 this.getEditor().SetData(value);
46219 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46220 * @return {Mixed} value The field value
46222 getValue : function()
46225 if (this.frame && this.frame.dom.style.display == 'none') {
46226 return Roo.form.FCKeditor.superclass.getValue.call(this);
46229 if(!this.el || !this.getEditor()) {
46231 // this.getValue.defer(100,this);
46236 var value=this.getEditor().GetData();
46237 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46238 return Roo.form.FCKeditor.superclass.getValue.call(this);
46244 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46245 * @return {Mixed} value The field value
46247 getRawValue : function()
46249 if (this.frame && this.frame.dom.style.display == 'none') {
46250 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46253 if(!this.el || !this.getEditor()) {
46254 //this.getRawValue.defer(100,this);
46261 var value=this.getEditor().GetData();
46262 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46263 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46267 setSize : function(w,h) {
46271 //if (this.frame && this.frame.dom.style.display == 'none') {
46272 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46275 //if(!this.el || !this.getEditor()) {
46276 // this.setSize.defer(100,this, [w,h]);
46282 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46284 this.frame.dom.setAttribute('width', w);
46285 this.frame.dom.setAttribute('height', h);
46286 this.frame.setSize(w,h);
46290 toggleSourceEdit : function(value) {
46294 this.el.dom.style.display = value ? '' : 'none';
46295 this.frame.dom.style.display = value ? 'none' : '';
46300 focus: function(tag)
46302 if (this.frame.dom.style.display == 'none') {
46303 return Roo.form.FCKeditor.superclass.focus.call(this);
46305 if(!this.el || !this.getEditor()) {
46306 this.focus.defer(100,this, [tag]);
46313 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46314 this.getEditor().Focus();
46316 if (!this.getEditor().Selection.GetSelection()) {
46317 this.focus.defer(100,this, [tag]);
46322 var r = this.getEditor().EditorDocument.createRange();
46323 r.setStart(tgs[0],0);
46324 r.setEnd(tgs[0],0);
46325 this.getEditor().Selection.GetSelection().removeAllRanges();
46326 this.getEditor().Selection.GetSelection().addRange(r);
46327 this.getEditor().Focus();
46334 replaceTextarea : function()
46336 if ( document.getElementById( this.getId() + '___Frame' ) )
46338 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46340 // We must check the elements firstly using the Id and then the name.
46341 var oTextarea = document.getElementById( this.getId() );
46343 var colElementsByName = document.getElementsByName( this.getId() ) ;
46345 oTextarea.style.display = 'none' ;
46347 if ( oTextarea.tabIndex ) {
46348 this.TabIndex = oTextarea.tabIndex ;
46351 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46352 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46353 this.frame = Roo.get(this.getId() + '___Frame')
46356 _getConfigHtml : function()
46360 for ( var o in this.fckconfig ) {
46361 sConfig += sConfig.length > 0 ? '&' : '';
46362 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46365 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46369 _getIFrameHtml : function()
46371 var sFile = 'fckeditor.html' ;
46372 /* no idea what this is about..
46375 if ( (/fcksource=true/i).test( window.top.location.search ) )
46376 sFile = 'fckeditor.original.html' ;
46381 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46382 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46385 var html = '<iframe id="' + this.getId() +
46386 '___Frame" src="' + sLink +
46387 '" width="' + this.width +
46388 '" height="' + this.height + '"' +
46389 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46390 ' frameborder="0" scrolling="no"></iframe>' ;
46395 _insertHtmlBefore : function( html, element )
46397 if ( element.insertAdjacentHTML ) {
46399 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46401 var oRange = document.createRange() ;
46402 oRange.setStartBefore( element ) ;
46403 var oFragment = oRange.createContextualFragment( html );
46404 element.parentNode.insertBefore( oFragment, element ) ;
46417 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46419 function FCKeditor_OnComplete(editorInstance){
46420 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46421 f.fckEditor = editorInstance;
46422 //console.log("loaded");
46423 f.fireEvent('editorinit', f, editorInstance);
46443 //<script type="text/javascript">
46445 * @class Roo.form.GridField
46446 * @extends Roo.form.Field
46447 * Embed a grid (or editable grid into a form)
46450 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
46452 * xgrid.store = Roo.data.Store
46453 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
46454 * xgrid.store.reader = Roo.data.JsonReader
46458 * Creates a new GridField
46459 * @param {Object} config Configuration options
46461 Roo.form.GridField = function(config){
46462 Roo.form.GridField.superclass.constructor.call(this, config);
46466 Roo.extend(Roo.form.GridField, Roo.form.Field, {
46468 * @cfg {Number} width - used to restrict width of grid..
46472 * @cfg {Number} height - used to restrict height of grid..
46476 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
46482 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46483 * {tag: "input", type: "checkbox", autocomplete: "off"})
46485 // defaultAutoCreate : { tag: 'div' },
46486 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46488 * @cfg {String} addTitle Text to include for adding a title.
46492 onResize : function(){
46493 Roo.form.Field.superclass.onResize.apply(this, arguments);
46496 initEvents : function(){
46497 // Roo.form.Checkbox.superclass.initEvents.call(this);
46498 // has no events...
46503 getResizeEl : function(){
46507 getPositionEl : function(){
46512 onRender : function(ct, position){
46514 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
46515 var style = this.style;
46518 Roo.form.GridField.superclass.onRender.call(this, ct, position);
46519 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
46520 this.viewEl = this.wrap.createChild({ tag: 'div' });
46522 this.viewEl.applyStyles(style);
46525 this.viewEl.setWidth(this.width);
46528 this.viewEl.setHeight(this.height);
46530 //if(this.inputValue !== undefined){
46531 //this.setValue(this.value);
46534 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
46537 this.grid.render();
46538 this.grid.getDataSource().on('remove', this.refreshValue, this);
46539 this.grid.getDataSource().on('update', this.refreshValue, this);
46540 this.grid.on('afteredit', this.refreshValue, this);
46546 * Sets the value of the item.
46547 * @param {String} either an object or a string..
46549 setValue : function(v){
46551 v = v || []; // empty set..
46552 // this does not seem smart - it really only affects memoryproxy grids..
46553 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
46554 var ds = this.grid.getDataSource();
46555 // assumes a json reader..
46557 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
46558 ds.loadData( data);
46560 // clear selection so it does not get stale.
46561 if (this.grid.sm) {
46562 this.grid.sm.clearSelections();
46565 Roo.form.GridField.superclass.setValue.call(this, v);
46566 this.refreshValue();
46567 // should load data in the grid really....
46571 refreshValue: function() {
46573 this.grid.getDataSource().each(function(r) {
46576 this.el.dom.value = Roo.encode(val);
46584 * Ext JS Library 1.1.1
46585 * Copyright(c) 2006-2007, Ext JS, LLC.
46587 * Originally Released Under LGPL - original licence link has changed is not relivant.
46590 * <script type="text/javascript">
46593 * @class Roo.form.DisplayField
46594 * @extends Roo.form.Field
46595 * A generic Field to display non-editable data.
46597 * Creates a new Display Field item.
46598 * @param {Object} config Configuration options
46600 Roo.form.DisplayField = function(config){
46601 Roo.form.DisplayField.superclass.constructor.call(this, config);
46605 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
46606 inputType: 'hidden',
46612 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46614 focusClass : undefined,
46616 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46618 fieldClass: 'x-form-field',
46621 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
46623 valueRenderer: undefined,
46627 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46628 * {tag: "input", type: "checkbox", autocomplete: "off"})
46631 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
46633 onResize : function(){
46634 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
46638 initEvents : function(){
46639 // Roo.form.Checkbox.superclass.initEvents.call(this);
46640 // has no events...
46645 getResizeEl : function(){
46649 getPositionEl : function(){
46654 onRender : function(ct, position){
46656 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
46657 //if(this.inputValue !== undefined){
46658 this.wrap = this.el.wrap();
46660 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
46662 if (this.bodyStyle) {
46663 this.viewEl.applyStyles(this.bodyStyle);
46665 //this.viewEl.setStyle('padding', '2px');
46667 this.setValue(this.value);
46672 initValue : Roo.emptyFn,
46677 onClick : function(){
46682 * Sets the checked state of the checkbox.
46683 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
46685 setValue : function(v){
46687 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
46688 // this might be called before we have a dom element..
46689 if (!this.viewEl) {
46692 this.viewEl.dom.innerHTML = html;
46693 Roo.form.DisplayField.superclass.setValue.call(this, v);
46703 * @class Roo.form.DayPicker
46704 * @extends Roo.form.Field
46705 * A Day picker show [M] [T] [W] ....
46707 * Creates a new Day Picker
46708 * @param {Object} config Configuration options
46710 Roo.form.DayPicker= function(config){
46711 Roo.form.DayPicker.superclass.constructor.call(this, config);
46715 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
46717 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
46719 focusClass : undefined,
46721 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
46723 fieldClass: "x-form-field",
46726 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
46727 * {tag: "input", type: "checkbox", autocomplete: "off"})
46729 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
46732 actionMode : 'viewEl',
46736 inputType : 'hidden',
46739 inputElement: false, // real input element?
46740 basedOn: false, // ????
46742 isFormField: true, // not sure where this is needed!!!!
46744 onResize : function(){
46745 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
46746 if(!this.boxLabel){
46747 this.el.alignTo(this.wrap, 'c-c');
46751 initEvents : function(){
46752 Roo.form.Checkbox.superclass.initEvents.call(this);
46753 this.el.on("click", this.onClick, this);
46754 this.el.on("change", this.onClick, this);
46758 getResizeEl : function(){
46762 getPositionEl : function(){
46768 onRender : function(ct, position){
46769 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
46771 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
46773 var r1 = '<table><tr>';
46774 var r2 = '<tr class="x-form-daypick-icons">';
46775 for (var i=0; i < 7; i++) {
46776 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
46777 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
46780 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
46781 viewEl.select('img').on('click', this.onClick, this);
46782 this.viewEl = viewEl;
46785 // this will not work on Chrome!!!
46786 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
46787 this.el.on('propertychange', this.setFromHidden, this); //ie
46795 initValue : Roo.emptyFn,
46798 * Returns the checked state of the checkbox.
46799 * @return {Boolean} True if checked, else false
46801 getValue : function(){
46802 return this.el.dom.value;
46807 onClick : function(e){
46808 //this.setChecked(!this.checked);
46809 Roo.get(e.target).toggleClass('x-menu-item-checked');
46810 this.refreshValue();
46811 //if(this.el.dom.checked != this.checked){
46812 // this.setValue(this.el.dom.checked);
46817 refreshValue : function()
46820 this.viewEl.select('img',true).each(function(e,i,n) {
46821 val += e.is(".x-menu-item-checked") ? String(n) : '';
46823 this.setValue(val, true);
46827 * Sets the checked state of the checkbox.
46828 * On is always based on a string comparison between inputValue and the param.
46829 * @param {Boolean/String} value - the value to set
46830 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
46832 setValue : function(v,suppressEvent){
46833 if (!this.el.dom) {
46836 var old = this.el.dom.value ;
46837 this.el.dom.value = v;
46838 if (suppressEvent) {
46842 // update display..
46843 this.viewEl.select('img',true).each(function(e,i,n) {
46845 var on = e.is(".x-menu-item-checked");
46846 var newv = v.indexOf(String(n)) > -1;
46848 e.toggleClass('x-menu-item-checked');
46854 this.fireEvent('change', this, v, old);
46859 // handle setting of hidden value by some other method!!?!?
46860 setFromHidden: function()
46865 //console.log("SET FROM HIDDEN");
46866 //alert('setFrom hidden');
46867 this.setValue(this.el.dom.value);
46870 onDestroy : function()
46873 Roo.get(this.viewEl).remove();
46876 Roo.form.DayPicker.superclass.onDestroy.call(this);
46880 * RooJS Library 1.1.1
46881 * Copyright(c) 2008-2011 Alan Knowles
46888 * @class Roo.form.ComboCheck
46889 * @extends Roo.form.ComboBox
46890 * A combobox for multiple select items.
46892 * FIXME - could do with a reset button..
46895 * Create a new ComboCheck
46896 * @param {Object} config Configuration options
46898 Roo.form.ComboCheck = function(config){
46899 Roo.form.ComboCheck.superclass.constructor.call(this, config);
46900 // should verify some data...
46902 // hiddenName = required..
46903 // displayField = required
46904 // valudField == required
46905 var req= [ 'hiddenName', 'displayField', 'valueField' ];
46907 Roo.each(req, function(e) {
46908 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
46909 throw "Roo.form.ComboCheck : missing value for: " + e;
46916 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
46921 selectedClass: 'x-menu-item-checked',
46924 onRender : function(ct, position){
46930 var cls = 'x-combo-list';
46933 this.tpl = new Roo.Template({
46934 html : '<div class="'+cls+'-item x-menu-check-item">' +
46935 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
46936 '<span>{' + this.displayField + '}</span>' +
46943 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
46944 this.view.singleSelect = false;
46945 this.view.multiSelect = true;
46946 this.view.toggleSelect = true;
46947 this.pageTb.add(new Roo.Toolbar.Fill(), {
46950 handler: function()
46957 onViewOver : function(e, t){
46963 onViewClick : function(doFocus,index){
46967 select: function () {
46968 //Roo.log("SELECT CALLED");
46971 selectByValue : function(xv, scrollIntoView){
46972 var ar = this.getValueArray();
46975 Roo.each(ar, function(v) {
46976 if(v === undefined || v === null){
46979 var r = this.findRecord(this.valueField, v);
46981 sels.push(this.store.indexOf(r))
46985 this.view.select(sels);
46991 onSelect : function(record, index){
46992 // Roo.log("onselect Called");
46993 // this is only called by the clear button now..
46994 this.view.clearSelections();
46995 this.setValue('[]');
46996 if (this.value != this.valueBefore) {
46997 this.fireEvent('change', this, this.value, this.valueBefore);
46998 this.valueBefore = this.value;
47001 getValueArray : function()
47006 //Roo.log(this.value);
47007 if (typeof(this.value) == 'undefined') {
47010 var ar = Roo.decode(this.value);
47011 return ar instanceof Array ? ar : []; //?? valid?
47014 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47019 expand : function ()
47022 Roo.form.ComboCheck.superclass.expand.call(this);
47023 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47024 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47029 collapse : function(){
47030 Roo.form.ComboCheck.superclass.collapse.call(this);
47031 var sl = this.view.getSelectedIndexes();
47032 var st = this.store;
47036 Roo.each(sl, function(i) {
47038 nv.push(r.get(this.valueField));
47040 this.setValue(Roo.encode(nv));
47041 if (this.value != this.valueBefore) {
47043 this.fireEvent('change', this, this.value, this.valueBefore);
47044 this.valueBefore = this.value;
47049 setValue : function(v){
47053 var vals = this.getValueArray();
47055 Roo.each(vals, function(k) {
47056 var r = this.findRecord(this.valueField, k);
47058 tv.push(r.data[this.displayField]);
47059 }else if(this.valueNotFoundText !== undefined){
47060 tv.push( this.valueNotFoundText );
47065 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47066 this.hiddenField.value = v;
47072 * Ext JS Library 1.1.1
47073 * Copyright(c) 2006-2007, Ext JS, LLC.
47075 * Originally Released Under LGPL - original licence link has changed is not relivant.
47078 * <script type="text/javascript">
47082 * @class Roo.form.Signature
47083 * @extends Roo.form.Field
47087 * @param {Object} config Configuration options
47090 Roo.form.Signature = function(config){
47091 Roo.form.Signature.superclass.constructor.call(this, config);
47093 this.addEvents({// not in used??
47096 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47097 * @param {Roo.form.Signature} combo This combo box
47102 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47103 * @param {Roo.form.ComboBox} combo This combo box
47104 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47110 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47112 * @cfg {Object} labels Label to use when rendering a form.
47116 * confirm : "Confirm"
47121 confirm : "Confirm"
47124 * @cfg {Number} width The signature panel width (defaults to 300)
47128 * @cfg {Number} height The signature panel height (defaults to 100)
47132 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47134 allowBlank : false,
47137 // {Object} signPanel The signature SVG panel element (defaults to {})
47139 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47140 isMouseDown : false,
47141 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47142 isConfirmed : false,
47143 // {String} signatureTmp SVG mapping string (defaults to empty string)
47147 defaultAutoCreate : { // modified by initCompnoent..
47153 onRender : function(ct, position){
47155 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47157 this.wrap = this.el.wrap({
47158 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47161 this.createToolbar(this);
47162 this.signPanel = this.wrap.createChild({
47164 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47168 this.svgID = Roo.id();
47169 this.svgEl = this.signPanel.createChild({
47170 xmlns : 'http://www.w3.org/2000/svg',
47172 id : this.svgID + "-svg",
47174 height: this.height,
47175 viewBox: '0 0 '+this.width+' '+this.height,
47179 id: this.svgID + "-svg-r",
47181 height: this.height,
47186 id: this.svgID + "-svg-l",
47188 y1: (this.height*0.8), // start set the line in 80% of height
47189 x2: this.width, // end
47190 y2: (this.height*0.8), // end set the line in 80% of height
47192 'stroke-width': "1",
47193 'stroke-dasharray': "3",
47194 'shape-rendering': "crispEdges",
47195 'pointer-events': "none"
47199 id: this.svgID + "-svg-p",
47201 'stroke-width': "3",
47203 'pointer-events': 'none'
47208 this.svgBox = this.svgEl.dom.getScreenCTM();
47210 createSVG : function(){
47211 var svg = this.signPanel;
47212 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47215 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47216 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47217 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47218 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47219 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47220 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47221 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47224 isTouchEvent : function(e){
47225 return e.type.match(/^touch/);
47227 getCoords : function (e) {
47228 var pt = this.svgEl.dom.createSVGPoint();
47231 if (this.isTouchEvent(e)) {
47232 pt.x = e.targetTouches[0].clientX
47233 pt.y = e.targetTouches[0].clientY;
47235 var a = this.svgEl.dom.getScreenCTM();
47236 var b = a.inverse();
47237 var mx = pt.matrixTransform(b);
47238 return mx.x + ',' + mx.y;
47240 //mouse event headler
47241 down : function (e) {
47242 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47243 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47245 this.isMouseDown = true;
47247 e.preventDefault();
47249 move : function (e) {
47250 if (this.isMouseDown) {
47251 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47252 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47255 e.preventDefault();
47257 up : function (e) {
47258 this.isMouseDown = false;
47259 var sp = this.signatureTmp.split(' ');
47262 if(!sp[sp.length-2].match(/^L/)){
47266 this.signatureTmp = sp.join(" ");
47269 if(this.getValue() != this.signatureTmp){
47270 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47271 this.isConfirmed = false;
47273 e.preventDefault();
47277 * Protected method that will not generally be called directly. It
47278 * is called when the editor creates its toolbar. Override this method if you need to
47279 * add custom toolbar buttons.
47280 * @param {HtmlEditor} editor
47282 createToolbar : function(editor){
47283 function btn(id, toggle, handler){
47284 var xid = fid + '-'+ id ;
47288 cls : 'x-btn-icon x-edit-'+id,
47289 enableToggle:toggle !== false,
47290 scope: editor, // was editor...
47291 handler:handler||editor.relayBtnCmd,
47292 clickEvent:'mousedown',
47293 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47299 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47303 cls : ' x-signature-btn x-signature-'+id,
47304 scope: editor, // was editor...
47305 handler: this.reset,
47306 clickEvent:'mousedown',
47307 text: this.labels.clear
47314 cls : ' x-signature-btn x-signature-'+id,
47315 scope: editor, // was editor...
47316 handler: this.confirmHandler,
47317 clickEvent:'mousedown',
47318 text: this.labels.confirm
47325 * when user is clicked confirm then show this image.....
47327 * @return {String} Image Data URI
47329 getImageDataURI : function(){
47330 var svg = this.svgEl.dom.parentNode.innerHTML;
47331 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47336 * @return {Boolean} this.isConfirmed
47338 getConfirmed : function(){
47339 return this.isConfirmed;
47343 * @return {Number} this.width
47345 getWidth : function(){
47350 * @return {Number} this.height
47352 getHeight : function(){
47353 return this.height;
47356 getSignature : function(){
47357 return this.signatureTmp;
47360 reset : function(){
47361 this.signatureTmp = '';
47362 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47363 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47364 this.isConfirmed = false;
47365 Roo.form.Signature.superclass.reset.call(this);
47367 setSignature : function(s){
47368 this.signatureTmp = s;
47369 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47370 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47372 this.isConfirmed = false;
47373 Roo.form.Signature.superclass.reset.call(this);
47376 // Roo.log(this.signPanel.dom.contentWindow.up())
47379 setConfirmed : function(){
47383 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47386 confirmHandler : function(){
47387 if(!this.getSignature()){
47391 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47392 this.setValue(this.getSignature());
47393 this.isConfirmed = true;
47395 this.fireEvent('confirm', this);
47398 // Subclasses should provide the validation implementation by overriding this
47399 validateValue : function(value){
47400 if(this.allowBlank){
47404 if(this.isConfirmed){
47411 * Ext JS Library 1.1.1
47412 * Copyright(c) 2006-2007, Ext JS, LLC.
47414 * Originally Released Under LGPL - original licence link has changed is not relivant.
47417 * <script type="text/javascript">
47422 * @class Roo.form.ComboBox
47423 * @extends Roo.form.TriggerField
47424 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47426 * Create a new ComboBox.
47427 * @param {Object} config Configuration options
47429 Roo.form.Select = function(config){
47430 Roo.form.Select.superclass.constructor.call(this, config);
47434 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47436 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47439 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47440 * rendering into an Roo.Editor, defaults to false)
47443 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
47444 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
47447 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
47450 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
47451 * the dropdown list (defaults to undefined, with no header element)
47455 * @cfg {String/Roo.Template} tpl The template to use to render the output
47459 defaultAutoCreate : {tag: "select" },
47461 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
47463 listWidth: undefined,
47465 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
47466 * mode = 'remote' or 'text' if mode = 'local')
47468 displayField: undefined,
47470 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
47471 * mode = 'remote' or 'value' if mode = 'local').
47472 * Note: use of a valueField requires the user make a selection
47473 * in order for a value to be mapped.
47475 valueField: undefined,
47479 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
47480 * field's data value (defaults to the underlying DOM element's name)
47482 hiddenName: undefined,
47484 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
47488 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
47490 selectedClass: 'x-combo-selected',
47492 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
47493 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
47494 * which displays a downward arrow icon).
47496 triggerClass : 'x-form-arrow-trigger',
47498 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
47502 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
47503 * anchor positions (defaults to 'tl-bl')
47505 listAlign: 'tl-bl?',
47507 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
47511 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
47512 * query specified by the allQuery config option (defaults to 'query')
47514 triggerAction: 'query',
47516 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
47517 * (defaults to 4, does not apply if editable = false)
47521 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
47522 * delay (typeAheadDelay) if it matches a known value (defaults to false)
47526 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
47527 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
47531 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
47532 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
47536 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
47537 * when editable = true (defaults to false)
47539 selectOnFocus:false,
47541 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
47543 queryParam: 'query',
47545 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
47546 * when mode = 'remote' (defaults to 'Loading...')
47548 loadingText: 'Loading...',
47550 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
47554 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
47558 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
47559 * traditional select (defaults to true)
47563 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
47567 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
47571 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
47572 * listWidth has a higher value)
47576 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
47577 * allow the user to set arbitrary text into the field (defaults to false)
47579 forceSelection:false,
47581 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
47582 * if typeAhead = true (defaults to 250)
47584 typeAheadDelay : 250,
47586 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
47587 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
47589 valueNotFoundText : undefined,
47592 * @cfg {String} defaultValue The value displayed after loading the store.
47597 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
47599 blockFocus : false,
47602 * @cfg {Boolean} disableClear Disable showing of clear button.
47604 disableClear : false,
47606 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
47608 alwaysQuery : false,
47614 // element that contains real text value.. (when hidden is used..)
47617 onRender : function(ct, position){
47618 Roo.form.Field.prototype.onRender.call(this, ct, position);
47621 this.store.on('beforeload', this.onBeforeLoad, this);
47622 this.store.on('load', this.onLoad, this);
47623 this.store.on('loadexception', this.onLoadException, this);
47624 this.store.load({});
47632 initEvents : function(){
47633 //Roo.form.ComboBox.superclass.initEvents.call(this);
47637 onDestroy : function(){
47640 this.store.un('beforeload', this.onBeforeLoad, this);
47641 this.store.un('load', this.onLoad, this);
47642 this.store.un('loadexception', this.onLoadException, this);
47644 //Roo.form.ComboBox.superclass.onDestroy.call(this);
47648 fireKey : function(e){
47649 if(e.isNavKeyPress() && !this.list.isVisible()){
47650 this.fireEvent("specialkey", this, e);
47655 onResize: function(w, h){
47663 * Allow or prevent the user from directly editing the field text. If false is passed,
47664 * the user will only be able to select from the items defined in the dropdown list. This method
47665 * is the runtime equivalent of setting the 'editable' config option at config time.
47666 * @param {Boolean} value True to allow the user to directly edit the field text
47668 setEditable : function(value){
47673 onBeforeLoad : function(){
47675 Roo.log("Select before load");
47678 this.innerList.update(this.loadingText ?
47679 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
47680 //this.restrictHeight();
47681 this.selectedIndex = -1;
47685 onLoad : function(){
47688 var dom = this.el.dom;
47689 dom.innerHTML = '';
47690 var od = dom.ownerDocument;
47692 if (this.emptyText) {
47693 var op = od.createElement('option');
47694 op.setAttribute('value', '');
47695 op.innerHTML = String.format('{0}', this.emptyText);
47696 dom.appendChild(op);
47698 if(this.store.getCount() > 0){
47700 var vf = this.valueField;
47701 var df = this.displayField;
47702 this.store.data.each(function(r) {
47703 // which colmsn to use... testing - cdoe / title..
47704 var op = od.createElement('option');
47705 op.setAttribute('value', r.data[vf]);
47706 op.innerHTML = String.format('{0}', r.data[df]);
47707 dom.appendChild(op);
47709 if (typeof(this.defaultValue != 'undefined')) {
47710 this.setValue(this.defaultValue);
47715 //this.onEmptyResults();
47720 onLoadException : function()
47722 dom.innerHTML = '';
47724 Roo.log("Select on load exception");
47728 Roo.log(this.store.reader.jsonData);
47729 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
47730 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
47736 onTypeAhead : function(){
47741 onSelect : function(record, index){
47742 Roo.log('on select?');
47744 if(this.fireEvent('beforeselect', this, record, index) !== false){
47745 this.setFromData(index > -1 ? record.data : false);
47747 this.fireEvent('select', this, record, index);
47752 * Returns the currently selected field value or empty string if no value is set.
47753 * @return {String} value The selected value
47755 getValue : function(){
47756 var dom = this.el.dom;
47757 this.value = dom.options[dom.selectedIndex].value;
47763 * Clears any text/value currently set in the field
47765 clearValue : function(){
47767 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
47772 * Sets the specified value into the field. If the value finds a match, the corresponding record text
47773 * will be displayed in the field. If the value does not match the data value of an existing item,
47774 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
47775 * Otherwise the field will be blank (although the value will still be set).
47776 * @param {String} value The value to match
47778 setValue : function(v){
47779 var d = this.el.dom;
47780 for (var i =0; i < d.options.length;i++) {
47781 if (v == d.options[i].value) {
47782 d.selectedIndex = i;
47790 * @property {Object} the last set data for the element
47795 * Sets the value of the field based on a object which is related to the record format for the store.
47796 * @param {Object} value the value to set as. or false on reset?
47798 setFromData : function(o){
47799 Roo.log('setfrom data?');
47805 reset : function(){
47809 findRecord : function(prop, value){
47814 if(this.store.getCount() > 0){
47815 this.store.each(function(r){
47816 if(r.data[prop] == value){
47826 getName: function()
47828 // returns hidden if it's set..
47829 if (!this.rendered) {return ''};
47830 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
47838 onEmptyResults : function(){
47839 Roo.log('empty results');
47844 * Returns true if the dropdown list is expanded, else false.
47846 isExpanded : function(){
47851 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
47852 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47853 * @param {String} value The data value of the item to select
47854 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47855 * selected item if it is not currently in view (defaults to true)
47856 * @return {Boolean} True if the value matched an item in the list, else false
47858 selectByValue : function(v, scrollIntoView){
47859 Roo.log('select By Value');
47862 if(v !== undefined && v !== null){
47863 var r = this.findRecord(this.valueField || this.displayField, v);
47865 this.select(this.store.indexOf(r), scrollIntoView);
47873 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
47874 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
47875 * @param {Number} index The zero-based index of the list item to select
47876 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
47877 * selected item if it is not currently in view (defaults to true)
47879 select : function(index, scrollIntoView){
47880 Roo.log('select ');
47883 this.selectedIndex = index;
47884 this.view.select(index);
47885 if(scrollIntoView !== false){
47886 var el = this.view.getNode(index);
47888 this.innerList.scrollChildIntoView(el, false);
47896 validateBlur : function(){
47903 initQuery : function(){
47904 this.doQuery(this.getRawValue());
47908 doForce : function(){
47909 if(this.el.dom.value.length > 0){
47910 this.el.dom.value =
47911 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
47917 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
47918 * query allowing the query action to be canceled if needed.
47919 * @param {String} query The SQL query to execute
47920 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
47921 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
47922 * saved in the current store (defaults to false)
47924 doQuery : function(q, forceAll){
47926 Roo.log('doQuery?');
47927 if(q === undefined || q === null){
47932 forceAll: forceAll,
47936 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
47940 forceAll = qe.forceAll;
47941 if(forceAll === true || (q.length >= this.minChars)){
47942 if(this.lastQuery != q || this.alwaysQuery){
47943 this.lastQuery = q;
47944 if(this.mode == 'local'){
47945 this.selectedIndex = -1;
47947 this.store.clearFilter();
47949 this.store.filter(this.displayField, q);
47953 this.store.baseParams[this.queryParam] = q;
47955 params: this.getParams(q)
47960 this.selectedIndex = -1;
47967 getParams : function(q){
47969 //p[this.queryParam] = q;
47972 p.limit = this.pageSize;
47978 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
47980 collapse : function(){
47985 collapseIf : function(e){
47990 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
47992 expand : function(){
48000 * @cfg {Boolean} grow
48004 * @cfg {Number} growMin
48008 * @cfg {Number} growMax
48016 setWidth : function()
48020 getResizeEl : function(){
48023 });//<script type="text/javasscript">
48027 * @class Roo.DDView
48028 * A DnD enabled version of Roo.View.
48029 * @param {Element/String} container The Element in which to create the View.
48030 * @param {String} tpl The template string used to create the markup for each element of the View
48031 * @param {Object} config The configuration properties. These include all the config options of
48032 * {@link Roo.View} plus some specific to this class.<br>
48034 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48035 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48037 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48038 .x-view-drag-insert-above {
48039 border-top:1px dotted #3366cc;
48041 .x-view-drag-insert-below {
48042 border-bottom:1px dotted #3366cc;
48048 Roo.DDView = function(container, tpl, config) {
48049 Roo.DDView.superclass.constructor.apply(this, arguments);
48050 this.getEl().setStyle("outline", "0px none");
48051 this.getEl().unselectable();
48052 if (this.dragGroup) {
48053 this.setDraggable(this.dragGroup.split(","));
48055 if (this.dropGroup) {
48056 this.setDroppable(this.dropGroup.split(","));
48058 if (this.deletable) {
48059 this.setDeletable();
48061 this.isDirtyFlag = false;
48067 Roo.extend(Roo.DDView, Roo.View, {
48068 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48069 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48070 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48071 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48075 reset: Roo.emptyFn,
48077 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48079 validate: function() {
48083 destroy: function() {
48084 this.purgeListeners();
48085 this.getEl.removeAllListeners();
48086 this.getEl().remove();
48087 if (this.dragZone) {
48088 if (this.dragZone.destroy) {
48089 this.dragZone.destroy();
48092 if (this.dropZone) {
48093 if (this.dropZone.destroy) {
48094 this.dropZone.destroy();
48099 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48100 getName: function() {
48104 /** Loads the View from a JSON string representing the Records to put into the Store. */
48105 setValue: function(v) {
48107 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48110 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48111 this.store.proxy = new Roo.data.MemoryProxy(data);
48115 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48116 getValue: function() {
48118 this.store.each(function(rec) {
48119 result += rec.id + ',';
48121 return result.substr(0, result.length - 1) + ')';
48124 getIds: function() {
48125 var i = 0, result = new Array(this.store.getCount());
48126 this.store.each(function(rec) {
48127 result[i++] = rec.id;
48132 isDirty: function() {
48133 return this.isDirtyFlag;
48137 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48138 * whole Element becomes the target, and this causes the drop gesture to append.
48140 getTargetFromEvent : function(e) {
48141 var target = e.getTarget();
48142 while ((target !== null) && (target.parentNode != this.el.dom)) {
48143 target = target.parentNode;
48146 target = this.el.dom.lastChild || this.el.dom;
48152 * Create the drag data which consists of an object which has the property "ddel" as
48153 * the drag proxy element.
48155 getDragData : function(e) {
48156 var target = this.findItemFromChild(e.getTarget());
48158 this.handleSelection(e);
48159 var selNodes = this.getSelectedNodes();
48162 copy: this.copy || (this.allowCopy && e.ctrlKey),
48166 var selectedIndices = this.getSelectedIndexes();
48167 for (var i = 0; i < selectedIndices.length; i++) {
48168 dragData.records.push(this.store.getAt(selectedIndices[i]));
48170 if (selNodes.length == 1) {
48171 dragData.ddel = target.cloneNode(true); // the div element
48173 var div = document.createElement('div'); // create the multi element drag "ghost"
48174 div.className = 'multi-proxy';
48175 for (var i = 0, len = selNodes.length; i < len; i++) {
48176 div.appendChild(selNodes[i].cloneNode(true));
48178 dragData.ddel = div;
48180 //console.log(dragData)
48181 //console.log(dragData.ddel.innerHTML)
48184 //console.log('nodragData')
48188 /** Specify to which ddGroup items in this DDView may be dragged. */
48189 setDraggable: function(ddGroup) {
48190 if (ddGroup instanceof Array) {
48191 Roo.each(ddGroup, this.setDraggable, this);
48194 if (this.dragZone) {
48195 this.dragZone.addToGroup(ddGroup);
48197 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48198 containerScroll: true,
48202 // Draggability implies selection. DragZone's mousedown selects the element.
48203 if (!this.multiSelect) { this.singleSelect = true; }
48205 // Wire the DragZone's handlers up to methods in *this*
48206 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48210 /** Specify from which ddGroup this DDView accepts drops. */
48211 setDroppable: function(ddGroup) {
48212 if (ddGroup instanceof Array) {
48213 Roo.each(ddGroup, this.setDroppable, this);
48216 if (this.dropZone) {
48217 this.dropZone.addToGroup(ddGroup);
48219 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48220 containerScroll: true,
48224 // Wire the DropZone's handlers up to methods in *this*
48225 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48226 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48227 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48228 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48229 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48233 /** Decide whether to drop above or below a View node. */
48234 getDropPoint : function(e, n, dd){
48235 if (n == this.el.dom) { return "above"; }
48236 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48237 var c = t + (b - t) / 2;
48238 var y = Roo.lib.Event.getPageY(e);
48246 onNodeEnter : function(n, dd, e, data){
48250 onNodeOver : function(n, dd, e, data){
48251 var pt = this.getDropPoint(e, n, dd);
48252 // set the insert point style on the target node
48253 var dragElClass = this.dropNotAllowed;
48256 if (pt == "above"){
48257 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48258 targetElClass = "x-view-drag-insert-above";
48260 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48261 targetElClass = "x-view-drag-insert-below";
48263 if (this.lastInsertClass != targetElClass){
48264 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48265 this.lastInsertClass = targetElClass;
48268 return dragElClass;
48271 onNodeOut : function(n, dd, e, data){
48272 this.removeDropIndicators(n);
48275 onNodeDrop : function(n, dd, e, data){
48276 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48279 var pt = this.getDropPoint(e, n, dd);
48280 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48281 if (pt == "below") { insertAt++; }
48282 for (var i = 0; i < data.records.length; i++) {
48283 var r = data.records[i];
48284 var dup = this.store.getById(r.id);
48285 if (dup && (dd != this.dragZone)) {
48286 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48289 this.store.insert(insertAt++, r.copy());
48291 data.source.isDirtyFlag = true;
48293 this.store.insert(insertAt++, r);
48295 this.isDirtyFlag = true;
48298 this.dragZone.cachedTarget = null;
48302 removeDropIndicators : function(n){
48304 Roo.fly(n).removeClass([
48305 "x-view-drag-insert-above",
48306 "x-view-drag-insert-below"]);
48307 this.lastInsertClass = "_noclass";
48312 * Utility method. Add a delete option to the DDView's context menu.
48313 * @param {String} imageUrl The URL of the "delete" icon image.
48315 setDeletable: function(imageUrl) {
48316 if (!this.singleSelect && !this.multiSelect) {
48317 this.singleSelect = true;
48319 var c = this.getContextMenu();
48320 this.contextMenu.on("itemclick", function(item) {
48323 this.remove(this.getSelectedIndexes());
48327 this.contextMenu.add({
48334 /** Return the context menu for this DDView. */
48335 getContextMenu: function() {
48336 if (!this.contextMenu) {
48337 // Create the View's context menu
48338 this.contextMenu = new Roo.menu.Menu({
48339 id: this.id + "-contextmenu"
48341 this.el.on("contextmenu", this.showContextMenu, this);
48343 return this.contextMenu;
48346 disableContextMenu: function() {
48347 if (this.contextMenu) {
48348 this.el.un("contextmenu", this.showContextMenu, this);
48352 showContextMenu: function(e, item) {
48353 item = this.findItemFromChild(e.getTarget());
48356 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48357 this.contextMenu.showAt(e.getXY());
48362 * Remove {@link Roo.data.Record}s at the specified indices.
48363 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48365 remove: function(selectedIndices) {
48366 selectedIndices = [].concat(selectedIndices);
48367 for (var i = 0; i < selectedIndices.length; i++) {
48368 var rec = this.store.getAt(selectedIndices[i]);
48369 this.store.remove(rec);
48374 * Double click fires the event, but also, if this is draggable, and there is only one other
48375 * related DropZone, it transfers the selected node.
48377 onDblClick : function(e){
48378 var item = this.findItemFromChild(e.getTarget());
48380 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48383 if (this.dragGroup) {
48384 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48385 while (targets.indexOf(this.dropZone) > -1) {
48386 targets.remove(this.dropZone);
48388 if (targets.length == 1) {
48389 this.dragZone.cachedTarget = null;
48390 var el = Roo.get(targets[0].getEl());
48391 var box = el.getBox(true);
48392 targets[0].onNodeDrop(el.dom, {
48394 xy: [box.x, box.y + box.height - 1]
48395 }, null, this.getDragData(e));
48401 handleSelection: function(e) {
48402 this.dragZone.cachedTarget = null;
48403 var item = this.findItemFromChild(e.getTarget());
48405 this.clearSelections(true);
48408 if (item && (this.multiSelect || this.singleSelect)){
48409 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48410 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48411 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48412 this.unselect(item);
48414 this.select(item, this.multiSelect && e.ctrlKey);
48415 this.lastSelection = item;
48420 onItemClick : function(item, index, e){
48421 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48427 unselect : function(nodeInfo, suppressEvent){
48428 var node = this.getNode(nodeInfo);
48429 if(node && this.isSelected(node)){
48430 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48431 Roo.fly(node).removeClass(this.selectedClass);
48432 this.selections.remove(node);
48433 if(!suppressEvent){
48434 this.fireEvent("selectionchange", this, this.selections);
48442 * Ext JS Library 1.1.1
48443 * Copyright(c) 2006-2007, Ext JS, LLC.
48445 * Originally Released Under LGPL - original licence link has changed is not relivant.
48448 * <script type="text/javascript">
48452 * @class Roo.LayoutManager
48453 * @extends Roo.util.Observable
48454 * Base class for layout managers.
48456 Roo.LayoutManager = function(container, config){
48457 Roo.LayoutManager.superclass.constructor.call(this);
48458 this.el = Roo.get(container);
48459 // ie scrollbar fix
48460 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
48461 document.body.scroll = "no";
48462 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
48463 this.el.position('relative');
48465 this.id = this.el.id;
48466 this.el.addClass("x-layout-container");
48467 /** false to disable window resize monitoring @type Boolean */
48468 this.monitorWindowResize = true;
48473 * Fires when a layout is performed.
48474 * @param {Roo.LayoutManager} this
48478 * @event regionresized
48479 * Fires when the user resizes a region.
48480 * @param {Roo.LayoutRegion} region The resized region
48481 * @param {Number} newSize The new size (width for east/west, height for north/south)
48483 "regionresized" : true,
48485 * @event regioncollapsed
48486 * Fires when a region is collapsed.
48487 * @param {Roo.LayoutRegion} region The collapsed region
48489 "regioncollapsed" : true,
48491 * @event regionexpanded
48492 * Fires when a region is expanded.
48493 * @param {Roo.LayoutRegion} region The expanded region
48495 "regionexpanded" : true
48497 this.updating = false;
48498 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
48501 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
48503 * Returns true if this layout is currently being updated
48504 * @return {Boolean}
48506 isUpdating : function(){
48507 return this.updating;
48511 * Suspend the LayoutManager from doing auto-layouts while
48512 * making multiple add or remove calls
48514 beginUpdate : function(){
48515 this.updating = true;
48519 * Restore auto-layouts and optionally disable the manager from performing a layout
48520 * @param {Boolean} noLayout true to disable a layout update
48522 endUpdate : function(noLayout){
48523 this.updating = false;
48529 layout: function(){
48533 onRegionResized : function(region, newSize){
48534 this.fireEvent("regionresized", region, newSize);
48538 onRegionCollapsed : function(region){
48539 this.fireEvent("regioncollapsed", region);
48542 onRegionExpanded : function(region){
48543 this.fireEvent("regionexpanded", region);
48547 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
48548 * performs box-model adjustments.
48549 * @return {Object} The size as an object {width: (the width), height: (the height)}
48551 getViewSize : function(){
48553 if(this.el.dom != document.body){
48554 size = this.el.getSize();
48556 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
48558 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
48559 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
48564 * Returns the Element this layout is bound to.
48565 * @return {Roo.Element}
48567 getEl : function(){
48572 * Returns the specified region.
48573 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
48574 * @return {Roo.LayoutRegion}
48576 getRegion : function(target){
48577 return this.regions[target.toLowerCase()];
48580 onWindowResize : function(){
48581 if(this.monitorWindowResize){
48587 * Ext JS Library 1.1.1
48588 * Copyright(c) 2006-2007, Ext JS, LLC.
48590 * Originally Released Under LGPL - original licence link has changed is not relivant.
48593 * <script type="text/javascript">
48596 * @class Roo.BorderLayout
48597 * @extends Roo.LayoutManager
48598 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
48599 * please see: <br><br>
48600 * <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>
48601 * <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>
48604 var layout = new Roo.BorderLayout(document.body, {
48638 preferredTabWidth: 150
48643 var CP = Roo.ContentPanel;
48645 layout.beginUpdate();
48646 layout.add("north", new CP("north", "North"));
48647 layout.add("south", new CP("south", {title: "South", closable: true}));
48648 layout.add("west", new CP("west", {title: "West"}));
48649 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
48650 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
48651 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
48652 layout.getRegion("center").showPanel("center1");
48653 layout.endUpdate();
48656 <b>The container the layout is rendered into can be either the body element or any other element.
48657 If it is not the body element, the container needs to either be an absolute positioned element,
48658 or you will need to add "position:relative" to the css of the container. You will also need to specify
48659 the container size if it is not the body element.</b>
48662 * Create a new BorderLayout
48663 * @param {String/HTMLElement/Element} container The container this layout is bound to
48664 * @param {Object} config Configuration options
48666 Roo.BorderLayout = function(container, config){
48667 config = config || {};
48668 Roo.BorderLayout.superclass.constructor.call(this, container, config);
48669 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
48670 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
48671 var target = this.factory.validRegions[i];
48672 if(config[target]){
48673 this.addRegion(target, config[target]);
48678 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
48680 * Creates and adds a new region if it doesn't already exist.
48681 * @param {String} target The target region key (north, south, east, west or center).
48682 * @param {Object} config The regions config object
48683 * @return {BorderLayoutRegion} The new region
48685 addRegion : function(target, config){
48686 if(!this.regions[target]){
48687 var r = this.factory.create(target, this, config);
48688 this.bindRegion(target, r);
48690 return this.regions[target];
48694 bindRegion : function(name, r){
48695 this.regions[name] = r;
48696 r.on("visibilitychange", this.layout, this);
48697 r.on("paneladded", this.layout, this);
48698 r.on("panelremoved", this.layout, this);
48699 r.on("invalidated", this.layout, this);
48700 r.on("resized", this.onRegionResized, this);
48701 r.on("collapsed", this.onRegionCollapsed, this);
48702 r.on("expanded", this.onRegionExpanded, this);
48706 * Performs a layout update.
48708 layout : function(){
48709 if(this.updating) return;
48710 var size = this.getViewSize();
48711 var w = size.width;
48712 var h = size.height;
48717 //var x = 0, y = 0;
48719 var rs = this.regions;
48720 var north = rs["north"];
48721 var south = rs["south"];
48722 var west = rs["west"];
48723 var east = rs["east"];
48724 var center = rs["center"];
48725 //if(this.hideOnLayout){ // not supported anymore
48726 //c.el.setStyle("display", "none");
48728 if(north && north.isVisible()){
48729 var b = north.getBox();
48730 var m = north.getMargins();
48731 b.width = w - (m.left+m.right);
48734 centerY = b.height + b.y + m.bottom;
48735 centerH -= centerY;
48736 north.updateBox(this.safeBox(b));
48738 if(south && south.isVisible()){
48739 var b = south.getBox();
48740 var m = south.getMargins();
48741 b.width = w - (m.left+m.right);
48743 var totalHeight = (b.height + m.top + m.bottom);
48744 b.y = h - totalHeight + m.top;
48745 centerH -= totalHeight;
48746 south.updateBox(this.safeBox(b));
48748 if(west && west.isVisible()){
48749 var b = west.getBox();
48750 var m = west.getMargins();
48751 b.height = centerH - (m.top+m.bottom);
48753 b.y = centerY + m.top;
48754 var totalWidth = (b.width + m.left + m.right);
48755 centerX += totalWidth;
48756 centerW -= totalWidth;
48757 west.updateBox(this.safeBox(b));
48759 if(east && east.isVisible()){
48760 var b = east.getBox();
48761 var m = east.getMargins();
48762 b.height = centerH - (m.top+m.bottom);
48763 var totalWidth = (b.width + m.left + m.right);
48764 b.x = w - totalWidth + m.left;
48765 b.y = centerY + m.top;
48766 centerW -= totalWidth;
48767 east.updateBox(this.safeBox(b));
48770 var m = center.getMargins();
48772 x: centerX + m.left,
48773 y: centerY + m.top,
48774 width: centerW - (m.left+m.right),
48775 height: centerH - (m.top+m.bottom)
48777 //if(this.hideOnLayout){
48778 //center.el.setStyle("display", "block");
48780 center.updateBox(this.safeBox(centerBox));
48783 this.fireEvent("layout", this);
48787 safeBox : function(box){
48788 box.width = Math.max(0, box.width);
48789 box.height = Math.max(0, box.height);
48794 * Adds a ContentPanel (or subclass) to this layout.
48795 * @param {String} target The target region key (north, south, east, west or center).
48796 * @param {Roo.ContentPanel} panel The panel to add
48797 * @return {Roo.ContentPanel} The added panel
48799 add : function(target, panel){
48801 target = target.toLowerCase();
48802 return this.regions[target].add(panel);
48806 * Remove a ContentPanel (or subclass) to this layout.
48807 * @param {String} target The target region key (north, south, east, west or center).
48808 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
48809 * @return {Roo.ContentPanel} The removed panel
48811 remove : function(target, panel){
48812 target = target.toLowerCase();
48813 return this.regions[target].remove(panel);
48817 * Searches all regions for a panel with the specified id
48818 * @param {String} panelId
48819 * @return {Roo.ContentPanel} The panel or null if it wasn't found
48821 findPanel : function(panelId){
48822 var rs = this.regions;
48823 for(var target in rs){
48824 if(typeof rs[target] != "function"){
48825 var p = rs[target].getPanel(panelId);
48835 * Searches all regions for a panel with the specified id and activates (shows) it.
48836 * @param {String/ContentPanel} panelId The panels id or the panel itself
48837 * @return {Roo.ContentPanel} The shown panel or null
48839 showPanel : function(panelId) {
48840 var rs = this.regions;
48841 for(var target in rs){
48842 var r = rs[target];
48843 if(typeof r != "function"){
48844 if(r.hasPanel(panelId)){
48845 return r.showPanel(panelId);
48853 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
48854 * @param {Roo.state.Provider} provider (optional) An alternate state provider
48856 restoreState : function(provider){
48858 provider = Roo.state.Manager;
48860 var sm = new Roo.LayoutStateManager();
48861 sm.init(this, provider);
48865 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
48866 * object should contain properties for each region to add ContentPanels to, and each property's value should be
48867 * a valid ContentPanel config object. Example:
48869 // Create the main layout
48870 var layout = new Roo.BorderLayout('main-ct', {
48881 // Create and add multiple ContentPanels at once via configs
48884 id: 'source-files',
48886 title:'Ext Source Files',
48899 * @param {Object} regions An object containing ContentPanel configs by region name
48901 batchAdd : function(regions){
48902 this.beginUpdate();
48903 for(var rname in regions){
48904 var lr = this.regions[rname];
48906 this.addTypedPanels(lr, regions[rname]);
48913 addTypedPanels : function(lr, ps){
48914 if(typeof ps == 'string'){
48915 lr.add(new Roo.ContentPanel(ps));
48917 else if(ps instanceof Array){
48918 for(var i =0, len = ps.length; i < len; i++){
48919 this.addTypedPanels(lr, ps[i]);
48922 else if(!ps.events){ // raw config?
48924 delete ps.el; // prevent conflict
48925 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
48927 else { // panel object assumed!
48932 * Adds a xtype elements to the layout.
48936 xtype : 'ContentPanel',
48943 xtype : 'NestedLayoutPanel',
48949 items : [ ... list of content panels or nested layout panels.. ]
48953 * @param {Object} cfg Xtype definition of item to add.
48955 addxtype : function(cfg)
48957 // basically accepts a pannel...
48958 // can accept a layout region..!?!?
48959 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
48961 if (!cfg.xtype.match(/Panel$/)) {
48966 if (typeof(cfg.region) == 'undefined') {
48967 Roo.log("Failed to add Panel, region was not set");
48971 var region = cfg.region;
48977 xitems = cfg.items;
48984 case 'ContentPanel': // ContentPanel (el, cfg)
48985 case 'ScrollPanel': // ContentPanel (el, cfg)
48987 if(cfg.autoCreate) {
48988 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
48990 var el = this.el.createChild();
48991 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
48994 this.add(region, ret);
48998 case 'TreePanel': // our new panel!
48999 cfg.el = this.el.createChild();
49000 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49001 this.add(region, ret);
49004 case 'NestedLayoutPanel':
49005 // create a new Layout (which is a Border Layout...
49006 var el = this.el.createChild();
49007 var clayout = cfg.layout;
49009 clayout.items = clayout.items || [];
49010 // replace this exitems with the clayout ones..
49011 xitems = clayout.items;
49014 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49015 cfg.background = false;
49017 var layout = new Roo.BorderLayout(el, clayout);
49019 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49020 //console.log('adding nested layout panel ' + cfg.toSource());
49021 this.add(region, ret);
49022 nb = {}; /// find first...
49027 // needs grid and region
49029 //var el = this.getRegion(region).el.createChild();
49030 var el = this.el.createChild();
49031 // create the grid first...
49033 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49035 if (region == 'center' && this.active ) {
49036 cfg.background = false;
49038 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49040 this.add(region, ret);
49041 if (cfg.background) {
49042 ret.on('activate', function(gp) {
49043 if (!gp.grid.rendered) {
49058 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49060 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49061 this.add(region, ret);
49064 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49068 // GridPanel (grid, cfg)
49071 this.beginUpdate();
49075 Roo.each(xitems, function(i) {
49076 region = nb && i.region ? i.region : false;
49078 var add = ret.addxtype(i);
49081 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49082 if (!i.background) {
49083 abn[region] = nb[region] ;
49090 // make the last non-background panel active..
49091 //if (nb) { Roo.log(abn); }
49094 for(var r in abn) {
49095 region = this.getRegion(r);
49097 // tried using nb[r], but it does not work..
49099 region.showPanel(abn[r]);
49110 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49111 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49112 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49113 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49116 var CP = Roo.ContentPanel;
49118 var layout = Roo.BorderLayout.create({
49122 panels: [new CP("north", "North")]
49131 panels: [new CP("west", {title: "West"})]
49140 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49149 panels: [new CP("south", {title: "South", closable: true})]
49156 preferredTabWidth: 150,
49158 new CP("center1", {title: "Close Me", closable: true}),
49159 new CP("center2", {title: "Center Panel", closable: false})
49164 layout.getRegion("center").showPanel("center1");
49169 Roo.BorderLayout.create = function(config, targetEl){
49170 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49171 layout.beginUpdate();
49172 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49173 for(var j = 0, jlen = regions.length; j < jlen; j++){
49174 var lr = regions[j];
49175 if(layout.regions[lr] && config[lr].panels){
49176 var r = layout.regions[lr];
49177 var ps = config[lr].panels;
49178 layout.addTypedPanels(r, ps);
49181 layout.endUpdate();
49186 Roo.BorderLayout.RegionFactory = {
49188 validRegions : ["north","south","east","west","center"],
49191 create : function(target, mgr, config){
49192 target = target.toLowerCase();
49193 if(config.lightweight || config.basic){
49194 return new Roo.BasicLayoutRegion(mgr, config, target);
49198 return new Roo.NorthLayoutRegion(mgr, config);
49200 return new Roo.SouthLayoutRegion(mgr, config);
49202 return new Roo.EastLayoutRegion(mgr, config);
49204 return new Roo.WestLayoutRegion(mgr, config);
49206 return new Roo.CenterLayoutRegion(mgr, config);
49208 throw 'Layout region "'+target+'" not supported.';
49212 * Ext JS Library 1.1.1
49213 * Copyright(c) 2006-2007, Ext JS, LLC.
49215 * Originally Released Under LGPL - original licence link has changed is not relivant.
49218 * <script type="text/javascript">
49222 * @class Roo.BasicLayoutRegion
49223 * @extends Roo.util.Observable
49224 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49225 * and does not have a titlebar, tabs or any other features. All it does is size and position
49226 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49228 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49230 this.position = pos;
49233 * @scope Roo.BasicLayoutRegion
49237 * @event beforeremove
49238 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49239 * @param {Roo.LayoutRegion} this
49240 * @param {Roo.ContentPanel} panel The panel
49241 * @param {Object} e The cancel event object
49243 "beforeremove" : true,
49245 * @event invalidated
49246 * Fires when the layout for this region is changed.
49247 * @param {Roo.LayoutRegion} this
49249 "invalidated" : true,
49251 * @event visibilitychange
49252 * Fires when this region is shown or hidden
49253 * @param {Roo.LayoutRegion} this
49254 * @param {Boolean} visibility true or false
49256 "visibilitychange" : true,
49258 * @event paneladded
49259 * Fires when a panel is added.
49260 * @param {Roo.LayoutRegion} this
49261 * @param {Roo.ContentPanel} panel The panel
49263 "paneladded" : true,
49265 * @event panelremoved
49266 * Fires when a panel is removed.
49267 * @param {Roo.LayoutRegion} this
49268 * @param {Roo.ContentPanel} panel The panel
49270 "panelremoved" : true,
49273 * Fires when this region is collapsed.
49274 * @param {Roo.LayoutRegion} this
49276 "collapsed" : true,
49279 * Fires when this region is expanded.
49280 * @param {Roo.LayoutRegion} this
49285 * Fires when this region is slid into view.
49286 * @param {Roo.LayoutRegion} this
49288 "slideshow" : true,
49291 * Fires when this region slides out of view.
49292 * @param {Roo.LayoutRegion} this
49294 "slidehide" : true,
49296 * @event panelactivated
49297 * Fires when a panel is activated.
49298 * @param {Roo.LayoutRegion} this
49299 * @param {Roo.ContentPanel} panel The activated panel
49301 "panelactivated" : true,
49304 * Fires when the user resizes this region.
49305 * @param {Roo.LayoutRegion} this
49306 * @param {Number} newSize The new size (width for east/west, height for north/south)
49310 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49311 this.panels = new Roo.util.MixedCollection();
49312 this.panels.getKey = this.getPanelId.createDelegate(this);
49314 this.activePanel = null;
49315 // ensure listeners are added...
49317 if (config.listeners || config.events) {
49318 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49319 listeners : config.listeners || {},
49320 events : config.events || {}
49324 if(skipConfig !== true){
49325 this.applyConfig(config);
49329 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49330 getPanelId : function(p){
49334 applyConfig : function(config){
49335 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49336 this.config = config;
49341 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49342 * the width, for horizontal (north, south) the height.
49343 * @param {Number} newSize The new width or height
49345 resizeTo : function(newSize){
49346 var el = this.el ? this.el :
49347 (this.activePanel ? this.activePanel.getEl() : null);
49349 switch(this.position){
49352 el.setWidth(newSize);
49353 this.fireEvent("resized", this, newSize);
49357 el.setHeight(newSize);
49358 this.fireEvent("resized", this, newSize);
49364 getBox : function(){
49365 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49368 getMargins : function(){
49369 return this.margins;
49372 updateBox : function(box){
49374 var el = this.activePanel.getEl();
49375 el.dom.style.left = box.x + "px";
49376 el.dom.style.top = box.y + "px";
49377 this.activePanel.setSize(box.width, box.height);
49381 * Returns the container element for this region.
49382 * @return {Roo.Element}
49384 getEl : function(){
49385 return this.activePanel;
49389 * Returns true if this region is currently visible.
49390 * @return {Boolean}
49392 isVisible : function(){
49393 return this.activePanel ? true : false;
49396 setActivePanel : function(panel){
49397 panel = this.getPanel(panel);
49398 if(this.activePanel && this.activePanel != panel){
49399 this.activePanel.setActiveState(false);
49400 this.activePanel.getEl().setLeftTop(-10000,-10000);
49402 this.activePanel = panel;
49403 panel.setActiveState(true);
49405 panel.setSize(this.box.width, this.box.height);
49407 this.fireEvent("panelactivated", this, panel);
49408 this.fireEvent("invalidated");
49412 * Show the specified panel.
49413 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49414 * @return {Roo.ContentPanel} The shown panel or null
49416 showPanel : function(panel){
49417 if(panel = this.getPanel(panel)){
49418 this.setActivePanel(panel);
49424 * Get the active panel for this region.
49425 * @return {Roo.ContentPanel} The active panel or null
49427 getActivePanel : function(){
49428 return this.activePanel;
49432 * Add the passed ContentPanel(s)
49433 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49434 * @return {Roo.ContentPanel} The panel added (if only one was added)
49436 add : function(panel){
49437 if(arguments.length > 1){
49438 for(var i = 0, len = arguments.length; i < len; i++) {
49439 this.add(arguments[i]);
49443 if(this.hasPanel(panel)){
49444 this.showPanel(panel);
49447 var el = panel.getEl();
49448 if(el.dom.parentNode != this.mgr.el.dom){
49449 this.mgr.el.dom.appendChild(el.dom);
49451 if(panel.setRegion){
49452 panel.setRegion(this);
49454 this.panels.add(panel);
49455 el.setStyle("position", "absolute");
49456 if(!panel.background){
49457 this.setActivePanel(panel);
49458 if(this.config.initialSize && this.panels.getCount()==1){
49459 this.resizeTo(this.config.initialSize);
49462 this.fireEvent("paneladded", this, panel);
49467 * Returns true if the panel is in this region.
49468 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49469 * @return {Boolean}
49471 hasPanel : function(panel){
49472 if(typeof panel == "object"){ // must be panel obj
49473 panel = panel.getId();
49475 return this.getPanel(panel) ? true : false;
49479 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
49480 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49481 * @param {Boolean} preservePanel Overrides the config preservePanel option
49482 * @return {Roo.ContentPanel} The panel that was removed
49484 remove : function(panel, preservePanel){
49485 panel = this.getPanel(panel);
49490 this.fireEvent("beforeremove", this, panel, e);
49491 if(e.cancel === true){
49494 var panelId = panel.getId();
49495 this.panels.removeKey(panelId);
49500 * Returns the panel specified or null if it's not in this region.
49501 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
49502 * @return {Roo.ContentPanel}
49504 getPanel : function(id){
49505 if(typeof id == "object"){ // must be panel obj
49508 return this.panels.get(id);
49512 * Returns this regions position (north/south/east/west/center).
49515 getPosition: function(){
49516 return this.position;
49520 * Ext JS Library 1.1.1
49521 * Copyright(c) 2006-2007, Ext JS, LLC.
49523 * Originally Released Under LGPL - original licence link has changed is not relivant.
49526 * <script type="text/javascript">
49530 * @class Roo.LayoutRegion
49531 * @extends Roo.BasicLayoutRegion
49532 * This class represents a region in a layout manager.
49533 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
49534 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
49535 * @cfg {Boolean} floatable False to disable floating (defaults to true)
49536 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
49537 * @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})
49538 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
49539 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
49540 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
49541 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
49542 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
49543 * @cfg {String} title The title for the region (overrides panel titles)
49544 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
49545 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
49546 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
49547 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
49548 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
49549 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
49550 * the space available, similar to FireFox 1.5 tabs (defaults to false)
49551 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
49552 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
49553 * @cfg {Boolean} showPin True to show a pin button
49554 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
49555 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
49556 * @cfg {Boolean} disableTabTips True to disable tab tooltips
49557 * @cfg {Number} width For East/West panels
49558 * @cfg {Number} height For North/South panels
49559 * @cfg {Boolean} split To show the splitter
49560 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
49562 Roo.LayoutRegion = function(mgr, config, pos){
49563 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
49564 var dh = Roo.DomHelper;
49565 /** This region's container element
49566 * @type Roo.Element */
49567 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
49568 /** This region's title element
49569 * @type Roo.Element */
49571 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
49572 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
49573 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
49575 this.titleEl.enableDisplayMode();
49576 /** This region's title text element
49577 * @type HTMLElement */
49578 this.titleTextEl = this.titleEl.dom.firstChild;
49579 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
49580 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
49581 this.closeBtn.enableDisplayMode();
49582 this.closeBtn.on("click", this.closeClicked, this);
49583 this.closeBtn.hide();
49585 this.createBody(config);
49586 this.visible = true;
49587 this.collapsed = false;
49589 if(config.hideWhenEmpty){
49591 this.on("paneladded", this.validateVisibility, this);
49592 this.on("panelremoved", this.validateVisibility, this);
49594 this.applyConfig(config);
49597 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
49599 createBody : function(){
49600 /** This region's body element
49601 * @type Roo.Element */
49602 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
49605 applyConfig : function(c){
49606 if(c.collapsible && this.position != "center" && !this.collapsedEl){
49607 var dh = Roo.DomHelper;
49608 if(c.titlebar !== false){
49609 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
49610 this.collapseBtn.on("click", this.collapse, this);
49611 this.collapseBtn.enableDisplayMode();
49613 if(c.showPin === true || this.showPin){
49614 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
49615 this.stickBtn.enableDisplayMode();
49616 this.stickBtn.on("click", this.expand, this);
49617 this.stickBtn.hide();
49620 /** This region's collapsed element
49621 * @type Roo.Element */
49622 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
49623 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
49625 if(c.floatable !== false){
49626 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
49627 this.collapsedEl.on("click", this.collapseClick, this);
49630 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
49631 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
49632 id: "message", unselectable: "on", style:{"float":"left"}});
49633 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
49635 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
49636 this.expandBtn.on("click", this.expand, this);
49638 if(this.collapseBtn){
49639 this.collapseBtn.setVisible(c.collapsible == true);
49641 this.cmargins = c.cmargins || this.cmargins ||
49642 (this.position == "west" || this.position == "east" ?
49643 {top: 0, left: 2, right:2, bottom: 0} :
49644 {top: 2, left: 0, right:0, bottom: 2});
49645 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49646 this.bottomTabs = c.tabPosition != "top";
49647 this.autoScroll = c.autoScroll || false;
49648 if(this.autoScroll){
49649 this.bodyEl.setStyle("overflow", "auto");
49651 this.bodyEl.setStyle("overflow", "hidden");
49653 //if(c.titlebar !== false){
49654 if((!c.titlebar && !c.title) || c.titlebar === false){
49655 this.titleEl.hide();
49657 this.titleEl.show();
49659 this.titleTextEl.innerHTML = c.title;
49663 this.duration = c.duration || .30;
49664 this.slideDuration = c.slideDuration || .45;
49667 this.collapse(true);
49674 * Returns true if this region is currently visible.
49675 * @return {Boolean}
49677 isVisible : function(){
49678 return this.visible;
49682 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
49683 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
49685 setCollapsedTitle : function(title){
49686 title = title || " ";
49687 if(this.collapsedTitleTextEl){
49688 this.collapsedTitleTextEl.innerHTML = title;
49692 getBox : function(){
49694 if(!this.collapsed){
49695 b = this.el.getBox(false, true);
49697 b = this.collapsedEl.getBox(false, true);
49702 getMargins : function(){
49703 return this.collapsed ? this.cmargins : this.margins;
49706 highlight : function(){
49707 this.el.addClass("x-layout-panel-dragover");
49710 unhighlight : function(){
49711 this.el.removeClass("x-layout-panel-dragover");
49714 updateBox : function(box){
49716 if(!this.collapsed){
49717 this.el.dom.style.left = box.x + "px";
49718 this.el.dom.style.top = box.y + "px";
49719 this.updateBody(box.width, box.height);
49721 this.collapsedEl.dom.style.left = box.x + "px";
49722 this.collapsedEl.dom.style.top = box.y + "px";
49723 this.collapsedEl.setSize(box.width, box.height);
49726 this.tabs.autoSizeTabs();
49730 updateBody : function(w, h){
49732 this.el.setWidth(w);
49733 w -= this.el.getBorderWidth("rl");
49734 if(this.config.adjustments){
49735 w += this.config.adjustments[0];
49739 this.el.setHeight(h);
49740 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
49741 h -= this.el.getBorderWidth("tb");
49742 if(this.config.adjustments){
49743 h += this.config.adjustments[1];
49745 this.bodyEl.setHeight(h);
49747 h = this.tabs.syncHeight(h);
49750 if(this.panelSize){
49751 w = w !== null ? w : this.panelSize.width;
49752 h = h !== null ? h : this.panelSize.height;
49754 if(this.activePanel){
49755 var el = this.activePanel.getEl();
49756 w = w !== null ? w : el.getWidth();
49757 h = h !== null ? h : el.getHeight();
49758 this.panelSize = {width: w, height: h};
49759 this.activePanel.setSize(w, h);
49761 if(Roo.isIE && this.tabs){
49762 this.tabs.el.repaint();
49767 * Returns the container element for this region.
49768 * @return {Roo.Element}
49770 getEl : function(){
49775 * Hides this region.
49778 if(!this.collapsed){
49779 this.el.dom.style.left = "-2000px";
49782 this.collapsedEl.dom.style.left = "-2000px";
49783 this.collapsedEl.hide();
49785 this.visible = false;
49786 this.fireEvent("visibilitychange", this, false);
49790 * Shows this region if it was previously hidden.
49793 if(!this.collapsed){
49796 this.collapsedEl.show();
49798 this.visible = true;
49799 this.fireEvent("visibilitychange", this, true);
49802 closeClicked : function(){
49803 if(this.activePanel){
49804 this.remove(this.activePanel);
49808 collapseClick : function(e){
49810 e.stopPropagation();
49813 e.stopPropagation();
49819 * Collapses this region.
49820 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
49822 collapse : function(skipAnim){
49823 if(this.collapsed) return;
49824 this.collapsed = true;
49826 this.split.el.hide();
49828 if(this.config.animate && skipAnim !== true){
49829 this.fireEvent("invalidated", this);
49830 this.animateCollapse();
49832 this.el.setLocation(-20000,-20000);
49834 this.collapsedEl.show();
49835 this.fireEvent("collapsed", this);
49836 this.fireEvent("invalidated", this);
49840 animateCollapse : function(){
49845 * Expands this region if it was previously collapsed.
49846 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
49847 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
49849 expand : function(e, skipAnim){
49850 if(e) e.stopPropagation();
49851 if(!this.collapsed || this.el.hasActiveFx()) return;
49853 this.afterSlideIn();
49856 this.collapsed = false;
49857 if(this.config.animate && skipAnim !== true){
49858 this.animateExpand();
49862 this.split.el.show();
49864 this.collapsedEl.setLocation(-2000,-2000);
49865 this.collapsedEl.hide();
49866 this.fireEvent("invalidated", this);
49867 this.fireEvent("expanded", this);
49871 animateExpand : function(){
49875 initTabs : function()
49877 this.bodyEl.setStyle("overflow", "hidden");
49878 var ts = new Roo.TabPanel(
49881 tabPosition: this.bottomTabs ? 'bottom' : 'top',
49882 disableTooltips: this.config.disableTabTips,
49883 toolbar : this.config.toolbar
49886 if(this.config.hideTabs){
49887 ts.stripWrap.setDisplayed(false);
49890 ts.resizeTabs = this.config.resizeTabs === true;
49891 ts.minTabWidth = this.config.minTabWidth || 40;
49892 ts.maxTabWidth = this.config.maxTabWidth || 250;
49893 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
49894 ts.monitorResize = false;
49895 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
49896 ts.bodyEl.addClass('x-layout-tabs-body');
49897 this.panels.each(this.initPanelAsTab, this);
49900 initPanelAsTab : function(panel){
49901 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
49902 this.config.closeOnTab && panel.isClosable());
49903 if(panel.tabTip !== undefined){
49904 ti.setTooltip(panel.tabTip);
49906 ti.on("activate", function(){
49907 this.setActivePanel(panel);
49909 if(this.config.closeOnTab){
49910 ti.on("beforeclose", function(t, e){
49912 this.remove(panel);
49918 updatePanelTitle : function(panel, title){
49919 if(this.activePanel == panel){
49920 this.updateTitle(title);
49923 var ti = this.tabs.getTab(panel.getEl().id);
49925 if(panel.tabTip !== undefined){
49926 ti.setTooltip(panel.tabTip);
49931 updateTitle : function(title){
49932 if(this.titleTextEl && !this.config.title){
49933 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
49937 setActivePanel : function(panel){
49938 panel = this.getPanel(panel);
49939 if(this.activePanel && this.activePanel != panel){
49940 this.activePanel.setActiveState(false);
49942 this.activePanel = panel;
49943 panel.setActiveState(true);
49944 if(this.panelSize){
49945 panel.setSize(this.panelSize.width, this.panelSize.height);
49948 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
49950 this.updateTitle(panel.getTitle());
49952 this.fireEvent("invalidated", this);
49954 this.fireEvent("panelactivated", this, panel);
49958 * Shows the specified panel.
49959 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
49960 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
49962 showPanel : function(panel){
49963 if(panel = this.getPanel(panel)){
49965 var tab = this.tabs.getTab(panel.getEl().id);
49966 if(tab.isHidden()){
49967 this.tabs.unhideTab(tab.id);
49971 this.setActivePanel(panel);
49978 * Get the active panel for this region.
49979 * @return {Roo.ContentPanel} The active panel or null
49981 getActivePanel : function(){
49982 return this.activePanel;
49985 validateVisibility : function(){
49986 if(this.panels.getCount() < 1){
49987 this.updateTitle(" ");
49988 this.closeBtn.hide();
49991 if(!this.isVisible()){
49998 * Adds the passed ContentPanel(s) to this region.
49999 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50000 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50002 add : function(panel){
50003 if(arguments.length > 1){
50004 for(var i = 0, len = arguments.length; i < len; i++) {
50005 this.add(arguments[i]);
50009 if(this.hasPanel(panel)){
50010 this.showPanel(panel);
50013 panel.setRegion(this);
50014 this.panels.add(panel);
50015 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50016 this.bodyEl.dom.appendChild(panel.getEl().dom);
50017 if(panel.background !== true){
50018 this.setActivePanel(panel);
50020 this.fireEvent("paneladded", this, panel);
50026 this.initPanelAsTab(panel);
50028 if(panel.background !== true){
50029 this.tabs.activate(panel.getEl().id);
50031 this.fireEvent("paneladded", this, panel);
50036 * Hides the tab for the specified panel.
50037 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50039 hidePanel : function(panel){
50040 if(this.tabs && (panel = this.getPanel(panel))){
50041 this.tabs.hideTab(panel.getEl().id);
50046 * Unhides the tab for a previously hidden panel.
50047 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50049 unhidePanel : function(panel){
50050 if(this.tabs && (panel = this.getPanel(panel))){
50051 this.tabs.unhideTab(panel.getEl().id);
50055 clearPanels : function(){
50056 while(this.panels.getCount() > 0){
50057 this.remove(this.panels.first());
50062 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50063 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50064 * @param {Boolean} preservePanel Overrides the config preservePanel option
50065 * @return {Roo.ContentPanel} The panel that was removed
50067 remove : function(panel, preservePanel){
50068 panel = this.getPanel(panel);
50073 this.fireEvent("beforeremove", this, panel, e);
50074 if(e.cancel === true){
50077 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50078 var panelId = panel.getId();
50079 this.panels.removeKey(panelId);
50081 document.body.appendChild(panel.getEl().dom);
50084 this.tabs.removeTab(panel.getEl().id);
50085 }else if (!preservePanel){
50086 this.bodyEl.dom.removeChild(panel.getEl().dom);
50088 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50089 var p = this.panels.first();
50090 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50091 tempEl.appendChild(p.getEl().dom);
50092 this.bodyEl.update("");
50093 this.bodyEl.dom.appendChild(p.getEl().dom);
50095 this.updateTitle(p.getTitle());
50097 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50098 this.setActivePanel(p);
50100 panel.setRegion(null);
50101 if(this.activePanel == panel){
50102 this.activePanel = null;
50104 if(this.config.autoDestroy !== false && preservePanel !== true){
50105 try{panel.destroy();}catch(e){}
50107 this.fireEvent("panelremoved", this, panel);
50112 * Returns the TabPanel component used by this region
50113 * @return {Roo.TabPanel}
50115 getTabs : function(){
50119 createTool : function(parentEl, className){
50120 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50121 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50122 btn.addClassOnOver("x-layout-tools-button-over");
50127 * Ext JS Library 1.1.1
50128 * Copyright(c) 2006-2007, Ext JS, LLC.
50130 * Originally Released Under LGPL - original licence link has changed is not relivant.
50133 * <script type="text/javascript">
50139 * @class Roo.SplitLayoutRegion
50140 * @extends Roo.LayoutRegion
50141 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50143 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50144 this.cursor = cursor;
50145 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50148 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50149 splitTip : "Drag to resize.",
50150 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50151 useSplitTips : false,
50153 applyConfig : function(config){
50154 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50157 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50158 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50159 /** The SplitBar for this region
50160 * @type Roo.SplitBar */
50161 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50162 this.split.on("moved", this.onSplitMove, this);
50163 this.split.useShim = config.useShim === true;
50164 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50165 if(this.useSplitTips){
50166 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50168 if(config.collapsible){
50169 this.split.el.on("dblclick", this.collapse, this);
50172 if(typeof config.minSize != "undefined"){
50173 this.split.minSize = config.minSize;
50175 if(typeof config.maxSize != "undefined"){
50176 this.split.maxSize = config.maxSize;
50178 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50179 this.hideSplitter();
50184 getHMaxSize : function(){
50185 var cmax = this.config.maxSize || 10000;
50186 var center = this.mgr.getRegion("center");
50187 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50190 getVMaxSize : function(){
50191 var cmax = this.config.maxSize || 10000;
50192 var center = this.mgr.getRegion("center");
50193 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50196 onSplitMove : function(split, newSize){
50197 this.fireEvent("resized", this, newSize);
50201 * Returns the {@link Roo.SplitBar} for this region.
50202 * @return {Roo.SplitBar}
50204 getSplitBar : function(){
50209 this.hideSplitter();
50210 Roo.SplitLayoutRegion.superclass.hide.call(this);
50213 hideSplitter : function(){
50215 this.split.el.setLocation(-2000,-2000);
50216 this.split.el.hide();
50222 this.split.el.show();
50224 Roo.SplitLayoutRegion.superclass.show.call(this);
50227 beforeSlide: function(){
50228 if(Roo.isGecko){// firefox overflow auto bug workaround
50229 this.bodyEl.clip();
50230 if(this.tabs) this.tabs.bodyEl.clip();
50231 if(this.activePanel){
50232 this.activePanel.getEl().clip();
50234 if(this.activePanel.beforeSlide){
50235 this.activePanel.beforeSlide();
50241 afterSlide : function(){
50242 if(Roo.isGecko){// firefox overflow auto bug workaround
50243 this.bodyEl.unclip();
50244 if(this.tabs) this.tabs.bodyEl.unclip();
50245 if(this.activePanel){
50246 this.activePanel.getEl().unclip();
50247 if(this.activePanel.afterSlide){
50248 this.activePanel.afterSlide();
50254 initAutoHide : function(){
50255 if(this.autoHide !== false){
50256 if(!this.autoHideHd){
50257 var st = new Roo.util.DelayedTask(this.slideIn, this);
50258 this.autoHideHd = {
50259 "mouseout": function(e){
50260 if(!e.within(this.el, true)){
50264 "mouseover" : function(e){
50270 this.el.on(this.autoHideHd);
50274 clearAutoHide : function(){
50275 if(this.autoHide !== false){
50276 this.el.un("mouseout", this.autoHideHd.mouseout);
50277 this.el.un("mouseover", this.autoHideHd.mouseover);
50281 clearMonitor : function(){
50282 Roo.get(document).un("click", this.slideInIf, this);
50285 // these names are backwards but not changed for compat
50286 slideOut : function(){
50287 if(this.isSlid || this.el.hasActiveFx()){
50290 this.isSlid = true;
50291 if(this.collapseBtn){
50292 this.collapseBtn.hide();
50294 this.closeBtnState = this.closeBtn.getStyle('display');
50295 this.closeBtn.hide();
50297 this.stickBtn.show();
50300 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50301 this.beforeSlide();
50302 this.el.setStyle("z-index", 10001);
50303 this.el.slideIn(this.getSlideAnchor(), {
50304 callback: function(){
50306 this.initAutoHide();
50307 Roo.get(document).on("click", this.slideInIf, this);
50308 this.fireEvent("slideshow", this);
50315 afterSlideIn : function(){
50316 this.clearAutoHide();
50317 this.isSlid = false;
50318 this.clearMonitor();
50319 this.el.setStyle("z-index", "");
50320 if(this.collapseBtn){
50321 this.collapseBtn.show();
50323 this.closeBtn.setStyle('display', this.closeBtnState);
50325 this.stickBtn.hide();
50327 this.fireEvent("slidehide", this);
50330 slideIn : function(cb){
50331 if(!this.isSlid || this.el.hasActiveFx()){
50335 this.isSlid = false;
50336 this.beforeSlide();
50337 this.el.slideOut(this.getSlideAnchor(), {
50338 callback: function(){
50339 this.el.setLeftTop(-10000, -10000);
50341 this.afterSlideIn();
50349 slideInIf : function(e){
50350 if(!e.within(this.el)){
50355 animateCollapse : function(){
50356 this.beforeSlide();
50357 this.el.setStyle("z-index", 20000);
50358 var anchor = this.getSlideAnchor();
50359 this.el.slideOut(anchor, {
50360 callback : function(){
50361 this.el.setStyle("z-index", "");
50362 this.collapsedEl.slideIn(anchor, {duration:.3});
50364 this.el.setLocation(-10000,-10000);
50366 this.fireEvent("collapsed", this);
50373 animateExpand : function(){
50374 this.beforeSlide();
50375 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50376 this.el.setStyle("z-index", 20000);
50377 this.collapsedEl.hide({
50380 this.el.slideIn(this.getSlideAnchor(), {
50381 callback : function(){
50382 this.el.setStyle("z-index", "");
50385 this.split.el.show();
50387 this.fireEvent("invalidated", this);
50388 this.fireEvent("expanded", this);
50416 getAnchor : function(){
50417 return this.anchors[this.position];
50420 getCollapseAnchor : function(){
50421 return this.canchors[this.position];
50424 getSlideAnchor : function(){
50425 return this.sanchors[this.position];
50428 getAlignAdj : function(){
50429 var cm = this.cmargins;
50430 switch(this.position){
50446 getExpandAdj : function(){
50447 var c = this.collapsedEl, cm = this.cmargins;
50448 switch(this.position){
50450 return [-(cm.right+c.getWidth()+cm.left), 0];
50453 return [cm.right+c.getWidth()+cm.left, 0];
50456 return [0, -(cm.top+cm.bottom+c.getHeight())];
50459 return [0, cm.top+cm.bottom+c.getHeight()];
50465 * Ext JS Library 1.1.1
50466 * Copyright(c) 2006-2007, Ext JS, LLC.
50468 * Originally Released Under LGPL - original licence link has changed is not relivant.
50471 * <script type="text/javascript">
50474 * These classes are private internal classes
50476 Roo.CenterLayoutRegion = function(mgr, config){
50477 Roo.LayoutRegion.call(this, mgr, config, "center");
50478 this.visible = true;
50479 this.minWidth = config.minWidth || 20;
50480 this.minHeight = config.minHeight || 20;
50483 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
50485 // center panel can't be hidden
50489 // center panel can't be hidden
50492 getMinWidth: function(){
50493 return this.minWidth;
50496 getMinHeight: function(){
50497 return this.minHeight;
50502 Roo.NorthLayoutRegion = function(mgr, config){
50503 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
50505 this.split.placement = Roo.SplitBar.TOP;
50506 this.split.orientation = Roo.SplitBar.VERTICAL;
50507 this.split.el.addClass("x-layout-split-v");
50509 var size = config.initialSize || config.height;
50510 if(typeof size != "undefined"){
50511 this.el.setHeight(size);
50514 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
50515 orientation: Roo.SplitBar.VERTICAL,
50516 getBox : function(){
50517 if(this.collapsed){
50518 return this.collapsedEl.getBox();
50520 var box = this.el.getBox();
50522 box.height += this.split.el.getHeight();
50527 updateBox : function(box){
50528 if(this.split && !this.collapsed){
50529 box.height -= this.split.el.getHeight();
50530 this.split.el.setLeft(box.x);
50531 this.split.el.setTop(box.y+box.height);
50532 this.split.el.setWidth(box.width);
50534 if(this.collapsed){
50535 this.updateBody(box.width, null);
50537 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50541 Roo.SouthLayoutRegion = function(mgr, config){
50542 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
50544 this.split.placement = Roo.SplitBar.BOTTOM;
50545 this.split.orientation = Roo.SplitBar.VERTICAL;
50546 this.split.el.addClass("x-layout-split-v");
50548 var size = config.initialSize || config.height;
50549 if(typeof size != "undefined"){
50550 this.el.setHeight(size);
50553 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
50554 orientation: Roo.SplitBar.VERTICAL,
50555 getBox : function(){
50556 if(this.collapsed){
50557 return this.collapsedEl.getBox();
50559 var box = this.el.getBox();
50561 var sh = this.split.el.getHeight();
50568 updateBox : function(box){
50569 if(this.split && !this.collapsed){
50570 var sh = this.split.el.getHeight();
50573 this.split.el.setLeft(box.x);
50574 this.split.el.setTop(box.y-sh);
50575 this.split.el.setWidth(box.width);
50577 if(this.collapsed){
50578 this.updateBody(box.width, null);
50580 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50584 Roo.EastLayoutRegion = function(mgr, config){
50585 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
50587 this.split.placement = Roo.SplitBar.RIGHT;
50588 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50589 this.split.el.addClass("x-layout-split-h");
50591 var size = config.initialSize || config.width;
50592 if(typeof size != "undefined"){
50593 this.el.setWidth(size);
50596 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
50597 orientation: Roo.SplitBar.HORIZONTAL,
50598 getBox : function(){
50599 if(this.collapsed){
50600 return this.collapsedEl.getBox();
50602 var box = this.el.getBox();
50604 var sw = this.split.el.getWidth();
50611 updateBox : function(box){
50612 if(this.split && !this.collapsed){
50613 var sw = this.split.el.getWidth();
50615 this.split.el.setLeft(box.x);
50616 this.split.el.setTop(box.y);
50617 this.split.el.setHeight(box.height);
50620 if(this.collapsed){
50621 this.updateBody(null, box.height);
50623 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50627 Roo.WestLayoutRegion = function(mgr, config){
50628 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
50630 this.split.placement = Roo.SplitBar.LEFT;
50631 this.split.orientation = Roo.SplitBar.HORIZONTAL;
50632 this.split.el.addClass("x-layout-split-h");
50634 var size = config.initialSize || config.width;
50635 if(typeof size != "undefined"){
50636 this.el.setWidth(size);
50639 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
50640 orientation: Roo.SplitBar.HORIZONTAL,
50641 getBox : function(){
50642 if(this.collapsed){
50643 return this.collapsedEl.getBox();
50645 var box = this.el.getBox();
50647 box.width += this.split.el.getWidth();
50652 updateBox : function(box){
50653 if(this.split && !this.collapsed){
50654 var sw = this.split.el.getWidth();
50656 this.split.el.setLeft(box.x+box.width);
50657 this.split.el.setTop(box.y);
50658 this.split.el.setHeight(box.height);
50660 if(this.collapsed){
50661 this.updateBody(null, box.height);
50663 Roo.LayoutRegion.prototype.updateBox.call(this, box);
50668 * Ext JS Library 1.1.1
50669 * Copyright(c) 2006-2007, Ext JS, LLC.
50671 * Originally Released Under LGPL - original licence link has changed is not relivant.
50674 * <script type="text/javascript">
50679 * Private internal class for reading and applying state
50681 Roo.LayoutStateManager = function(layout){
50682 // default empty state
50691 Roo.LayoutStateManager.prototype = {
50692 init : function(layout, provider){
50693 this.provider = provider;
50694 var state = provider.get(layout.id+"-layout-state");
50696 var wasUpdating = layout.isUpdating();
50698 layout.beginUpdate();
50700 for(var key in state){
50701 if(typeof state[key] != "function"){
50702 var rstate = state[key];
50703 var r = layout.getRegion(key);
50706 r.resizeTo(rstate.size);
50708 if(rstate.collapsed == true){
50711 r.expand(null, true);
50717 layout.endUpdate();
50719 this.state = state;
50721 this.layout = layout;
50722 layout.on("regionresized", this.onRegionResized, this);
50723 layout.on("regioncollapsed", this.onRegionCollapsed, this);
50724 layout.on("regionexpanded", this.onRegionExpanded, this);
50727 storeState : function(){
50728 this.provider.set(this.layout.id+"-layout-state", this.state);
50731 onRegionResized : function(region, newSize){
50732 this.state[region.getPosition()].size = newSize;
50736 onRegionCollapsed : function(region){
50737 this.state[region.getPosition()].collapsed = true;
50741 onRegionExpanded : function(region){
50742 this.state[region.getPosition()].collapsed = false;
50747 * Ext JS Library 1.1.1
50748 * Copyright(c) 2006-2007, Ext JS, LLC.
50750 * Originally Released Under LGPL - original licence link has changed is not relivant.
50753 * <script type="text/javascript">
50756 * @class Roo.ContentPanel
50757 * @extends Roo.util.Observable
50758 * A basic ContentPanel element.
50759 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
50760 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
50761 * @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
50762 * @cfg {Boolean} closable True if the panel can be closed/removed
50763 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
50764 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
50765 * @cfg {Toolbar} toolbar A toolbar for this panel
50766 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
50767 * @cfg {String} title The title for this panel
50768 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
50769 * @cfg {String} url Calls {@link #setUrl} with this value
50770 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
50771 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
50772 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
50773 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
50776 * Create a new ContentPanel.
50777 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
50778 * @param {String/Object} config A string to set only the title or a config object
50779 * @param {String} content (optional) Set the HTML content for this panel
50780 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
50782 Roo.ContentPanel = function(el, config, content){
50786 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
50790 if (config && config.parentLayout) {
50791 el = config.parentLayout.el.createChild();
50794 if(el.autoCreate){ // xtype is available if this is called from factory
50798 this.el = Roo.get(el);
50799 if(!this.el && config && config.autoCreate){
50800 if(typeof config.autoCreate == "object"){
50801 if(!config.autoCreate.id){
50802 config.autoCreate.id = config.id||el;
50804 this.el = Roo.DomHelper.append(document.body,
50805 config.autoCreate, true);
50807 this.el = Roo.DomHelper.append(document.body,
50808 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
50811 this.closable = false;
50812 this.loaded = false;
50813 this.active = false;
50814 if(typeof config == "string"){
50815 this.title = config;
50817 Roo.apply(this, config);
50820 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
50821 this.wrapEl = this.el.wrap();
50822 this.toolbar.container = this.el.insertSibling(false, 'before');
50823 this.toolbar = new Roo.Toolbar(this.toolbar);
50826 // xtype created footer. - not sure if will work as we normally have to render first..
50827 if (this.footer && !this.footer.el && this.footer.xtype) {
50828 if (!this.wrapEl) {
50829 this.wrapEl = this.el.wrap();
50832 this.footer.container = this.wrapEl.createChild();
50834 this.footer = Roo.factory(this.footer, Roo);
50839 this.resizeEl = Roo.get(this.resizeEl, true);
50841 this.resizeEl = this.el;
50843 // handle view.xtype
50851 * Fires when this panel is activated.
50852 * @param {Roo.ContentPanel} this
50856 * @event deactivate
50857 * Fires when this panel is activated.
50858 * @param {Roo.ContentPanel} this
50860 "deactivate" : true,
50864 * Fires when this panel is resized if fitToFrame is true.
50865 * @param {Roo.ContentPanel} this
50866 * @param {Number} width The width after any component adjustments
50867 * @param {Number} height The height after any component adjustments
50873 * Fires when this tab is created
50874 * @param {Roo.ContentPanel} this
50885 if(this.autoScroll){
50886 this.resizeEl.setStyle("overflow", "auto");
50888 // fix randome scrolling
50889 this.el.on('scroll', function() {
50890 Roo.log('fix random scolling');
50891 this.scrollTo('top',0);
50894 content = content || this.content;
50896 this.setContent(content);
50898 if(config && config.url){
50899 this.setUrl(this.url, this.params, this.loadOnce);
50904 Roo.ContentPanel.superclass.constructor.call(this);
50906 if (this.view && typeof(this.view.xtype) != 'undefined') {
50907 this.view.el = this.el.appendChild(document.createElement("div"));
50908 this.view = Roo.factory(this.view);
50909 this.view.render && this.view.render(false, '');
50913 this.fireEvent('render', this);
50916 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
50918 setRegion : function(region){
50919 this.region = region;
50921 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
50923 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
50928 * Returns the toolbar for this Panel if one was configured.
50929 * @return {Roo.Toolbar}
50931 getToolbar : function(){
50932 return this.toolbar;
50935 setActiveState : function(active){
50936 this.active = active;
50938 this.fireEvent("deactivate", this);
50940 this.fireEvent("activate", this);
50944 * Updates this panel's element
50945 * @param {String} content The new content
50946 * @param {Boolean} loadScripts (optional) true to look for and process scripts
50948 setContent : function(content, loadScripts){
50949 this.el.update(content, loadScripts);
50952 ignoreResize : function(w, h){
50953 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
50956 this.lastSize = {width: w, height: h};
50961 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
50962 * @return {Roo.UpdateManager} The UpdateManager
50964 getUpdateManager : function(){
50965 return this.el.getUpdateManager();
50968 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
50969 * @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:
50972 url: "your-url.php",
50973 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
50974 callback: yourFunction,
50975 scope: yourObject, //(optional scope)
50978 text: "Loading...",
50983 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
50984 * 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.
50985 * @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}
50986 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
50987 * @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.
50988 * @return {Roo.ContentPanel} this
50991 var um = this.el.getUpdateManager();
50992 um.update.apply(um, arguments);
50998 * 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.
50999 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51000 * @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)
51001 * @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)
51002 * @return {Roo.UpdateManager} The UpdateManager
51004 setUrl : function(url, params, loadOnce){
51005 if(this.refreshDelegate){
51006 this.removeListener("activate", this.refreshDelegate);
51008 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51009 this.on("activate", this.refreshDelegate);
51010 return this.el.getUpdateManager();
51013 _handleRefresh : function(url, params, loadOnce){
51014 if(!loadOnce || !this.loaded){
51015 var updater = this.el.getUpdateManager();
51016 updater.update(url, params, this._setLoaded.createDelegate(this));
51020 _setLoaded : function(){
51021 this.loaded = true;
51025 * Returns this panel's id
51028 getId : function(){
51033 * Returns this panel's element - used by regiosn to add.
51034 * @return {Roo.Element}
51036 getEl : function(){
51037 return this.wrapEl || this.el;
51040 adjustForComponents : function(width, height)
51042 //Roo.log('adjustForComponents ');
51043 if(this.resizeEl != this.el){
51044 width -= this.el.getFrameWidth('lr');
51045 height -= this.el.getFrameWidth('tb');
51048 var te = this.toolbar.getEl();
51049 height -= te.getHeight();
51050 te.setWidth(width);
51053 var te = this.footer.getEl();
51054 Roo.log("footer:" + te.getHeight());
51056 height -= te.getHeight();
51057 te.setWidth(width);
51061 if(this.adjustments){
51062 width += this.adjustments[0];
51063 height += this.adjustments[1];
51065 return {"width": width, "height": height};
51068 setSize : function(width, height){
51069 if(this.fitToFrame && !this.ignoreResize(width, height)){
51070 if(this.fitContainer && this.resizeEl != this.el){
51071 this.el.setSize(width, height);
51073 var size = this.adjustForComponents(width, height);
51074 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51075 this.fireEvent('resize', this, size.width, size.height);
51080 * Returns this panel's title
51083 getTitle : function(){
51088 * Set this panel's title
51089 * @param {String} title
51091 setTitle : function(title){
51092 this.title = title;
51094 this.region.updatePanelTitle(this, title);
51099 * Returns true is this panel was configured to be closable
51100 * @return {Boolean}
51102 isClosable : function(){
51103 return this.closable;
51106 beforeSlide : function(){
51108 this.resizeEl.clip();
51111 afterSlide : function(){
51113 this.resizeEl.unclip();
51117 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51118 * Will fail silently if the {@link #setUrl} method has not been called.
51119 * This does not activate the panel, just updates its content.
51121 refresh : function(){
51122 if(this.refreshDelegate){
51123 this.loaded = false;
51124 this.refreshDelegate();
51129 * Destroys this panel
51131 destroy : function(){
51132 this.el.removeAllListeners();
51133 var tempEl = document.createElement("span");
51134 tempEl.appendChild(this.el.dom);
51135 tempEl.innerHTML = "";
51141 * form - if the content panel contains a form - this is a reference to it.
51142 * @type {Roo.form.Form}
51146 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51147 * This contains a reference to it.
51153 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51163 * @param {Object} cfg Xtype definition of item to add.
51166 addxtype : function(cfg) {
51168 if (cfg.xtype.match(/^Form$/)) {
51171 //if (this.footer) {
51172 // el = this.footer.container.insertSibling(false, 'before');
51174 el = this.el.createChild();
51177 this.form = new Roo.form.Form(cfg);
51180 if ( this.form.allItems.length) this.form.render(el.dom);
51183 // should only have one of theses..
51184 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51185 // views.. should not be just added - used named prop 'view''
51187 cfg.el = this.el.appendChild(document.createElement("div"));
51190 var ret = new Roo.factory(cfg);
51192 ret.render && ret.render(false, ''); // render blank..
51201 * @class Roo.GridPanel
51202 * @extends Roo.ContentPanel
51204 * Create a new GridPanel.
51205 * @param {Roo.grid.Grid} grid The grid for this panel
51206 * @param {String/Object} config A string to set only the panel's title, or a config object
51208 Roo.GridPanel = function(grid, config){
51211 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51212 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51214 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51216 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51219 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51221 // xtype created footer. - not sure if will work as we normally have to render first..
51222 if (this.footer && !this.footer.el && this.footer.xtype) {
51224 this.footer.container = this.grid.getView().getFooterPanel(true);
51225 this.footer.dataSource = this.grid.dataSource;
51226 this.footer = Roo.factory(this.footer, Roo);
51230 grid.monitorWindowResize = false; // turn off autosizing
51231 grid.autoHeight = false;
51232 grid.autoWidth = false;
51234 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51237 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51238 getId : function(){
51239 return this.grid.id;
51243 * Returns the grid for this panel
51244 * @return {Roo.grid.Grid}
51246 getGrid : function(){
51250 setSize : function(width, height){
51251 if(!this.ignoreResize(width, height)){
51252 var grid = this.grid;
51253 var size = this.adjustForComponents(width, height);
51254 grid.getGridEl().setSize(size.width, size.height);
51259 beforeSlide : function(){
51260 this.grid.getView().scroller.clip();
51263 afterSlide : function(){
51264 this.grid.getView().scroller.unclip();
51267 destroy : function(){
51268 this.grid.destroy();
51270 Roo.GridPanel.superclass.destroy.call(this);
51276 * @class Roo.NestedLayoutPanel
51277 * @extends Roo.ContentPanel
51279 * Create a new NestedLayoutPanel.
51282 * @param {Roo.BorderLayout} layout The layout for this panel
51283 * @param {String/Object} config A string to set only the title or a config object
51285 Roo.NestedLayoutPanel = function(layout, config)
51287 // construct with only one argument..
51288 /* FIXME - implement nicer consturctors
51289 if (layout.layout) {
51291 layout = config.layout;
51292 delete config.layout;
51294 if (layout.xtype && !layout.getEl) {
51295 // then layout needs constructing..
51296 layout = Roo.factory(layout, Roo);
51301 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51303 layout.monitorWindowResize = false; // turn off autosizing
51304 this.layout = layout;
51305 this.layout.getEl().addClass("x-layout-nested-layout");
51312 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51314 setSize : function(width, height){
51315 if(!this.ignoreResize(width, height)){
51316 var size = this.adjustForComponents(width, height);
51317 var el = this.layout.getEl();
51318 el.setSize(size.width, size.height);
51319 var touch = el.dom.offsetWidth;
51320 this.layout.layout();
51321 // ie requires a double layout on the first pass
51322 if(Roo.isIE && !this.initialized){
51323 this.initialized = true;
51324 this.layout.layout();
51329 // activate all subpanels if not currently active..
51331 setActiveState : function(active){
51332 this.active = active;
51334 this.fireEvent("deactivate", this);
51338 this.fireEvent("activate", this);
51339 // not sure if this should happen before or after..
51340 if (!this.layout) {
51341 return; // should not happen..
51344 for (var r in this.layout.regions) {
51345 reg = this.layout.getRegion(r);
51346 if (reg.getActivePanel()) {
51347 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51348 reg.setActivePanel(reg.getActivePanel());
51351 if (!reg.panels.length) {
51354 reg.showPanel(reg.getPanel(0));
51363 * Returns the nested BorderLayout for this panel
51364 * @return {Roo.BorderLayout}
51366 getLayout : function(){
51367 return this.layout;
51371 * Adds a xtype elements to the layout of the nested panel
51375 xtype : 'ContentPanel',
51382 xtype : 'NestedLayoutPanel',
51388 items : [ ... list of content panels or nested layout panels.. ]
51392 * @param {Object} cfg Xtype definition of item to add.
51394 addxtype : function(cfg) {
51395 return this.layout.addxtype(cfg);
51400 Roo.ScrollPanel = function(el, config, content){
51401 config = config || {};
51402 config.fitToFrame = true;
51403 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51405 this.el.dom.style.overflow = "hidden";
51406 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51407 this.el.removeClass("x-layout-inactive-content");
51408 this.el.on("mousewheel", this.onWheel, this);
51410 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51411 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51412 up.unselectable(); down.unselectable();
51413 up.on("click", this.scrollUp, this);
51414 down.on("click", this.scrollDown, this);
51415 up.addClassOnOver("x-scroller-btn-over");
51416 down.addClassOnOver("x-scroller-btn-over");
51417 up.addClassOnClick("x-scroller-btn-click");
51418 down.addClassOnClick("x-scroller-btn-click");
51419 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51421 this.resizeEl = this.el;
51422 this.el = wrap; this.up = up; this.down = down;
51425 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51427 wheelIncrement : 5,
51428 scrollUp : function(){
51429 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51432 scrollDown : function(){
51433 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51436 afterScroll : function(){
51437 var el = this.resizeEl;
51438 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
51439 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51440 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
51443 setSize : function(){
51444 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
51445 this.afterScroll();
51448 onWheel : function(e){
51449 var d = e.getWheelDelta();
51450 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
51451 this.afterScroll();
51455 setContent : function(content, loadScripts){
51456 this.resizeEl.update(content, loadScripts);
51470 * @class Roo.TreePanel
51471 * @extends Roo.ContentPanel
51473 * Create a new TreePanel. - defaults to fit/scoll contents.
51474 * @param {String/Object} config A string to set only the panel's title, or a config object
51475 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
51477 Roo.TreePanel = function(config){
51478 var el = config.el;
51479 var tree = config.tree;
51480 delete config.tree;
51481 delete config.el; // hopefull!
51483 // wrapper for IE7 strict & safari scroll issue
51485 var treeEl = el.createChild();
51486 config.resizeEl = treeEl;
51490 Roo.TreePanel.superclass.constructor.call(this, el, config);
51493 this.tree = new Roo.tree.TreePanel(treeEl , tree);
51494 //console.log(tree);
51495 this.on('activate', function()
51497 if (this.tree.rendered) {
51500 //console.log('render tree');
51501 this.tree.render();
51503 // this should not be needed.. - it's actually the 'el' that resizes?
51504 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
51506 //this.on('resize', function (cp, w, h) {
51507 // this.tree.innerCt.setWidth(w);
51508 // this.tree.innerCt.setHeight(h);
51509 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
51516 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
51533 * Ext JS Library 1.1.1
51534 * Copyright(c) 2006-2007, Ext JS, LLC.
51536 * Originally Released Under LGPL - original licence link has changed is not relivant.
51539 * <script type="text/javascript">
51544 * @class Roo.ReaderLayout
51545 * @extends Roo.BorderLayout
51546 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
51547 * center region containing two nested regions (a top one for a list view and one for item preview below),
51548 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
51549 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
51550 * expedites the setup of the overall layout and regions for this common application style.
51553 var reader = new Roo.ReaderLayout();
51554 var CP = Roo.ContentPanel; // shortcut for adding
51556 reader.beginUpdate();
51557 reader.add("north", new CP("north", "North"));
51558 reader.add("west", new CP("west", {title: "West"}));
51559 reader.add("east", new CP("east", {title: "East"}));
51561 reader.regions.listView.add(new CP("listView", "List"));
51562 reader.regions.preview.add(new CP("preview", "Preview"));
51563 reader.endUpdate();
51566 * Create a new ReaderLayout
51567 * @param {Object} config Configuration options
51568 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
51569 * document.body if omitted)
51571 Roo.ReaderLayout = function(config, renderTo){
51572 var c = config || {size:{}};
51573 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
51574 north: c.north !== false ? Roo.apply({
51578 }, c.north) : false,
51579 west: c.west !== false ? Roo.apply({
51587 margins:{left:5,right:0,bottom:5,top:5},
51588 cmargins:{left:5,right:5,bottom:5,top:5}
51589 }, c.west) : false,
51590 east: c.east !== false ? Roo.apply({
51598 margins:{left:0,right:5,bottom:5,top:5},
51599 cmargins:{left:5,right:5,bottom:5,top:5}
51600 }, c.east) : false,
51601 center: Roo.apply({
51602 tabPosition: 'top',
51606 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
51610 this.el.addClass('x-reader');
51612 this.beginUpdate();
51614 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
51615 south: c.preview !== false ? Roo.apply({
51622 cmargins:{top:5,left:0, right:0, bottom:0}
51623 }, c.preview) : false,
51624 center: Roo.apply({
51630 this.add('center', new Roo.NestedLayoutPanel(inner,
51631 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
51635 this.regions.preview = inner.getRegion('south');
51636 this.regions.listView = inner.getRegion('center');
51639 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
51641 * Ext JS Library 1.1.1
51642 * Copyright(c) 2006-2007, Ext JS, LLC.
51644 * Originally Released Under LGPL - original licence link has changed is not relivant.
51647 * <script type="text/javascript">
51651 * @class Roo.grid.Grid
51652 * @extends Roo.util.Observable
51653 * This class represents the primary interface of a component based grid control.
51654 * <br><br>Usage:<pre><code>
51655 var grid = new Roo.grid.Grid("my-container-id", {
51658 selModel: mySelectionModel,
51659 autoSizeColumns: true,
51660 monitorWindowResize: false,
51661 trackMouseOver: true
51666 * <b>Common Problems:</b><br/>
51667 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
51668 * element will correct this<br/>
51669 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
51670 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
51671 * are unpredictable.<br/>
51672 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
51673 * grid to calculate dimensions/offsets.<br/>
51675 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
51676 * The container MUST have some type of size defined for the grid to fill. The container will be
51677 * automatically set to position relative if it isn't already.
51678 * @param {Object} config A config object that sets properties on this grid.
51680 Roo.grid.Grid = function(container, config){
51681 // initialize the container
51682 this.container = Roo.get(container);
51683 this.container.update("");
51684 this.container.setStyle("overflow", "hidden");
51685 this.container.addClass('x-grid-container');
51687 this.id = this.container.id;
51689 Roo.apply(this, config);
51690 // check and correct shorthanded configs
51692 this.dataSource = this.ds;
51696 this.colModel = this.cm;
51700 this.selModel = this.sm;
51704 if (this.selModel) {
51705 this.selModel = Roo.factory(this.selModel, Roo.grid);
51706 this.sm = this.selModel;
51707 this.sm.xmodule = this.xmodule || false;
51709 if (typeof(this.colModel.config) == 'undefined') {
51710 this.colModel = new Roo.grid.ColumnModel(this.colModel);
51711 this.cm = this.colModel;
51712 this.cm.xmodule = this.xmodule || false;
51714 if (this.dataSource) {
51715 this.dataSource= Roo.factory(this.dataSource, Roo.data);
51716 this.ds = this.dataSource;
51717 this.ds.xmodule = this.xmodule || false;
51724 this.container.setWidth(this.width);
51728 this.container.setHeight(this.height);
51735 * The raw click event for the entire grid.
51736 * @param {Roo.EventObject} e
51741 * The raw dblclick event for the entire grid.
51742 * @param {Roo.EventObject} e
51746 * @event contextmenu
51747 * The raw contextmenu event for the entire grid.
51748 * @param {Roo.EventObject} e
51750 "contextmenu" : true,
51753 * The raw mousedown event for the entire grid.
51754 * @param {Roo.EventObject} e
51756 "mousedown" : true,
51759 * The raw mouseup event for the entire grid.
51760 * @param {Roo.EventObject} e
51765 * The raw mouseover event for the entire grid.
51766 * @param {Roo.EventObject} e
51768 "mouseover" : true,
51771 * The raw mouseout event for the entire grid.
51772 * @param {Roo.EventObject} e
51777 * The raw keypress event for the entire grid.
51778 * @param {Roo.EventObject} e
51783 * The raw keydown event for the entire grid.
51784 * @param {Roo.EventObject} e
51792 * Fires when a cell is clicked
51793 * @param {Grid} this
51794 * @param {Number} rowIndex
51795 * @param {Number} columnIndex
51796 * @param {Roo.EventObject} e
51798 "cellclick" : true,
51800 * @event celldblclick
51801 * Fires when a cell is double clicked
51802 * @param {Grid} this
51803 * @param {Number} rowIndex
51804 * @param {Number} columnIndex
51805 * @param {Roo.EventObject} e
51807 "celldblclick" : true,
51810 * Fires when a row is clicked
51811 * @param {Grid} this
51812 * @param {Number} rowIndex
51813 * @param {Roo.EventObject} e
51817 * @event rowdblclick
51818 * Fires when a row is double clicked
51819 * @param {Grid} this
51820 * @param {Number} rowIndex
51821 * @param {Roo.EventObject} e
51823 "rowdblclick" : true,
51825 * @event headerclick
51826 * Fires when a header is clicked
51827 * @param {Grid} this
51828 * @param {Number} columnIndex
51829 * @param {Roo.EventObject} e
51831 "headerclick" : true,
51833 * @event headerdblclick
51834 * Fires when a header cell is double clicked
51835 * @param {Grid} this
51836 * @param {Number} columnIndex
51837 * @param {Roo.EventObject} e
51839 "headerdblclick" : true,
51841 * @event rowcontextmenu
51842 * Fires when a row is right clicked
51843 * @param {Grid} this
51844 * @param {Number} rowIndex
51845 * @param {Roo.EventObject} e
51847 "rowcontextmenu" : true,
51849 * @event cellcontextmenu
51850 * Fires when a cell is right clicked
51851 * @param {Grid} this
51852 * @param {Number} rowIndex
51853 * @param {Number} cellIndex
51854 * @param {Roo.EventObject} e
51856 "cellcontextmenu" : true,
51858 * @event headercontextmenu
51859 * Fires when a header is right clicked
51860 * @param {Grid} this
51861 * @param {Number} columnIndex
51862 * @param {Roo.EventObject} e
51864 "headercontextmenu" : true,
51866 * @event bodyscroll
51867 * Fires when the body element is scrolled
51868 * @param {Number} scrollLeft
51869 * @param {Number} scrollTop
51871 "bodyscroll" : true,
51873 * @event columnresize
51874 * Fires when the user resizes a column
51875 * @param {Number} columnIndex
51876 * @param {Number} newSize
51878 "columnresize" : true,
51880 * @event columnmove
51881 * Fires when the user moves a column
51882 * @param {Number} oldIndex
51883 * @param {Number} newIndex
51885 "columnmove" : true,
51888 * Fires when row(s) start being dragged
51889 * @param {Grid} this
51890 * @param {Roo.GridDD} dd The drag drop object
51891 * @param {event} e The raw browser event
51893 "startdrag" : true,
51896 * Fires when a drag operation is complete
51897 * @param {Grid} this
51898 * @param {Roo.GridDD} dd The drag drop object
51899 * @param {event} e The raw browser event
51904 * Fires when dragged row(s) are dropped on a valid DD target
51905 * @param {Grid} this
51906 * @param {Roo.GridDD} dd The drag drop object
51907 * @param {String} targetId The target drag drop object
51908 * @param {event} e The raw browser event
51913 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
51914 * @param {Grid} this
51915 * @param {Roo.GridDD} dd The drag drop object
51916 * @param {String} targetId The target drag drop object
51917 * @param {event} e The raw browser event
51922 * Fires when the dragged row(s) first cross another DD target while being dragged
51923 * @param {Grid} this
51924 * @param {Roo.GridDD} dd The drag drop object
51925 * @param {String} targetId The target drag drop object
51926 * @param {event} e The raw browser event
51928 "dragenter" : true,
51931 * Fires when the dragged row(s) leave another DD target while being dragged
51932 * @param {Grid} this
51933 * @param {Roo.GridDD} dd The drag drop object
51934 * @param {String} targetId The target drag drop object
51935 * @param {event} e The raw browser event
51940 * Fires when a row is rendered, so you can change add a style to it.
51941 * @param {GridView} gridview The grid view
51942 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
51948 * Fires when the grid is rendered
51949 * @param {Grid} grid
51954 Roo.grid.Grid.superclass.constructor.call(this);
51956 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
51959 * @cfg {String} ddGroup - drag drop group.
51963 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
51965 minColumnWidth : 25,
51968 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
51969 * <b>on initial render.</b> It is more efficient to explicitly size the columns
51970 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
51972 autoSizeColumns : false,
51975 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
51977 autoSizeHeaders : true,
51980 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
51982 monitorWindowResize : true,
51985 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
51986 * rows measured to get a columns size. Default is 0 (all rows).
51988 maxRowsToMeasure : 0,
51991 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
51993 trackMouseOver : true,
51996 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52000 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52002 enableDragDrop : false,
52005 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52007 enableColumnMove : true,
52010 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52012 enableColumnHide : true,
52015 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52017 enableRowHeightSync : false,
52020 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52025 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52027 autoHeight : false,
52030 * @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.
52032 autoExpandColumn : false,
52035 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52038 autoExpandMin : 50,
52041 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52043 autoExpandMax : 1000,
52046 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52051 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52055 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52065 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52066 * of a fixed width. Default is false.
52069 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52072 * Called once after all setup has been completed and the grid is ready to be rendered.
52073 * @return {Roo.grid.Grid} this
52075 render : function()
52077 var c = this.container;
52078 // try to detect autoHeight/width mode
52079 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52080 this.autoHeight = true;
52082 var view = this.getView();
52085 c.on("click", this.onClick, this);
52086 c.on("dblclick", this.onDblClick, this);
52087 c.on("contextmenu", this.onContextMenu, this);
52088 c.on("keydown", this.onKeyDown, this);
52090 c.on("touchstart", this.onTouchStart, this);
52093 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52095 this.getSelectionModel().init(this);
52100 this.loadMask = new Roo.LoadMask(this.container,
52101 Roo.apply({store:this.dataSource}, this.loadMask));
52105 if (this.toolbar && this.toolbar.xtype) {
52106 this.toolbar.container = this.getView().getHeaderPanel(true);
52107 this.toolbar = new Roo.Toolbar(this.toolbar);
52109 if (this.footer && this.footer.xtype) {
52110 this.footer.dataSource = this.getDataSource();
52111 this.footer.container = this.getView().getFooterPanel(true);
52112 this.footer = Roo.factory(this.footer, Roo);
52114 if (this.dropTarget && this.dropTarget.xtype) {
52115 delete this.dropTarget.xtype;
52116 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52120 this.rendered = true;
52121 this.fireEvent('render', this);
52126 * Reconfigures the grid to use a different Store and Column Model.
52127 * The View will be bound to the new objects and refreshed.
52128 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52129 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52131 reconfigure : function(dataSource, colModel){
52133 this.loadMask.destroy();
52134 this.loadMask = new Roo.LoadMask(this.container,
52135 Roo.apply({store:dataSource}, this.loadMask));
52137 this.view.bind(dataSource, colModel);
52138 this.dataSource = dataSource;
52139 this.colModel = colModel;
52140 this.view.refresh(true);
52144 onKeyDown : function(e){
52145 this.fireEvent("keydown", e);
52149 * Destroy this grid.
52150 * @param {Boolean} removeEl True to remove the element
52152 destroy : function(removeEl, keepListeners){
52154 this.loadMask.destroy();
52156 var c = this.container;
52157 c.removeAllListeners();
52158 this.view.destroy();
52159 this.colModel.purgeListeners();
52160 if(!keepListeners){
52161 this.purgeListeners();
52164 if(removeEl === true){
52170 processEvent : function(name, e){
52171 // does this fire select???
52172 Roo.log('grid:processEvent ' + name);
52174 if (name != 'touchstart' ) {
52175 this.fireEvent(name, e);
52178 var t = e.getTarget();
52180 var header = v.findHeaderIndex(t);
52181 if(header !== false){
52182 var ename = name == 'touchstart' ? 'click' : name;
52184 this.fireEvent("header" + ename, this, header, e);
52186 var row = v.findRowIndex(t);
52187 var cell = v.findCellIndex(t);
52188 if (name == 'touchstart') {
52189 // first touch is always a click.
52190 // hopefull this happens after selection is updated.?
52193 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52194 var cs = this.selModel.getSelectedCell();
52195 if (row == cs[0] && cell == cs[1]){
52199 if (typeof(this.selModel.getSelections) != 'undefined') {
52200 var cs = this.selModel.getSelections();
52201 var ds = this.dataSource;
52202 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52213 this.fireEvent("row" + name, this, row, e);
52214 if(cell !== false){
52215 this.fireEvent("cell" + name, this, row, cell, e);
52222 onClick : function(e){
52223 this.processEvent("click", e);
52226 onTouchStart : function(e){
52227 this.processEvent("touchstart", e);
52231 onContextMenu : function(e, t){
52232 this.processEvent("contextmenu", e);
52236 onDblClick : function(e){
52237 this.processEvent("dblclick", e);
52241 walkCells : function(row, col, step, fn, scope){
52242 var cm = this.colModel, clen = cm.getColumnCount();
52243 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52255 if(fn.call(scope || this, row, col, cm) === true){
52273 if(fn.call(scope || this, row, col, cm) === true){
52285 getSelections : function(){
52286 return this.selModel.getSelections();
52290 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52291 * but if manual update is required this method will initiate it.
52293 autoSize : function(){
52295 this.view.layout();
52296 if(this.view.adjustForScroll){
52297 this.view.adjustForScroll();
52303 * Returns the grid's underlying element.
52304 * @return {Element} The element
52306 getGridEl : function(){
52307 return this.container;
52310 // private for compatibility, overridden by editor grid
52311 stopEditing : function(){},
52314 * Returns the grid's SelectionModel.
52315 * @return {SelectionModel}
52317 getSelectionModel : function(){
52318 if(!this.selModel){
52319 this.selModel = new Roo.grid.RowSelectionModel();
52321 return this.selModel;
52325 * Returns the grid's DataSource.
52326 * @return {DataSource}
52328 getDataSource : function(){
52329 return this.dataSource;
52333 * Returns the grid's ColumnModel.
52334 * @return {ColumnModel}
52336 getColumnModel : function(){
52337 return this.colModel;
52341 * Returns the grid's GridView object.
52342 * @return {GridView}
52344 getView : function(){
52346 this.view = new Roo.grid.GridView(this.viewConfig);
52351 * Called to get grid's drag proxy text, by default returns this.ddText.
52354 getDragDropText : function(){
52355 var count = this.selModel.getCount();
52356 return String.format(this.ddText, count, count == 1 ? '' : 's');
52360 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52361 * %0 is replaced with the number of selected rows.
52364 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52366 * Ext JS Library 1.1.1
52367 * Copyright(c) 2006-2007, Ext JS, LLC.
52369 * Originally Released Under LGPL - original licence link has changed is not relivant.
52372 * <script type="text/javascript">
52375 Roo.grid.AbstractGridView = function(){
52379 "beforerowremoved" : true,
52380 "beforerowsinserted" : true,
52381 "beforerefresh" : true,
52382 "rowremoved" : true,
52383 "rowsinserted" : true,
52384 "rowupdated" : true,
52387 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52390 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52391 rowClass : "x-grid-row",
52392 cellClass : "x-grid-cell",
52393 tdClass : "x-grid-td",
52394 hdClass : "x-grid-hd",
52395 splitClass : "x-grid-hd-split",
52397 init: function(grid){
52399 var cid = this.grid.getGridEl().id;
52400 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52401 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52402 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52403 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52406 getColumnRenderers : function(){
52407 var renderers = [];
52408 var cm = this.grid.colModel;
52409 var colCount = cm.getColumnCount();
52410 for(var i = 0; i < colCount; i++){
52411 renderers[i] = cm.getRenderer(i);
52416 getColumnIds : function(){
52418 var cm = this.grid.colModel;
52419 var colCount = cm.getColumnCount();
52420 for(var i = 0; i < colCount; i++){
52421 ids[i] = cm.getColumnId(i);
52426 getDataIndexes : function(){
52427 if(!this.indexMap){
52428 this.indexMap = this.buildIndexMap();
52430 return this.indexMap.colToData;
52433 getColumnIndexByDataIndex : function(dataIndex){
52434 if(!this.indexMap){
52435 this.indexMap = this.buildIndexMap();
52437 return this.indexMap.dataToCol[dataIndex];
52441 * Set a css style for a column dynamically.
52442 * @param {Number} colIndex The index of the column
52443 * @param {String} name The css property name
52444 * @param {String} value The css value
52446 setCSSStyle : function(colIndex, name, value){
52447 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
52448 Roo.util.CSS.updateRule(selector, name, value);
52451 generateRules : function(cm){
52452 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
52453 Roo.util.CSS.removeStyleSheet(rulesId);
52454 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
52455 var cid = cm.getColumnId(i);
52456 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
52457 this.tdSelector, cid, " {\n}\n",
52458 this.hdSelector, cid, " {\n}\n",
52459 this.splitSelector, cid, " {\n}\n");
52461 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
52465 * Ext JS Library 1.1.1
52466 * Copyright(c) 2006-2007, Ext JS, LLC.
52468 * Originally Released Under LGPL - original licence link has changed is not relivant.
52471 * <script type="text/javascript">
52475 // This is a support class used internally by the Grid components
52476 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
52478 this.view = grid.getView();
52479 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52480 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
52482 this.setHandleElId(Roo.id(hd));
52483 this.setOuterHandleElId(Roo.id(hd2));
52485 this.scroll = false;
52487 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
52489 getDragData : function(e){
52490 var t = Roo.lib.Event.getTarget(e);
52491 var h = this.view.findHeaderCell(t);
52493 return {ddel: h.firstChild, header:h};
52498 onInitDrag : function(e){
52499 this.view.headersDisabled = true;
52500 var clone = this.dragData.ddel.cloneNode(true);
52501 clone.id = Roo.id();
52502 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
52503 this.proxy.update(clone);
52507 afterValidDrop : function(){
52509 setTimeout(function(){
52510 v.headersDisabled = false;
52514 afterInvalidDrop : function(){
52516 setTimeout(function(){
52517 v.headersDisabled = false;
52523 * Ext JS Library 1.1.1
52524 * Copyright(c) 2006-2007, Ext JS, LLC.
52526 * Originally Released Under LGPL - original licence link has changed is not relivant.
52529 * <script type="text/javascript">
52532 // This is a support class used internally by the Grid components
52533 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
52535 this.view = grid.getView();
52536 // split the proxies so they don't interfere with mouse events
52537 this.proxyTop = Roo.DomHelper.append(document.body, {
52538 cls:"col-move-top", html:" "
52540 this.proxyBottom = Roo.DomHelper.append(document.body, {
52541 cls:"col-move-bottom", html:" "
52543 this.proxyTop.hide = this.proxyBottom.hide = function(){
52544 this.setLeftTop(-100,-100);
52545 this.setStyle("visibility", "hidden");
52547 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
52548 // temporarily disabled
52549 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
52550 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
52552 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
52553 proxyOffsets : [-4, -9],
52554 fly: Roo.Element.fly,
52556 getTargetFromEvent : function(e){
52557 var t = Roo.lib.Event.getTarget(e);
52558 var cindex = this.view.findCellIndex(t);
52559 if(cindex !== false){
52560 return this.view.getHeaderCell(cindex);
52565 nextVisible : function(h){
52566 var v = this.view, cm = this.grid.colModel;
52569 if(!cm.isHidden(v.getCellIndex(h))){
52577 prevVisible : function(h){
52578 var v = this.view, cm = this.grid.colModel;
52581 if(!cm.isHidden(v.getCellIndex(h))){
52589 positionIndicator : function(h, n, e){
52590 var x = Roo.lib.Event.getPageX(e);
52591 var r = Roo.lib.Dom.getRegion(n.firstChild);
52592 var px, pt, py = r.top + this.proxyOffsets[1];
52593 if((r.right - x) <= (r.right-r.left)/2){
52594 px = r.right+this.view.borderWidth;
52600 var oldIndex = this.view.getCellIndex(h);
52601 var newIndex = this.view.getCellIndex(n);
52603 if(this.grid.colModel.isFixed(newIndex)){
52607 var locked = this.grid.colModel.isLocked(newIndex);
52612 if(oldIndex < newIndex){
52615 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
52618 px += this.proxyOffsets[0];
52619 this.proxyTop.setLeftTop(px, py);
52620 this.proxyTop.show();
52621 if(!this.bottomOffset){
52622 this.bottomOffset = this.view.mainHd.getHeight();
52624 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
52625 this.proxyBottom.show();
52629 onNodeEnter : function(n, dd, e, data){
52630 if(data.header != n){
52631 this.positionIndicator(data.header, n, e);
52635 onNodeOver : function(n, dd, e, data){
52636 var result = false;
52637 if(data.header != n){
52638 result = this.positionIndicator(data.header, n, e);
52641 this.proxyTop.hide();
52642 this.proxyBottom.hide();
52644 return result ? this.dropAllowed : this.dropNotAllowed;
52647 onNodeOut : function(n, dd, e, data){
52648 this.proxyTop.hide();
52649 this.proxyBottom.hide();
52652 onNodeDrop : function(n, dd, e, data){
52653 var h = data.header;
52655 var cm = this.grid.colModel;
52656 var x = Roo.lib.Event.getPageX(e);
52657 var r = Roo.lib.Dom.getRegion(n.firstChild);
52658 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
52659 var oldIndex = this.view.getCellIndex(h);
52660 var newIndex = this.view.getCellIndex(n);
52661 var locked = cm.isLocked(newIndex);
52665 if(oldIndex < newIndex){
52668 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
52671 cm.setLocked(oldIndex, locked, true);
52672 cm.moveColumn(oldIndex, newIndex);
52673 this.grid.fireEvent("columnmove", oldIndex, newIndex);
52681 * Ext JS Library 1.1.1
52682 * Copyright(c) 2006-2007, Ext JS, LLC.
52684 * Originally Released Under LGPL - original licence link has changed is not relivant.
52687 * <script type="text/javascript">
52691 * @class Roo.grid.GridView
52692 * @extends Roo.util.Observable
52695 * @param {Object} config
52697 Roo.grid.GridView = function(config){
52698 Roo.grid.GridView.superclass.constructor.call(this);
52701 Roo.apply(this, config);
52704 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
52706 unselectable : 'unselectable="on"',
52707 unselectableCls : 'x-unselectable',
52710 rowClass : "x-grid-row",
52712 cellClass : "x-grid-col",
52714 tdClass : "x-grid-td",
52716 hdClass : "x-grid-hd",
52718 splitClass : "x-grid-split",
52720 sortClasses : ["sort-asc", "sort-desc"],
52722 enableMoveAnim : false,
52726 dh : Roo.DomHelper,
52728 fly : Roo.Element.fly,
52730 css : Roo.util.CSS,
52736 scrollIncrement : 22,
52738 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
52740 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
52742 bind : function(ds, cm){
52744 this.ds.un("load", this.onLoad, this);
52745 this.ds.un("datachanged", this.onDataChange, this);
52746 this.ds.un("add", this.onAdd, this);
52747 this.ds.un("remove", this.onRemove, this);
52748 this.ds.un("update", this.onUpdate, this);
52749 this.ds.un("clear", this.onClear, this);
52752 ds.on("load", this.onLoad, this);
52753 ds.on("datachanged", this.onDataChange, this);
52754 ds.on("add", this.onAdd, this);
52755 ds.on("remove", this.onRemove, this);
52756 ds.on("update", this.onUpdate, this);
52757 ds.on("clear", this.onClear, this);
52762 this.cm.un("widthchange", this.onColWidthChange, this);
52763 this.cm.un("headerchange", this.onHeaderChange, this);
52764 this.cm.un("hiddenchange", this.onHiddenChange, this);
52765 this.cm.un("columnmoved", this.onColumnMove, this);
52766 this.cm.un("columnlockchange", this.onColumnLock, this);
52769 this.generateRules(cm);
52770 cm.on("widthchange", this.onColWidthChange, this);
52771 cm.on("headerchange", this.onHeaderChange, this);
52772 cm.on("hiddenchange", this.onHiddenChange, this);
52773 cm.on("columnmoved", this.onColumnMove, this);
52774 cm.on("columnlockchange", this.onColumnLock, this);
52779 init: function(grid){
52780 Roo.grid.GridView.superclass.init.call(this, grid);
52782 this.bind(grid.dataSource, grid.colModel);
52784 grid.on("headerclick", this.handleHeaderClick, this);
52786 if(grid.trackMouseOver){
52787 grid.on("mouseover", this.onRowOver, this);
52788 grid.on("mouseout", this.onRowOut, this);
52790 grid.cancelTextSelection = function(){};
52791 this.gridId = grid.id;
52793 var tpls = this.templates || {};
52796 tpls.master = new Roo.Template(
52797 '<div class="x-grid" hidefocus="true">',
52798 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
52799 '<div class="x-grid-topbar"></div>',
52800 '<div class="x-grid-scroller"><div></div></div>',
52801 '<div class="x-grid-locked">',
52802 '<div class="x-grid-header">{lockedHeader}</div>',
52803 '<div class="x-grid-body">{lockedBody}</div>',
52805 '<div class="x-grid-viewport">',
52806 '<div class="x-grid-header">{header}</div>',
52807 '<div class="x-grid-body">{body}</div>',
52809 '<div class="x-grid-bottombar"></div>',
52811 '<div class="x-grid-resize-proxy"> </div>',
52814 tpls.master.disableformats = true;
52818 tpls.header = new Roo.Template(
52819 '<table border="0" cellspacing="0" cellpadding="0">',
52820 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
52823 tpls.header.disableformats = true;
52825 tpls.header.compile();
52828 tpls.hcell = new Roo.Template(
52829 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
52830 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
52833 tpls.hcell.disableFormats = true;
52835 tpls.hcell.compile();
52838 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
52839 this.unselectableCls + '" ' + this.unselectable +'> </div>');
52840 tpls.hsplit.disableFormats = true;
52842 tpls.hsplit.compile();
52845 tpls.body = new Roo.Template(
52846 '<table border="0" cellspacing="0" cellpadding="0">',
52847 "<tbody>{rows}</tbody>",
52850 tpls.body.disableFormats = true;
52852 tpls.body.compile();
52855 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
52856 tpls.row.disableFormats = true;
52858 tpls.row.compile();
52861 tpls.cell = new Roo.Template(
52862 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
52863 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
52864 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
52867 tpls.cell.disableFormats = true;
52869 tpls.cell.compile();
52871 this.templates = tpls;
52874 // remap these for backwards compat
52875 onColWidthChange : function(){
52876 this.updateColumns.apply(this, arguments);
52878 onHeaderChange : function(){
52879 this.updateHeaders.apply(this, arguments);
52881 onHiddenChange : function(){
52882 this.handleHiddenChange.apply(this, arguments);
52884 onColumnMove : function(){
52885 this.handleColumnMove.apply(this, arguments);
52887 onColumnLock : function(){
52888 this.handleLockChange.apply(this, arguments);
52891 onDataChange : function(){
52893 this.updateHeaderSortState();
52896 onClear : function(){
52900 onUpdate : function(ds, record){
52901 this.refreshRow(record);
52904 refreshRow : function(record){
52905 var ds = this.ds, index;
52906 if(typeof record == 'number'){
52908 record = ds.getAt(index);
52910 index = ds.indexOf(record);
52912 this.insertRows(ds, index, index, true);
52913 this.onRemove(ds, record, index+1, true);
52914 this.syncRowHeights(index, index);
52916 this.fireEvent("rowupdated", this, index, record);
52919 onAdd : function(ds, records, index){
52920 this.insertRows(ds, index, index + (records.length-1));
52923 onRemove : function(ds, record, index, isUpdate){
52924 if(isUpdate !== true){
52925 this.fireEvent("beforerowremoved", this, index, record);
52927 var bt = this.getBodyTable(), lt = this.getLockedTable();
52928 if(bt.rows[index]){
52929 bt.firstChild.removeChild(bt.rows[index]);
52931 if(lt.rows[index]){
52932 lt.firstChild.removeChild(lt.rows[index]);
52934 if(isUpdate !== true){
52935 this.stripeRows(index);
52936 this.syncRowHeights(index, index);
52938 this.fireEvent("rowremoved", this, index, record);
52942 onLoad : function(){
52943 this.scrollToTop();
52947 * Scrolls the grid to the top
52949 scrollToTop : function(){
52951 this.scroller.dom.scrollTop = 0;
52957 * Gets a panel in the header of the grid that can be used for toolbars etc.
52958 * After modifying the contents of this panel a call to grid.autoSize() may be
52959 * required to register any changes in size.
52960 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
52961 * @return Roo.Element
52963 getHeaderPanel : function(doShow){
52965 this.headerPanel.show();
52967 return this.headerPanel;
52971 * Gets a panel in the footer of the grid that can be used for toolbars etc.
52972 * After modifying the contents of this panel a call to grid.autoSize() may be
52973 * required to register any changes in size.
52974 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
52975 * @return Roo.Element
52977 getFooterPanel : function(doShow){
52979 this.footerPanel.show();
52981 return this.footerPanel;
52984 initElements : function(){
52985 var E = Roo.Element;
52986 var el = this.grid.getGridEl().dom.firstChild;
52987 var cs = el.childNodes;
52989 this.el = new E(el);
52991 this.focusEl = new E(el.firstChild);
52992 this.focusEl.swallowEvent("click", true);
52994 this.headerPanel = new E(cs[1]);
52995 this.headerPanel.enableDisplayMode("block");
52997 this.scroller = new E(cs[2]);
52998 this.scrollSizer = new E(this.scroller.dom.firstChild);
53000 this.lockedWrap = new E(cs[3]);
53001 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53002 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53004 this.mainWrap = new E(cs[4]);
53005 this.mainHd = new E(this.mainWrap.dom.firstChild);
53006 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53008 this.footerPanel = new E(cs[5]);
53009 this.footerPanel.enableDisplayMode("block");
53011 this.resizeProxy = new E(cs[6]);
53013 this.headerSelector = String.format(
53014 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53015 this.lockedHd.id, this.mainHd.id
53018 this.splitterSelector = String.format(
53019 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53020 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53023 idToCssName : function(s)
53025 return s.replace(/[^a-z0-9]+/ig, '-');
53028 getHeaderCell : function(index){
53029 return Roo.DomQuery.select(this.headerSelector)[index];
53032 getHeaderCellMeasure : function(index){
53033 return this.getHeaderCell(index).firstChild;
53036 getHeaderCellText : function(index){
53037 return this.getHeaderCell(index).firstChild.firstChild;
53040 getLockedTable : function(){
53041 return this.lockedBody.dom.firstChild;
53044 getBodyTable : function(){
53045 return this.mainBody.dom.firstChild;
53048 getLockedRow : function(index){
53049 return this.getLockedTable().rows[index];
53052 getRow : function(index){
53053 return this.getBodyTable().rows[index];
53056 getRowComposite : function(index){
53058 this.rowEl = new Roo.CompositeElementLite();
53060 var els = [], lrow, mrow;
53061 if(lrow = this.getLockedRow(index)){
53064 if(mrow = this.getRow(index)){
53067 this.rowEl.elements = els;
53071 * Gets the 'td' of the cell
53073 * @param {Integer} rowIndex row to select
53074 * @param {Integer} colIndex column to select
53078 getCell : function(rowIndex, colIndex){
53079 var locked = this.cm.getLockedCount();
53081 if(colIndex < locked){
53082 source = this.lockedBody.dom.firstChild;
53084 source = this.mainBody.dom.firstChild;
53085 colIndex -= locked;
53087 return source.rows[rowIndex].childNodes[colIndex];
53090 getCellText : function(rowIndex, colIndex){
53091 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53094 getCellBox : function(cell){
53095 var b = this.fly(cell).getBox();
53096 if(Roo.isOpera){ // opera fails to report the Y
53097 b.y = cell.offsetTop + this.mainBody.getY();
53102 getCellIndex : function(cell){
53103 var id = String(cell.className).match(this.cellRE);
53105 return parseInt(id[1], 10);
53110 findHeaderIndex : function(n){
53111 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53112 return r ? this.getCellIndex(r) : false;
53115 findHeaderCell : function(n){
53116 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53117 return r ? r : false;
53120 findRowIndex : function(n){
53124 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53125 return r ? r.rowIndex : false;
53128 findCellIndex : function(node){
53129 var stop = this.el.dom;
53130 while(node && node != stop){
53131 if(this.findRE.test(node.className)){
53132 return this.getCellIndex(node);
53134 node = node.parentNode;
53139 getColumnId : function(index){
53140 return this.cm.getColumnId(index);
53143 getSplitters : function()
53145 if(this.splitterSelector){
53146 return Roo.DomQuery.select(this.splitterSelector);
53152 getSplitter : function(index){
53153 return this.getSplitters()[index];
53156 onRowOver : function(e, t){
53158 if((row = this.findRowIndex(t)) !== false){
53159 this.getRowComposite(row).addClass("x-grid-row-over");
53163 onRowOut : function(e, t){
53165 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53166 this.getRowComposite(row).removeClass("x-grid-row-over");
53170 renderHeaders : function(){
53172 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53173 var cb = [], lb = [], sb = [], lsb = [], p = {};
53174 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53175 p.cellId = "x-grid-hd-0-" + i;
53176 p.splitId = "x-grid-csplit-0-" + i;
53177 p.id = cm.getColumnId(i);
53178 p.title = cm.getColumnTooltip(i) || "";
53179 p.value = cm.getColumnHeader(i) || "";
53180 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53181 if(!cm.isLocked(i)){
53182 cb[cb.length] = ct.apply(p);
53183 sb[sb.length] = st.apply(p);
53185 lb[lb.length] = ct.apply(p);
53186 lsb[lsb.length] = st.apply(p);
53189 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53190 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53193 updateHeaders : function(){
53194 var html = this.renderHeaders();
53195 this.lockedHd.update(html[0]);
53196 this.mainHd.update(html[1]);
53200 * Focuses the specified row.
53201 * @param {Number} row The row index
53203 focusRow : function(row)
53205 //Roo.log('GridView.focusRow');
53206 var x = this.scroller.dom.scrollLeft;
53207 this.focusCell(row, 0, false);
53208 this.scroller.dom.scrollLeft = x;
53212 * Focuses the specified cell.
53213 * @param {Number} row The row index
53214 * @param {Number} col The column index
53215 * @param {Boolean} hscroll false to disable horizontal scrolling
53217 focusCell : function(row, col, hscroll)
53219 //Roo.log('GridView.focusCell');
53220 var el = this.ensureVisible(row, col, hscroll);
53221 this.focusEl.alignTo(el, "tl-tl");
53223 this.focusEl.focus();
53225 this.focusEl.focus.defer(1, this.focusEl);
53230 * Scrolls the specified cell into view
53231 * @param {Number} row The row index
53232 * @param {Number} col The column index
53233 * @param {Boolean} hscroll false to disable horizontal scrolling
53235 ensureVisible : function(row, col, hscroll)
53237 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53238 //return null; //disable for testing.
53239 if(typeof row != "number"){
53240 row = row.rowIndex;
53242 if(row < 0 && row >= this.ds.getCount()){
53245 col = (col !== undefined ? col : 0);
53246 var cm = this.grid.colModel;
53247 while(cm.isHidden(col)){
53251 var el = this.getCell(row, col);
53255 var c = this.scroller.dom;
53257 var ctop = parseInt(el.offsetTop, 10);
53258 var cleft = parseInt(el.offsetLeft, 10);
53259 var cbot = ctop + el.offsetHeight;
53260 var cright = cleft + el.offsetWidth;
53262 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53263 var stop = parseInt(c.scrollTop, 10);
53264 var sleft = parseInt(c.scrollLeft, 10);
53265 var sbot = stop + ch;
53266 var sright = sleft + c.clientWidth;
53268 Roo.log('GridView.ensureVisible:' +
53270 ' c.clientHeight:' + c.clientHeight +
53271 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53279 c.scrollTop = ctop;
53280 //Roo.log("set scrolltop to ctop DISABLE?");
53281 }else if(cbot > sbot){
53282 //Roo.log("set scrolltop to cbot-ch");
53283 c.scrollTop = cbot-ch;
53286 if(hscroll !== false){
53288 c.scrollLeft = cleft;
53289 }else if(cright > sright){
53290 c.scrollLeft = cright-c.clientWidth;
53297 updateColumns : function(){
53298 this.grid.stopEditing();
53299 var cm = this.grid.colModel, colIds = this.getColumnIds();
53300 //var totalWidth = cm.getTotalWidth();
53302 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53303 //if(cm.isHidden(i)) continue;
53304 var w = cm.getColumnWidth(i);
53305 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53306 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53308 this.updateSplitters();
53311 generateRules : function(cm){
53312 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53313 Roo.util.CSS.removeStyleSheet(rulesId);
53314 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53315 var cid = cm.getColumnId(i);
53317 if(cm.config[i].align){
53318 align = 'text-align:'+cm.config[i].align+';';
53321 if(cm.isHidden(i)){
53322 hidden = 'display:none;';
53324 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53326 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53327 this.hdSelector, cid, " {\n", align, width, "}\n",
53328 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53329 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53331 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53334 updateSplitters : function(){
53335 var cm = this.cm, s = this.getSplitters();
53336 if(s){ // splitters not created yet
53337 var pos = 0, locked = true;
53338 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53339 if(cm.isHidden(i)) continue;
53340 var w = cm.getColumnWidth(i); // make sure it's a number
53341 if(!cm.isLocked(i) && locked){
53346 s[i].style.left = (pos-this.splitOffset) + "px";
53351 handleHiddenChange : function(colModel, colIndex, hidden){
53353 this.hideColumn(colIndex);
53355 this.unhideColumn(colIndex);
53359 hideColumn : function(colIndex){
53360 var cid = this.getColumnId(colIndex);
53361 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53362 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53364 this.updateHeaders();
53366 this.updateSplitters();
53370 unhideColumn : function(colIndex){
53371 var cid = this.getColumnId(colIndex);
53372 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53373 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53376 this.updateHeaders();
53378 this.updateSplitters();
53382 insertRows : function(dm, firstRow, lastRow, isUpdate){
53383 if(firstRow == 0 && lastRow == dm.getCount()-1){
53387 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53389 var s = this.getScrollState();
53390 var markup = this.renderRows(firstRow, lastRow);
53391 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53392 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53393 this.restoreScroll(s);
53395 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53396 this.syncRowHeights(firstRow, lastRow);
53397 this.stripeRows(firstRow);
53403 bufferRows : function(markup, target, index){
53404 var before = null, trows = target.rows, tbody = target.tBodies[0];
53405 if(index < trows.length){
53406 before = trows[index];
53408 var b = document.createElement("div");
53409 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53410 var rows = b.firstChild.rows;
53411 for(var i = 0, len = rows.length; i < len; i++){
53413 tbody.insertBefore(rows[0], before);
53415 tbody.appendChild(rows[0]);
53422 deleteRows : function(dm, firstRow, lastRow){
53423 if(dm.getRowCount()<1){
53424 this.fireEvent("beforerefresh", this);
53425 this.mainBody.update("");
53426 this.lockedBody.update("");
53427 this.fireEvent("refresh", this);
53429 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53430 var bt = this.getBodyTable();
53431 var tbody = bt.firstChild;
53432 var rows = bt.rows;
53433 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53434 tbody.removeChild(rows[firstRow]);
53436 this.stripeRows(firstRow);
53437 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
53441 updateRows : function(dataSource, firstRow, lastRow){
53442 var s = this.getScrollState();
53444 this.restoreScroll(s);
53447 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
53451 this.updateHeaderSortState();
53454 getScrollState : function(){
53456 var sb = this.scroller.dom;
53457 return {left: sb.scrollLeft, top: sb.scrollTop};
53460 stripeRows : function(startRow){
53461 if(!this.grid.stripeRows || this.ds.getCount() < 1){
53464 startRow = startRow || 0;
53465 var rows = this.getBodyTable().rows;
53466 var lrows = this.getLockedTable().rows;
53467 var cls = ' x-grid-row-alt ';
53468 for(var i = startRow, len = rows.length; i < len; i++){
53469 var row = rows[i], lrow = lrows[i];
53470 var isAlt = ((i+1) % 2 == 0);
53471 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
53472 if(isAlt == hasAlt){
53476 row.className += " x-grid-row-alt";
53478 row.className = row.className.replace("x-grid-row-alt", "");
53481 lrow.className = row.className;
53486 restoreScroll : function(state){
53487 //Roo.log('GridView.restoreScroll');
53488 var sb = this.scroller.dom;
53489 sb.scrollLeft = state.left;
53490 sb.scrollTop = state.top;
53494 syncScroll : function(){
53495 //Roo.log('GridView.syncScroll');
53496 var sb = this.scroller.dom;
53497 var sh = this.mainHd.dom;
53498 var bs = this.mainBody.dom;
53499 var lv = this.lockedBody.dom;
53500 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
53501 lv.scrollTop = bs.scrollTop = sb.scrollTop;
53504 handleScroll : function(e){
53506 var sb = this.scroller.dom;
53507 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
53511 handleWheel : function(e){
53512 var d = e.getWheelDelta();
53513 this.scroller.dom.scrollTop -= d*22;
53514 // set this here to prevent jumpy scrolling on large tables
53515 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
53519 renderRows : function(startRow, endRow){
53520 // pull in all the crap needed to render rows
53521 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
53522 var colCount = cm.getColumnCount();
53524 if(ds.getCount() < 1){
53528 // build a map for all the columns
53530 for(var i = 0; i < colCount; i++){
53531 var name = cm.getDataIndex(i);
53533 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
53534 renderer : cm.getRenderer(i),
53535 id : cm.getColumnId(i),
53536 locked : cm.isLocked(i)
53540 startRow = startRow || 0;
53541 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
53543 // records to render
53544 var rs = ds.getRange(startRow, endRow);
53546 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
53549 // As much as I hate to duplicate code, this was branched because FireFox really hates
53550 // [].join("") on strings. The performance difference was substantial enough to
53551 // branch this function
53552 doRender : Roo.isGecko ?
53553 function(cs, rs, ds, startRow, colCount, stripe){
53554 var ts = this.templates, ct = ts.cell, rt = ts.row;
53556 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53558 var hasListener = this.grid.hasListener('rowclass');
53560 for(var j = 0, len = rs.length; j < len; j++){
53561 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
53562 for(var i = 0; i < colCount; i++){
53564 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53566 p.css = p.attr = "";
53567 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53568 if(p.value == undefined || p.value === "") p.value = " ";
53569 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53570 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53572 var markup = ct.apply(p);
53580 if(stripe && ((rowIndex+1) % 2 == 0)){
53581 alt.push("x-grid-row-alt")
53584 alt.push( " x-grid-dirty-row");
53587 if(this.getRowClass){
53588 alt.push(this.getRowClass(r, rowIndex));
53594 rowIndex : rowIndex,
53597 this.grid.fireEvent('rowclass', this, rowcfg);
53598 alt.push(rowcfg.rowClass);
53600 rp.alt = alt.join(" ");
53601 lbuf+= rt.apply(rp);
53603 buf+= rt.apply(rp);
53605 return [lbuf, buf];
53607 function(cs, rs, ds, startRow, colCount, stripe){
53608 var ts = this.templates, ct = ts.cell, rt = ts.row;
53610 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
53611 var hasListener = this.grid.hasListener('rowclass');
53614 for(var j = 0, len = rs.length; j < len; j++){
53615 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
53616 for(var i = 0; i < colCount; i++){
53618 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
53620 p.css = p.attr = "";
53621 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
53622 if(p.value == undefined || p.value === "") p.value = " ";
53623 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
53624 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
53627 var markup = ct.apply(p);
53629 cb[cb.length] = markup;
53631 lcb[lcb.length] = markup;
53635 if(stripe && ((rowIndex+1) % 2 == 0)){
53636 alt.push( "x-grid-row-alt");
53639 alt.push(" x-grid-dirty-row");
53642 if(this.getRowClass){
53643 alt.push( this.getRowClass(r, rowIndex));
53649 rowIndex : rowIndex,
53652 this.grid.fireEvent('rowclass', this, rowcfg);
53653 alt.push(rowcfg.rowClass);
53655 rp.alt = alt.join(" ");
53656 rp.cells = lcb.join("");
53657 lbuf[lbuf.length] = rt.apply(rp);
53658 rp.cells = cb.join("");
53659 buf[buf.length] = rt.apply(rp);
53661 return [lbuf.join(""), buf.join("")];
53664 renderBody : function(){
53665 var markup = this.renderRows();
53666 var bt = this.templates.body;
53667 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
53671 * Refreshes the grid
53672 * @param {Boolean} headersToo
53674 refresh : function(headersToo){
53675 this.fireEvent("beforerefresh", this);
53676 this.grid.stopEditing();
53677 var result = this.renderBody();
53678 this.lockedBody.update(result[0]);
53679 this.mainBody.update(result[1]);
53680 if(headersToo === true){
53681 this.updateHeaders();
53682 this.updateColumns();
53683 this.updateSplitters();
53684 this.updateHeaderSortState();
53686 this.syncRowHeights();
53688 this.fireEvent("refresh", this);
53691 handleColumnMove : function(cm, oldIndex, newIndex){
53692 this.indexMap = null;
53693 var s = this.getScrollState();
53694 this.refresh(true);
53695 this.restoreScroll(s);
53696 this.afterMove(newIndex);
53699 afterMove : function(colIndex){
53700 if(this.enableMoveAnim && Roo.enableFx){
53701 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
53703 // if multisort - fix sortOrder, and reload..
53704 if (this.grid.dataSource.multiSort) {
53705 // the we can call sort again..
53706 var dm = this.grid.dataSource;
53707 var cm = this.grid.colModel;
53709 for(var i = 0; i < cm.config.length; i++ ) {
53711 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
53712 continue; // dont' bother, it's not in sort list or being set.
53715 so.push(cm.config[i].dataIndex);
53718 dm.load(dm.lastOptions);
53725 updateCell : function(dm, rowIndex, dataIndex){
53726 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
53727 if(typeof colIndex == "undefined"){ // not present in grid
53730 var cm = this.grid.colModel;
53731 var cell = this.getCell(rowIndex, colIndex);
53732 var cellText = this.getCellText(rowIndex, colIndex);
53735 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
53736 id : cm.getColumnId(colIndex),
53737 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
53739 var renderer = cm.getRenderer(colIndex);
53740 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
53741 if(typeof val == "undefined" || val === "") val = " ";
53742 cellText.innerHTML = val;
53743 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
53744 this.syncRowHeights(rowIndex, rowIndex);
53747 calcColumnWidth : function(colIndex, maxRowsToMeasure){
53749 if(this.grid.autoSizeHeaders){
53750 var h = this.getHeaderCellMeasure(colIndex);
53751 maxWidth = Math.max(maxWidth, h.scrollWidth);
53754 if(this.cm.isLocked(colIndex)){
53755 tb = this.getLockedTable();
53758 tb = this.getBodyTable();
53759 index = colIndex - this.cm.getLockedCount();
53762 var rows = tb.rows;
53763 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
53764 for(var i = 0; i < stopIndex; i++){
53765 var cell = rows[i].childNodes[index].firstChild;
53766 maxWidth = Math.max(maxWidth, cell.scrollWidth);
53769 return maxWidth + /*margin for error in IE*/ 5;
53772 * Autofit a column to its content.
53773 * @param {Number} colIndex
53774 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
53776 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
53777 if(this.cm.isHidden(colIndex)){
53778 return; // can't calc a hidden column
53781 var cid = this.cm.getColumnId(colIndex);
53782 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
53783 if(this.grid.autoSizeHeaders){
53784 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
53787 var newWidth = this.calcColumnWidth(colIndex);
53788 this.cm.setColumnWidth(colIndex,
53789 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
53790 if(!suppressEvent){
53791 this.grid.fireEvent("columnresize", colIndex, newWidth);
53796 * Autofits all columns to their content and then expands to fit any extra space in the grid
53798 autoSizeColumns : function(){
53799 var cm = this.grid.colModel;
53800 var colCount = cm.getColumnCount();
53801 for(var i = 0; i < colCount; i++){
53802 this.autoSizeColumn(i, true, true);
53804 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
53807 this.updateColumns();
53813 * Autofits all columns to the grid's width proportionate with their current size
53814 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
53816 fitColumns : function(reserveScrollSpace){
53817 var cm = this.grid.colModel;
53818 var colCount = cm.getColumnCount();
53822 for (i = 0; i < colCount; i++){
53823 if(!cm.isHidden(i) && !cm.isFixed(i)){
53824 w = cm.getColumnWidth(i);
53830 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
53831 if(reserveScrollSpace){
53834 var frac = (avail - cm.getTotalWidth())/width;
53835 while (cols.length){
53838 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
53840 this.updateColumns();
53844 onRowSelect : function(rowIndex){
53845 var row = this.getRowComposite(rowIndex);
53846 row.addClass("x-grid-row-selected");
53849 onRowDeselect : function(rowIndex){
53850 var row = this.getRowComposite(rowIndex);
53851 row.removeClass("x-grid-row-selected");
53854 onCellSelect : function(row, col){
53855 var cell = this.getCell(row, col);
53857 Roo.fly(cell).addClass("x-grid-cell-selected");
53861 onCellDeselect : function(row, col){
53862 var cell = this.getCell(row, col);
53864 Roo.fly(cell).removeClass("x-grid-cell-selected");
53868 updateHeaderSortState : function(){
53870 // sort state can be single { field: xxx, direction : yyy}
53871 // or { xxx=>ASC , yyy : DESC ..... }
53874 if (!this.ds.multiSort) {
53875 var state = this.ds.getSortState();
53879 mstate[state.field] = state.direction;
53880 // FIXME... - this is not used here.. but might be elsewhere..
53881 this.sortState = state;
53884 mstate = this.ds.sortToggle;
53886 //remove existing sort classes..
53888 var sc = this.sortClasses;
53889 var hds = this.el.select(this.headerSelector).removeClass(sc);
53891 for(var f in mstate) {
53893 var sortColumn = this.cm.findColumnIndex(f);
53895 if(sortColumn != -1){
53896 var sortDir = mstate[f];
53897 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
53906 handleHeaderClick : function(g, index,e){
53908 Roo.log("header click");
53911 // touch events on header are handled by context
53912 this.handleHdCtx(g,index,e);
53917 if(this.headersDisabled){
53920 var dm = g.dataSource, cm = g.colModel;
53921 if(!cm.isSortable(index)){
53926 if (dm.multiSort) {
53927 // update the sortOrder
53929 for(var i = 0; i < cm.config.length; i++ ) {
53931 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
53932 continue; // dont' bother, it's not in sort list or being set.
53935 so.push(cm.config[i].dataIndex);
53941 dm.sort(cm.getDataIndex(index));
53945 destroy : function(){
53947 this.colMenu.removeAll();
53948 Roo.menu.MenuMgr.unregister(this.colMenu);
53949 this.colMenu.getEl().remove();
53950 delete this.colMenu;
53953 this.hmenu.removeAll();
53954 Roo.menu.MenuMgr.unregister(this.hmenu);
53955 this.hmenu.getEl().remove();
53958 if(this.grid.enableColumnMove){
53959 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53961 for(var dd in dds){
53962 if(!dds[dd].config.isTarget && dds[dd].dragElId){
53963 var elid = dds[dd].dragElId;
53965 Roo.get(elid).remove();
53966 } else if(dds[dd].config.isTarget){
53967 dds[dd].proxyTop.remove();
53968 dds[dd].proxyBottom.remove();
53971 if(Roo.dd.DDM.locationCache[dd]){
53972 delete Roo.dd.DDM.locationCache[dd];
53975 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
53978 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
53979 this.bind(null, null);
53980 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
53983 handleLockChange : function(){
53984 this.refresh(true);
53987 onDenyColumnLock : function(){
53991 onDenyColumnHide : function(){
53995 handleHdMenuClick : function(item){
53996 var index = this.hdCtxIndex;
53997 var cm = this.cm, ds = this.ds;
54000 ds.sort(cm.getDataIndex(index), "ASC");
54003 ds.sort(cm.getDataIndex(index), "DESC");
54006 var lc = cm.getLockedCount();
54007 if(cm.getColumnCount(true) <= lc+1){
54008 this.onDenyColumnLock();
54012 cm.setLocked(index, true, true);
54013 cm.moveColumn(index, lc);
54014 this.grid.fireEvent("columnmove", index, lc);
54016 cm.setLocked(index, true);
54020 var lc = cm.getLockedCount();
54021 if((lc-1) != index){
54022 cm.setLocked(index, false, true);
54023 cm.moveColumn(index, lc-1);
54024 this.grid.fireEvent("columnmove", index, lc-1);
54026 cm.setLocked(index, false);
54029 case 'wider': // used to expand cols on touch..
54031 var cw = cm.getColumnWidth(index);
54032 cw += (item.id == 'wider' ? 1 : -1) * 50;
54033 cw = Math.max(0, cw);
54034 cw = Math.min(cw,4000);
54035 cm.setColumnWidth(index, cw);
54039 index = cm.getIndexById(item.id.substr(4));
54041 if(item.checked && cm.getColumnCount(true) <= 1){
54042 this.onDenyColumnHide();
54045 cm.setHidden(index, item.checked);
54051 beforeColMenuShow : function(){
54052 var cm = this.cm, colCount = cm.getColumnCount();
54053 this.colMenu.removeAll();
54054 for(var i = 0; i < colCount; i++){
54055 this.colMenu.add(new Roo.menu.CheckItem({
54056 id: "col-"+cm.getColumnId(i),
54057 text: cm.getColumnHeader(i),
54058 checked: !cm.isHidden(i),
54064 handleHdCtx : function(g, index, e){
54066 var hd = this.getHeaderCell(index);
54067 this.hdCtxIndex = index;
54068 var ms = this.hmenu.items, cm = this.cm;
54069 ms.get("asc").setDisabled(!cm.isSortable(index));
54070 ms.get("desc").setDisabled(!cm.isSortable(index));
54071 if(this.grid.enableColLock !== false){
54072 ms.get("lock").setDisabled(cm.isLocked(index));
54073 ms.get("unlock").setDisabled(!cm.isLocked(index));
54075 this.hmenu.show(hd, "tl-bl");
54078 handleHdOver : function(e){
54079 var hd = this.findHeaderCell(e.getTarget());
54080 if(hd && !this.headersDisabled){
54081 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54082 this.fly(hd).addClass("x-grid-hd-over");
54087 handleHdOut : function(e){
54088 var hd = this.findHeaderCell(e.getTarget());
54090 this.fly(hd).removeClass("x-grid-hd-over");
54094 handleSplitDblClick : function(e, t){
54095 var i = this.getCellIndex(t);
54096 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54097 this.autoSizeColumn(i, true);
54102 render : function(){
54105 var colCount = cm.getColumnCount();
54107 if(this.grid.monitorWindowResize === true){
54108 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54110 var header = this.renderHeaders();
54111 var body = this.templates.body.apply({rows:""});
54112 var html = this.templates.master.apply({
54115 lockedHeader: header[0],
54119 //this.updateColumns();
54121 this.grid.getGridEl().dom.innerHTML = html;
54123 this.initElements();
54125 // a kludge to fix the random scolling effect in webkit
54126 this.el.on("scroll", function() {
54127 this.el.dom.scrollTop=0; // hopefully not recursive..
54130 this.scroller.on("scroll", this.handleScroll, this);
54131 this.lockedBody.on("mousewheel", this.handleWheel, this);
54132 this.mainBody.on("mousewheel", this.handleWheel, this);
54134 this.mainHd.on("mouseover", this.handleHdOver, this);
54135 this.mainHd.on("mouseout", this.handleHdOut, this);
54136 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54137 {delegate: "."+this.splitClass});
54139 this.lockedHd.on("mouseover", this.handleHdOver, this);
54140 this.lockedHd.on("mouseout", this.handleHdOut, this);
54141 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54142 {delegate: "."+this.splitClass});
54144 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54145 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54148 this.updateSplitters();
54150 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54151 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54152 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54155 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54156 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54158 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54159 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54161 if(this.grid.enableColLock !== false){
54162 this.hmenu.add('-',
54163 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54164 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54168 this.hmenu.add('-',
54169 {id:"wider", text: this.columnsWiderText},
54170 {id:"narrow", text: this.columnsNarrowText }
54176 if(this.grid.enableColumnHide !== false){
54178 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54179 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54180 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54182 this.hmenu.add('-',
54183 {id:"columns", text: this.columnsText, menu: this.colMenu}
54186 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54188 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54191 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54192 this.dd = new Roo.grid.GridDragZone(this.grid, {
54193 ddGroup : this.grid.ddGroup || 'GridDD'
54199 for(var i = 0; i < colCount; i++){
54200 if(cm.isHidden(i)){
54201 this.hideColumn(i);
54203 if(cm.config[i].align){
54204 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54205 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54209 this.updateHeaderSortState();
54211 this.beforeInitialResize();
54214 // two part rendering gives faster view to the user
54215 this.renderPhase2.defer(1, this);
54218 renderPhase2 : function(){
54219 // render the rows now
54221 if(this.grid.autoSizeColumns){
54222 this.autoSizeColumns();
54226 beforeInitialResize : function(){
54230 onColumnSplitterMoved : function(i, w){
54231 this.userResized = true;
54232 var cm = this.grid.colModel;
54233 cm.setColumnWidth(i, w, true);
54234 var cid = cm.getColumnId(i);
54235 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54236 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54237 this.updateSplitters();
54239 this.grid.fireEvent("columnresize", i, w);
54242 syncRowHeights : function(startIndex, endIndex){
54243 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54244 startIndex = startIndex || 0;
54245 var mrows = this.getBodyTable().rows;
54246 var lrows = this.getLockedTable().rows;
54247 var len = mrows.length-1;
54248 endIndex = Math.min(endIndex || len, len);
54249 for(var i = startIndex; i <= endIndex; i++){
54250 var m = mrows[i], l = lrows[i];
54251 var h = Math.max(m.offsetHeight, l.offsetHeight);
54252 m.style.height = l.style.height = h + "px";
54257 layout : function(initialRender, is2ndPass){
54259 var auto = g.autoHeight;
54260 var scrollOffset = 16;
54261 var c = g.getGridEl(), cm = this.cm,
54262 expandCol = g.autoExpandColumn,
54264 //c.beginMeasure();
54266 if(!c.dom.offsetWidth){ // display:none?
54268 this.lockedWrap.show();
54269 this.mainWrap.show();
54274 var hasLock = this.cm.isLocked(0);
54276 var tbh = this.headerPanel.getHeight();
54277 var bbh = this.footerPanel.getHeight();
54280 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54281 var newHeight = ch + c.getBorderWidth("tb");
54283 newHeight = Math.min(g.maxHeight, newHeight);
54285 c.setHeight(newHeight);
54289 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54292 var s = this.scroller;
54294 var csize = c.getSize(true);
54296 this.el.setSize(csize.width, csize.height);
54298 this.headerPanel.setWidth(csize.width);
54299 this.footerPanel.setWidth(csize.width);
54301 var hdHeight = this.mainHd.getHeight();
54302 var vw = csize.width;
54303 var vh = csize.height - (tbh + bbh);
54307 var bt = this.getBodyTable();
54308 var ltWidth = hasLock ?
54309 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54311 var scrollHeight = bt.offsetHeight;
54312 var scrollWidth = ltWidth + bt.offsetWidth;
54313 var vscroll = false, hscroll = false;
54315 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54317 var lw = this.lockedWrap, mw = this.mainWrap;
54318 var lb = this.lockedBody, mb = this.mainBody;
54320 setTimeout(function(){
54321 var t = s.dom.offsetTop;
54322 var w = s.dom.clientWidth,
54323 h = s.dom.clientHeight;
54326 lw.setSize(ltWidth, h);
54328 mw.setLeftTop(ltWidth, t);
54329 mw.setSize(w-ltWidth, h);
54331 lb.setHeight(h-hdHeight);
54332 mb.setHeight(h-hdHeight);
54334 if(is2ndPass !== true && !gv.userResized && expandCol){
54335 // high speed resize without full column calculation
54337 var ci = cm.getIndexById(expandCol);
54339 ci = cm.findColumnIndex(expandCol);
54341 ci = Math.max(0, ci); // make sure it's got at least the first col.
54342 var expandId = cm.getColumnId(ci);
54343 var tw = cm.getTotalWidth(false);
54344 var currentWidth = cm.getColumnWidth(ci);
54345 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54346 if(currentWidth != cw){
54347 cm.setColumnWidth(ci, cw, true);
54348 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54349 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54350 gv.updateSplitters();
54351 gv.layout(false, true);
54363 onWindowResize : function(){
54364 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54370 appendFooter : function(parentEl){
54374 sortAscText : "Sort Ascending",
54375 sortDescText : "Sort Descending",
54376 lockText : "Lock Column",
54377 unlockText : "Unlock Column",
54378 columnsText : "Columns",
54380 columnsWiderText : "Wider",
54381 columnsNarrowText : "Thinner"
54385 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54386 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54387 this.proxy.el.addClass('x-grid3-col-dd');
54390 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54391 handleMouseDown : function(e){
54395 callHandleMouseDown : function(e){
54396 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54401 * Ext JS Library 1.1.1
54402 * Copyright(c) 2006-2007, Ext JS, LLC.
54404 * Originally Released Under LGPL - original licence link has changed is not relivant.
54407 * <script type="text/javascript">
54411 // This is a support class used internally by the Grid components
54412 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54414 this.view = grid.getView();
54415 this.proxy = this.view.resizeProxy;
54416 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54417 "gridSplitters" + this.grid.getGridEl().id, {
54418 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54420 this.setHandleElId(Roo.id(hd));
54421 this.setOuterHandleElId(Roo.id(hd2));
54422 this.scroll = false;
54424 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54425 fly: Roo.Element.fly,
54427 b4StartDrag : function(x, y){
54428 this.view.headersDisabled = true;
54429 this.proxy.setHeight(this.view.mainWrap.getHeight());
54430 var w = this.cm.getColumnWidth(this.cellIndex);
54431 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54432 this.resetConstraints();
54433 this.setXConstraint(minw, 1000);
54434 this.setYConstraint(0, 0);
54435 this.minX = x - minw;
54436 this.maxX = x + 1000;
54438 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
54442 handleMouseDown : function(e){
54443 ev = Roo.EventObject.setEvent(e);
54444 var t = this.fly(ev.getTarget());
54445 if(t.hasClass("x-grid-split")){
54446 this.cellIndex = this.view.getCellIndex(t.dom);
54447 this.split = t.dom;
54448 this.cm = this.grid.colModel;
54449 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
54450 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
54455 endDrag : function(e){
54456 this.view.headersDisabled = false;
54457 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
54458 var diff = endX - this.startPos;
54459 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
54462 autoOffset : function(){
54463 this.setDelta(0,0);
54467 * Ext JS Library 1.1.1
54468 * Copyright(c) 2006-2007, Ext JS, LLC.
54470 * Originally Released Under LGPL - original licence link has changed is not relivant.
54473 * <script type="text/javascript">
54477 // This is a support class used internally by the Grid components
54478 Roo.grid.GridDragZone = function(grid, config){
54479 this.view = grid.getView();
54480 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
54481 if(this.view.lockedBody){
54482 this.setHandleElId(Roo.id(this.view.mainBody.dom));
54483 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
54485 this.scroll = false;
54487 this.ddel = document.createElement('div');
54488 this.ddel.className = 'x-grid-dd-wrap';
54491 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
54492 ddGroup : "GridDD",
54494 getDragData : function(e){
54495 var t = Roo.lib.Event.getTarget(e);
54496 var rowIndex = this.view.findRowIndex(t);
54497 var sm = this.grid.selModel;
54499 //Roo.log(rowIndex);
54501 if (sm.getSelectedCell) {
54502 // cell selection..
54503 if (!sm.getSelectedCell()) {
54506 if (rowIndex != sm.getSelectedCell()[0]) {
54512 if(rowIndex !== false){
54517 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
54519 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
54522 if (e.hasModifier()){
54523 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
54526 Roo.log("getDragData");
54531 rowIndex: rowIndex,
54532 selections:sm.getSelections ? sm.getSelections() : (
54533 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
54540 onInitDrag : function(e){
54541 var data = this.dragData;
54542 this.ddel.innerHTML = this.grid.getDragDropText();
54543 this.proxy.update(this.ddel);
54544 // fire start drag?
54547 afterRepair : function(){
54548 this.dragging = false;
54551 getRepairXY : function(e, data){
54555 onEndDrag : function(data, e){
54559 onValidDrop : function(dd, e, id){
54564 beforeInvalidDrop : function(e, id){
54569 * Ext JS Library 1.1.1
54570 * Copyright(c) 2006-2007, Ext JS, LLC.
54572 * Originally Released Under LGPL - original licence link has changed is not relivant.
54575 * <script type="text/javascript">
54580 * @class Roo.grid.ColumnModel
54581 * @extends Roo.util.Observable
54582 * This is the default implementation of a ColumnModel used by the Grid. It defines
54583 * the columns in the grid.
54586 var colModel = new Roo.grid.ColumnModel([
54587 {header: "Ticker", width: 60, sortable: true, locked: true},
54588 {header: "Company Name", width: 150, sortable: true},
54589 {header: "Market Cap.", width: 100, sortable: true},
54590 {header: "$ Sales", width: 100, sortable: true, renderer: money},
54591 {header: "Employees", width: 100, sortable: true, resizable: false}
54596 * The config options listed for this class are options which may appear in each
54597 * individual column definition.
54598 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
54600 * @param {Object} config An Array of column config objects. See this class's
54601 * config objects for details.
54603 Roo.grid.ColumnModel = function(config){
54605 * The config passed into the constructor
54607 this.config = config;
54610 // if no id, create one
54611 // if the column does not have a dataIndex mapping,
54612 // map it to the order it is in the config
54613 for(var i = 0, len = config.length; i < len; i++){
54615 if(typeof c.dataIndex == "undefined"){
54618 if(typeof c.renderer == "string"){
54619 c.renderer = Roo.util.Format[c.renderer];
54621 if(typeof c.id == "undefined"){
54624 if(c.editor && c.editor.xtype){
54625 c.editor = Roo.factory(c.editor, Roo.grid);
54627 if(c.editor && c.editor.isFormField){
54628 c.editor = new Roo.grid.GridEditor(c.editor);
54630 this.lookup[c.id] = c;
54634 * The width of columns which have no width specified (defaults to 100)
54637 this.defaultWidth = 100;
54640 * Default sortable of columns which have no sortable specified (defaults to false)
54643 this.defaultSortable = false;
54647 * @event widthchange
54648 * Fires when the width of a column changes.
54649 * @param {ColumnModel} this
54650 * @param {Number} columnIndex The column index
54651 * @param {Number} newWidth The new width
54653 "widthchange": true,
54655 * @event headerchange
54656 * Fires when the text of a header changes.
54657 * @param {ColumnModel} this
54658 * @param {Number} columnIndex The column index
54659 * @param {Number} newText The new header text
54661 "headerchange": true,
54663 * @event hiddenchange
54664 * Fires when a column is hidden or "unhidden".
54665 * @param {ColumnModel} this
54666 * @param {Number} columnIndex The column index
54667 * @param {Boolean} hidden true if hidden, false otherwise
54669 "hiddenchange": true,
54671 * @event columnmoved
54672 * Fires when a column is moved.
54673 * @param {ColumnModel} this
54674 * @param {Number} oldIndex
54675 * @param {Number} newIndex
54677 "columnmoved" : true,
54679 * @event columlockchange
54680 * Fires when a column's locked state is changed
54681 * @param {ColumnModel} this
54682 * @param {Number} colIndex
54683 * @param {Boolean} locked true if locked
54685 "columnlockchange" : true
54687 Roo.grid.ColumnModel.superclass.constructor.call(this);
54689 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
54691 * @cfg {String} header The header text to display in the Grid view.
54694 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
54695 * {@link Roo.data.Record} definition from which to draw the column's value. If not
54696 * specified, the column's index is used as an index into the Record's data Array.
54699 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
54700 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
54703 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
54704 * Defaults to the value of the {@link #defaultSortable} property.
54705 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
54708 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
54711 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
54714 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
54717 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
54720 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
54721 * given the cell's data value. See {@link #setRenderer}. If not specified, the
54722 * default renderer uses the raw data value.
54725 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
54728 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
54732 * Returns the id of the column at the specified index.
54733 * @param {Number} index The column index
54734 * @return {String} the id
54736 getColumnId : function(index){
54737 return this.config[index].id;
54741 * Returns the column for a specified id.
54742 * @param {String} id The column id
54743 * @return {Object} the column
54745 getColumnById : function(id){
54746 return this.lookup[id];
54751 * Returns the column for a specified dataIndex.
54752 * @param {String} dataIndex The column dataIndex
54753 * @return {Object|Boolean} the column or false if not found
54755 getColumnByDataIndex: function(dataIndex){
54756 var index = this.findColumnIndex(dataIndex);
54757 return index > -1 ? this.config[index] : false;
54761 * Returns the index for a specified column id.
54762 * @param {String} id The column id
54763 * @return {Number} the index, or -1 if not found
54765 getIndexById : function(id){
54766 for(var i = 0, len = this.config.length; i < len; i++){
54767 if(this.config[i].id == id){
54775 * Returns the index for a specified column dataIndex.
54776 * @param {String} dataIndex The column dataIndex
54777 * @return {Number} the index, or -1 if not found
54780 findColumnIndex : function(dataIndex){
54781 for(var i = 0, len = this.config.length; i < len; i++){
54782 if(this.config[i].dataIndex == dataIndex){
54790 moveColumn : function(oldIndex, newIndex){
54791 var c = this.config[oldIndex];
54792 this.config.splice(oldIndex, 1);
54793 this.config.splice(newIndex, 0, c);
54794 this.dataMap = null;
54795 this.fireEvent("columnmoved", this, oldIndex, newIndex);
54798 isLocked : function(colIndex){
54799 return this.config[colIndex].locked === true;
54802 setLocked : function(colIndex, value, suppressEvent){
54803 if(this.isLocked(colIndex) == value){
54806 this.config[colIndex].locked = value;
54807 if(!suppressEvent){
54808 this.fireEvent("columnlockchange", this, colIndex, value);
54812 getTotalLockedWidth : function(){
54813 var totalWidth = 0;
54814 for(var i = 0; i < this.config.length; i++){
54815 if(this.isLocked(i) && !this.isHidden(i)){
54816 this.totalWidth += this.getColumnWidth(i);
54822 getLockedCount : function(){
54823 for(var i = 0, len = this.config.length; i < len; i++){
54824 if(!this.isLocked(i)){
54831 * Returns the number of columns.
54834 getColumnCount : function(visibleOnly){
54835 if(visibleOnly === true){
54837 for(var i = 0, len = this.config.length; i < len; i++){
54838 if(!this.isHidden(i)){
54844 return this.config.length;
54848 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
54849 * @param {Function} fn
54850 * @param {Object} scope (optional)
54851 * @return {Array} result
54853 getColumnsBy : function(fn, scope){
54855 for(var i = 0, len = this.config.length; i < len; i++){
54856 var c = this.config[i];
54857 if(fn.call(scope||this, c, i) === true){
54865 * Returns true if the specified column is sortable.
54866 * @param {Number} col The column index
54867 * @return {Boolean}
54869 isSortable : function(col){
54870 if(typeof this.config[col].sortable == "undefined"){
54871 return this.defaultSortable;
54873 return this.config[col].sortable;
54877 * Returns the rendering (formatting) function defined for the column.
54878 * @param {Number} col The column index.
54879 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
54881 getRenderer : function(col){
54882 if(!this.config[col].renderer){
54883 return Roo.grid.ColumnModel.defaultRenderer;
54885 return this.config[col].renderer;
54889 * Sets the rendering (formatting) function for a column.
54890 * @param {Number} col The column index
54891 * @param {Function} fn The function to use to process the cell's raw data
54892 * to return HTML markup for the grid view. The render function is called with
54893 * the following parameters:<ul>
54894 * <li>Data value.</li>
54895 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
54896 * <li>css A CSS style string to apply to the table cell.</li>
54897 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
54898 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
54899 * <li>Row index</li>
54900 * <li>Column index</li>
54901 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
54903 setRenderer : function(col, fn){
54904 this.config[col].renderer = fn;
54908 * Returns the width for the specified column.
54909 * @param {Number} col The column index
54912 getColumnWidth : function(col){
54913 return this.config[col].width * 1 || this.defaultWidth;
54917 * Sets the width for a column.
54918 * @param {Number} col The column index
54919 * @param {Number} width The new width
54921 setColumnWidth : function(col, width, suppressEvent){
54922 this.config[col].width = width;
54923 this.totalWidth = null;
54924 if(!suppressEvent){
54925 this.fireEvent("widthchange", this, col, width);
54930 * Returns the total width of all columns.
54931 * @param {Boolean} includeHidden True to include hidden column widths
54934 getTotalWidth : function(includeHidden){
54935 if(!this.totalWidth){
54936 this.totalWidth = 0;
54937 for(var i = 0, len = this.config.length; i < len; i++){
54938 if(includeHidden || !this.isHidden(i)){
54939 this.totalWidth += this.getColumnWidth(i);
54943 return this.totalWidth;
54947 * Returns the header for the specified column.
54948 * @param {Number} col The column index
54951 getColumnHeader : function(col){
54952 return this.config[col].header;
54956 * Sets the header for a column.
54957 * @param {Number} col The column index
54958 * @param {String} header The new header
54960 setColumnHeader : function(col, header){
54961 this.config[col].header = header;
54962 this.fireEvent("headerchange", this, col, header);
54966 * Returns the tooltip for the specified column.
54967 * @param {Number} col The column index
54970 getColumnTooltip : function(col){
54971 return this.config[col].tooltip;
54974 * Sets the tooltip for a column.
54975 * @param {Number} col The column index
54976 * @param {String} tooltip The new tooltip
54978 setColumnTooltip : function(col, tooltip){
54979 this.config[col].tooltip = tooltip;
54983 * Returns the dataIndex for the specified column.
54984 * @param {Number} col The column index
54987 getDataIndex : function(col){
54988 return this.config[col].dataIndex;
54992 * Sets the dataIndex for a column.
54993 * @param {Number} col The column index
54994 * @param {Number} dataIndex The new dataIndex
54996 setDataIndex : function(col, dataIndex){
54997 this.config[col].dataIndex = dataIndex;
55003 * Returns true if the cell is editable.
55004 * @param {Number} colIndex The column index
55005 * @param {Number} rowIndex The row index
55006 * @return {Boolean}
55008 isCellEditable : function(colIndex, rowIndex){
55009 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55013 * Returns the editor defined for the cell/column.
55014 * return false or null to disable editing.
55015 * @param {Number} colIndex The column index
55016 * @param {Number} rowIndex The row index
55019 getCellEditor : function(colIndex, rowIndex){
55020 return this.config[colIndex].editor;
55024 * Sets if a column is editable.
55025 * @param {Number} col The column index
55026 * @param {Boolean} editable True if the column is editable
55028 setEditable : function(col, editable){
55029 this.config[col].editable = editable;
55034 * Returns true if the column is hidden.
55035 * @param {Number} colIndex The column index
55036 * @return {Boolean}
55038 isHidden : function(colIndex){
55039 return this.config[colIndex].hidden;
55044 * Returns true if the column width cannot be changed
55046 isFixed : function(colIndex){
55047 return this.config[colIndex].fixed;
55051 * Returns true if the column can be resized
55052 * @return {Boolean}
55054 isResizable : function(colIndex){
55055 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55058 * Sets if a column is hidden.
55059 * @param {Number} colIndex The column index
55060 * @param {Boolean} hidden True if the column is hidden
55062 setHidden : function(colIndex, hidden){
55063 this.config[colIndex].hidden = hidden;
55064 this.totalWidth = null;
55065 this.fireEvent("hiddenchange", this, colIndex, hidden);
55069 * Sets the editor for a column.
55070 * @param {Number} col The column index
55071 * @param {Object} editor The editor object
55073 setEditor : function(col, editor){
55074 this.config[col].editor = editor;
55078 Roo.grid.ColumnModel.defaultRenderer = function(value){
55079 if(typeof value == "string" && value.length < 1){
55085 // Alias for backwards compatibility
55086 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55089 * Ext JS Library 1.1.1
55090 * Copyright(c) 2006-2007, Ext JS, LLC.
55092 * Originally Released Under LGPL - original licence link has changed is not relivant.
55095 * <script type="text/javascript">
55099 * @class Roo.grid.AbstractSelectionModel
55100 * @extends Roo.util.Observable
55101 * Abstract base class for grid SelectionModels. It provides the interface that should be
55102 * implemented by descendant classes. This class should not be directly instantiated.
55105 Roo.grid.AbstractSelectionModel = function(){
55106 this.locked = false;
55107 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55110 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55111 /** @ignore Called by the grid automatically. Do not call directly. */
55112 init : function(grid){
55118 * Locks the selections.
55121 this.locked = true;
55125 * Unlocks the selections.
55127 unlock : function(){
55128 this.locked = false;
55132 * Returns true if the selections are locked.
55133 * @return {Boolean}
55135 isLocked : function(){
55136 return this.locked;
55140 * Ext JS Library 1.1.1
55141 * Copyright(c) 2006-2007, Ext JS, LLC.
55143 * Originally Released Under LGPL - original licence link has changed is not relivant.
55146 * <script type="text/javascript">
55149 * @extends Roo.grid.AbstractSelectionModel
55150 * @class Roo.grid.RowSelectionModel
55151 * The default SelectionModel used by {@link Roo.grid.Grid}.
55152 * It supports multiple selections and keyboard selection/navigation.
55154 * @param {Object} config
55156 Roo.grid.RowSelectionModel = function(config){
55157 Roo.apply(this, config);
55158 this.selections = new Roo.util.MixedCollection(false, function(o){
55163 this.lastActive = false;
55167 * @event selectionchange
55168 * Fires when the selection changes
55169 * @param {SelectionModel} this
55171 "selectionchange" : true,
55173 * @event afterselectionchange
55174 * Fires after the selection changes (eg. by key press or clicking)
55175 * @param {SelectionModel} this
55177 "afterselectionchange" : true,
55179 * @event beforerowselect
55180 * Fires when a row is selected being selected, return false to cancel.
55181 * @param {SelectionModel} this
55182 * @param {Number} rowIndex The selected index
55183 * @param {Boolean} keepExisting False if other selections will be cleared
55185 "beforerowselect" : true,
55188 * Fires when a row is selected.
55189 * @param {SelectionModel} this
55190 * @param {Number} rowIndex The selected index
55191 * @param {Roo.data.Record} r The record
55193 "rowselect" : true,
55195 * @event rowdeselect
55196 * Fires when a row is deselected.
55197 * @param {SelectionModel} this
55198 * @param {Number} rowIndex The selected index
55200 "rowdeselect" : true
55202 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55203 this.locked = false;
55206 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55208 * @cfg {Boolean} singleSelect
55209 * True to allow selection of only one row at a time (defaults to false)
55211 singleSelect : false,
55214 initEvents : function(){
55216 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55217 this.grid.on("mousedown", this.handleMouseDown, this);
55218 }else{ // allow click to work like normal
55219 this.grid.on("rowclick", this.handleDragableRowClick, this);
55222 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55223 "up" : function(e){
55225 this.selectPrevious(e.shiftKey);
55226 }else if(this.last !== false && this.lastActive !== false){
55227 var last = this.last;
55228 this.selectRange(this.last, this.lastActive-1);
55229 this.grid.getView().focusRow(this.lastActive);
55230 if(last !== false){
55234 this.selectFirstRow();
55236 this.fireEvent("afterselectionchange", this);
55238 "down" : function(e){
55240 this.selectNext(e.shiftKey);
55241 }else if(this.last !== false && this.lastActive !== false){
55242 var last = this.last;
55243 this.selectRange(this.last, this.lastActive+1);
55244 this.grid.getView().focusRow(this.lastActive);
55245 if(last !== false){
55249 this.selectFirstRow();
55251 this.fireEvent("afterselectionchange", this);
55256 var view = this.grid.view;
55257 view.on("refresh", this.onRefresh, this);
55258 view.on("rowupdated", this.onRowUpdated, this);
55259 view.on("rowremoved", this.onRemove, this);
55263 onRefresh : function(){
55264 var ds = this.grid.dataSource, i, v = this.grid.view;
55265 var s = this.selections;
55266 s.each(function(r){
55267 if((i = ds.indexOfId(r.id)) != -1){
55276 onRemove : function(v, index, r){
55277 this.selections.remove(r);
55281 onRowUpdated : function(v, index, r){
55282 if(this.isSelected(r)){
55283 v.onRowSelect(index);
55289 * @param {Array} records The records to select
55290 * @param {Boolean} keepExisting (optional) True to keep existing selections
55292 selectRecords : function(records, keepExisting){
55294 this.clearSelections();
55296 var ds = this.grid.dataSource;
55297 for(var i = 0, len = records.length; i < len; i++){
55298 this.selectRow(ds.indexOf(records[i]), true);
55303 * Gets the number of selected rows.
55306 getCount : function(){
55307 return this.selections.length;
55311 * Selects the first row in the grid.
55313 selectFirstRow : function(){
55318 * Select the last row.
55319 * @param {Boolean} keepExisting (optional) True to keep existing selections
55321 selectLastRow : function(keepExisting){
55322 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55326 * Selects the row immediately following the last selected row.
55327 * @param {Boolean} keepExisting (optional) True to keep existing selections
55329 selectNext : function(keepExisting){
55330 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55331 this.selectRow(this.last+1, keepExisting);
55332 this.grid.getView().focusRow(this.last);
55337 * Selects the row that precedes the last selected row.
55338 * @param {Boolean} keepExisting (optional) True to keep existing selections
55340 selectPrevious : function(keepExisting){
55342 this.selectRow(this.last-1, keepExisting);
55343 this.grid.getView().focusRow(this.last);
55348 * Returns the selected records
55349 * @return {Array} Array of selected records
55351 getSelections : function(){
55352 return [].concat(this.selections.items);
55356 * Returns the first selected record.
55359 getSelected : function(){
55360 return this.selections.itemAt(0);
55365 * Clears all selections.
55367 clearSelections : function(fast){
55368 if(this.locked) return;
55370 var ds = this.grid.dataSource;
55371 var s = this.selections;
55372 s.each(function(r){
55373 this.deselectRow(ds.indexOfId(r.id));
55377 this.selections.clear();
55384 * Selects all rows.
55386 selectAll : function(){
55387 if(this.locked) return;
55388 this.selections.clear();
55389 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55390 this.selectRow(i, true);
55395 * Returns True if there is a selection.
55396 * @return {Boolean}
55398 hasSelection : function(){
55399 return this.selections.length > 0;
55403 * Returns True if the specified row is selected.
55404 * @param {Number/Record} record The record or index of the record to check
55405 * @return {Boolean}
55407 isSelected : function(index){
55408 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55409 return (r && this.selections.key(r.id) ? true : false);
55413 * Returns True if the specified record id is selected.
55414 * @param {String} id The id of record to check
55415 * @return {Boolean}
55417 isIdSelected : function(id){
55418 return (this.selections.key(id) ? true : false);
55422 handleMouseDown : function(e, t){
55423 var view = this.grid.getView(), rowIndex;
55424 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55427 if(e.shiftKey && this.last !== false){
55428 var last = this.last;
55429 this.selectRange(last, rowIndex, e.ctrlKey);
55430 this.last = last; // reset the last
55431 view.focusRow(rowIndex);
55433 var isSelected = this.isSelected(rowIndex);
55434 if(e.button !== 0 && isSelected){
55435 view.focusRow(rowIndex);
55436 }else if(e.ctrlKey && isSelected){
55437 this.deselectRow(rowIndex);
55438 }else if(!isSelected){
55439 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
55440 view.focusRow(rowIndex);
55443 this.fireEvent("afterselectionchange", this);
55446 handleDragableRowClick : function(grid, rowIndex, e)
55448 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
55449 this.selectRow(rowIndex, false);
55450 grid.view.focusRow(rowIndex);
55451 this.fireEvent("afterselectionchange", this);
55456 * Selects multiple rows.
55457 * @param {Array} rows Array of the indexes of the row to select
55458 * @param {Boolean} keepExisting (optional) True to keep existing selections
55460 selectRows : function(rows, keepExisting){
55462 this.clearSelections();
55464 for(var i = 0, len = rows.length; i < len; i++){
55465 this.selectRow(rows[i], true);
55470 * Selects a range of rows. All rows in between startRow and endRow are also selected.
55471 * @param {Number} startRow The index of the first row in the range
55472 * @param {Number} endRow The index of the last row in the range
55473 * @param {Boolean} keepExisting (optional) True to retain existing selections
55475 selectRange : function(startRow, endRow, keepExisting){
55476 if(this.locked) return;
55478 this.clearSelections();
55480 if(startRow <= endRow){
55481 for(var i = startRow; i <= endRow; i++){
55482 this.selectRow(i, true);
55485 for(var i = startRow; i >= endRow; i--){
55486 this.selectRow(i, true);
55492 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
55493 * @param {Number} startRow The index of the first row in the range
55494 * @param {Number} endRow The index of the last row in the range
55496 deselectRange : function(startRow, endRow, preventViewNotify){
55497 if(this.locked) return;
55498 for(var i = startRow; i <= endRow; i++){
55499 this.deselectRow(i, preventViewNotify);
55505 * @param {Number} row The index of the row to select
55506 * @param {Boolean} keepExisting (optional) True to keep existing selections
55508 selectRow : function(index, keepExisting, preventViewNotify){
55509 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
55510 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
55511 if(!keepExisting || this.singleSelect){
55512 this.clearSelections();
55514 var r = this.grid.dataSource.getAt(index);
55515 this.selections.add(r);
55516 this.last = this.lastActive = index;
55517 if(!preventViewNotify){
55518 this.grid.getView().onRowSelect(index);
55520 this.fireEvent("rowselect", this, index, r);
55521 this.fireEvent("selectionchange", this);
55527 * @param {Number} row The index of the row to deselect
55529 deselectRow : function(index, preventViewNotify){
55530 if(this.locked) return;
55531 if(this.last == index){
55534 if(this.lastActive == index){
55535 this.lastActive = false;
55537 var r = this.grid.dataSource.getAt(index);
55538 this.selections.remove(r);
55539 if(!preventViewNotify){
55540 this.grid.getView().onRowDeselect(index);
55542 this.fireEvent("rowdeselect", this, index);
55543 this.fireEvent("selectionchange", this);
55547 restoreLast : function(){
55549 this.last = this._last;
55554 acceptsNav : function(row, col, cm){
55555 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55559 onEditorKey : function(field, e){
55560 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
55565 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55567 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55569 }else if(k == e.ENTER && !e.ctrlKey){
55573 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
55575 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
55577 }else if(k == e.ESC){
55581 g.startEditing(newCell[0], newCell[1]);
55586 * Ext JS Library 1.1.1
55587 * Copyright(c) 2006-2007, Ext JS, LLC.
55589 * Originally Released Under LGPL - original licence link has changed is not relivant.
55592 * <script type="text/javascript">
55595 * @class Roo.grid.CellSelectionModel
55596 * @extends Roo.grid.AbstractSelectionModel
55597 * This class provides the basic implementation for cell selection in a grid.
55599 * @param {Object} config The object containing the configuration of this model.
55600 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
55602 Roo.grid.CellSelectionModel = function(config){
55603 Roo.apply(this, config);
55605 this.selection = null;
55609 * @event beforerowselect
55610 * Fires before a cell is selected.
55611 * @param {SelectionModel} this
55612 * @param {Number} rowIndex The selected row index
55613 * @param {Number} colIndex The selected cell index
55615 "beforecellselect" : true,
55617 * @event cellselect
55618 * Fires when a cell is selected.
55619 * @param {SelectionModel} this
55620 * @param {Number} rowIndex The selected row index
55621 * @param {Number} colIndex The selected cell index
55623 "cellselect" : true,
55625 * @event selectionchange
55626 * Fires when the active selection changes.
55627 * @param {SelectionModel} this
55628 * @param {Object} selection null for no selection or an object (o) with two properties
55630 <li>o.record: the record object for the row the selection is in</li>
55631 <li>o.cell: An array of [rowIndex, columnIndex]</li>
55634 "selectionchange" : true,
55637 * Fires when the tab (or enter) was pressed on the last editable cell
55638 * You can use this to trigger add new row.
55639 * @param {SelectionModel} this
55643 * @event beforeeditnext
55644 * Fires before the next editable sell is made active
55645 * You can use this to skip to another cell or fire the tabend
55646 * if you set cell to false
55647 * @param {Object} eventdata object : { cell : [ row, col ] }
55649 "beforeeditnext" : true
55651 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
55654 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
55656 enter_is_tab: false,
55659 initEvents : function(){
55660 this.grid.on("mousedown", this.handleMouseDown, this);
55661 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
55662 var view = this.grid.view;
55663 view.on("refresh", this.onViewChange, this);
55664 view.on("rowupdated", this.onRowUpdated, this);
55665 view.on("beforerowremoved", this.clearSelections, this);
55666 view.on("beforerowsinserted", this.clearSelections, this);
55667 if(this.grid.isEditor){
55668 this.grid.on("beforeedit", this.beforeEdit, this);
55673 beforeEdit : function(e){
55674 this.select(e.row, e.column, false, true, e.record);
55678 onRowUpdated : function(v, index, r){
55679 if(this.selection && this.selection.record == r){
55680 v.onCellSelect(index, this.selection.cell[1]);
55685 onViewChange : function(){
55686 this.clearSelections(true);
55690 * Returns the currently selected cell,.
55691 * @return {Array} The selected cell (row, column) or null if none selected.
55693 getSelectedCell : function(){
55694 return this.selection ? this.selection.cell : null;
55698 * Clears all selections.
55699 * @param {Boolean} true to prevent the gridview from being notified about the change.
55701 clearSelections : function(preventNotify){
55702 var s = this.selection;
55704 if(preventNotify !== true){
55705 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
55707 this.selection = null;
55708 this.fireEvent("selectionchange", this, null);
55713 * Returns true if there is a selection.
55714 * @return {Boolean}
55716 hasSelection : function(){
55717 return this.selection ? true : false;
55721 handleMouseDown : function(e, t){
55722 var v = this.grid.getView();
55723 if(this.isLocked()){
55726 var row = v.findRowIndex(t);
55727 var cell = v.findCellIndex(t);
55728 if(row !== false && cell !== false){
55729 this.select(row, cell);
55735 * @param {Number} rowIndex
55736 * @param {Number} collIndex
55738 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
55739 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
55740 this.clearSelections();
55741 r = r || this.grid.dataSource.getAt(rowIndex);
55744 cell : [rowIndex, colIndex]
55746 if(!preventViewNotify){
55747 var v = this.grid.getView();
55748 v.onCellSelect(rowIndex, colIndex);
55749 if(preventFocus !== true){
55750 v.focusCell(rowIndex, colIndex);
55753 this.fireEvent("cellselect", this, rowIndex, colIndex);
55754 this.fireEvent("selectionchange", this, this.selection);
55759 isSelectable : function(rowIndex, colIndex, cm){
55760 return !cm.isHidden(colIndex);
55764 handleKeyDown : function(e){
55765 //Roo.log('Cell Sel Model handleKeyDown');
55766 if(!e.isNavKeyPress()){
55769 var g = this.grid, s = this.selection;
55772 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
55774 this.select(cell[0], cell[1]);
55779 var walk = function(row, col, step){
55780 return g.walkCells(row, col, step, sm.isSelectable, sm);
55782 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
55789 // handled by onEditorKey
55790 if (g.isEditor && g.editing) {
55794 newCell = walk(r, c-1, -1);
55796 newCell = walk(r, c+1, 1);
55801 newCell = walk(r+1, c, 1);
55805 newCell = walk(r-1, c, -1);
55809 newCell = walk(r, c+1, 1);
55813 newCell = walk(r, c-1, -1);
55818 if(g.isEditor && !g.editing){
55819 g.startEditing(r, c);
55828 this.select(newCell[0], newCell[1]);
55834 acceptsNav : function(row, col, cm){
55835 return !cm.isHidden(col) && cm.isCellEditable(col, row);
55839 * @param {Number} field (not used) - as it's normally used as a listener
55840 * @param {Number} e - event - fake it by using
55842 * var e = Roo.EventObjectImpl.prototype;
55843 * e.keyCode = e.TAB
55847 onEditorKey : function(field, e){
55849 var k = e.getKey(),
55852 ed = g.activeEditor,
55854 ///Roo.log('onEditorKey' + k);
55857 if (this.enter_is_tab && k == e.ENTER) {
55863 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
55865 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55871 } else if(k == e.ENTER && !e.ctrlKey){
55874 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
55876 } else if(k == e.ESC){
55881 var ecall = { cell : newCell, forward : forward };
55882 this.fireEvent('beforeeditnext', ecall );
55883 newCell = ecall.cell;
55884 forward = ecall.forward;
55888 //Roo.log('next cell after edit');
55889 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
55890 } else if (forward) {
55891 // tabbed past last
55892 this.fireEvent.defer(100, this, ['tabend',this]);
55897 * Ext JS Library 1.1.1
55898 * Copyright(c) 2006-2007, Ext JS, LLC.
55900 * Originally Released Under LGPL - original licence link has changed is not relivant.
55903 * <script type="text/javascript">
55907 * @class Roo.grid.EditorGrid
55908 * @extends Roo.grid.Grid
55909 * Class for creating and editable grid.
55910 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55911 * The container MUST have some type of size defined for the grid to fill. The container will be
55912 * automatically set to position relative if it isn't already.
55913 * @param {Object} dataSource The data model to bind to
55914 * @param {Object} colModel The column model with info about this grid's columns
55916 Roo.grid.EditorGrid = function(container, config){
55917 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
55918 this.getGridEl().addClass("xedit-grid");
55920 if(!this.selModel){
55921 this.selModel = new Roo.grid.CellSelectionModel();
55924 this.activeEditor = null;
55928 * @event beforeedit
55929 * Fires before cell editing is triggered. The edit event object has the following properties <br />
55930 * <ul style="padding:5px;padding-left:16px;">
55931 * <li>grid - This grid</li>
55932 * <li>record - The record being edited</li>
55933 * <li>field - The field name being edited</li>
55934 * <li>value - The value for the field being edited.</li>
55935 * <li>row - The grid row index</li>
55936 * <li>column - The grid column index</li>
55937 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55939 * @param {Object} e An edit event (see above for description)
55941 "beforeedit" : true,
55944 * Fires after a cell is edited. <br />
55945 * <ul style="padding:5px;padding-left:16px;">
55946 * <li>grid - This grid</li>
55947 * <li>record - The record being edited</li>
55948 * <li>field - The field name being edited</li>
55949 * <li>value - The value being set</li>
55950 * <li>originalValue - The original value for the field, before the edit.</li>
55951 * <li>row - The grid row index</li>
55952 * <li>column - The grid column index</li>
55954 * @param {Object} e An edit event (see above for description)
55956 "afteredit" : true,
55958 * @event validateedit
55959 * Fires after a cell is edited, but before the value is set in the record.
55960 * You can use this to modify the value being set in the field, Return false
55961 * to cancel the change. The edit event object has the following properties <br />
55962 * <ul style="padding:5px;padding-left:16px;">
55963 * <li>editor - This editor</li>
55964 * <li>grid - This grid</li>
55965 * <li>record - The record being edited</li>
55966 * <li>field - The field name being edited</li>
55967 * <li>value - The value being set</li>
55968 * <li>originalValue - The original value for the field, before the edit.</li>
55969 * <li>row - The grid row index</li>
55970 * <li>column - The grid column index</li>
55971 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
55973 * @param {Object} e An edit event (see above for description)
55975 "validateedit" : true
55977 this.on("bodyscroll", this.stopEditing, this);
55978 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
55981 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
55983 * @cfg {Number} clicksToEdit
55984 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
55991 trackMouseOver: false, // causes very odd FF errors
55993 onCellDblClick : function(g, row, col){
55994 this.startEditing(row, col);
55997 onEditComplete : function(ed, value, startValue){
55998 this.editing = false;
55999 this.activeEditor = null;
56000 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56002 var field = this.colModel.getDataIndex(ed.col);
56007 originalValue: startValue,
56014 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56017 if(String(value) !== String(startValue)){
56019 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56020 r.set(field, e.value);
56021 // if we are dealing with a combo box..
56022 // then we also set the 'name' colum to be the displayField
56023 if (ed.field.displayField && ed.field.name) {
56024 r.set(ed.field.name, ed.field.el.dom.value);
56027 delete e.cancel; //?? why!!!
56028 this.fireEvent("afteredit", e);
56031 this.fireEvent("afteredit", e); // always fire it!
56033 this.view.focusCell(ed.row, ed.col);
56037 * Starts editing the specified for the specified row/column
56038 * @param {Number} rowIndex
56039 * @param {Number} colIndex
56041 startEditing : function(row, col){
56042 this.stopEditing();
56043 if(this.colModel.isCellEditable(col, row)){
56044 this.view.ensureVisible(row, col, true);
56046 var r = this.dataSource.getAt(row);
56047 var field = this.colModel.getDataIndex(col);
56048 var cell = Roo.get(this.view.getCell(row,col));
56053 value: r.data[field],
56058 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56059 this.editing = true;
56060 var ed = this.colModel.getCellEditor(col, row);
56066 ed.render(ed.parentEl || document.body);
56072 (function(){ // complex but required for focus issues in safari, ie and opera
56076 ed.on("complete", this.onEditComplete, this, {single: true});
56077 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56078 this.activeEditor = ed;
56079 var v = r.data[field];
56080 ed.startEdit(this.view.getCell(row, col), v);
56081 // combo's with 'displayField and name set
56082 if (ed.field.displayField && ed.field.name) {
56083 ed.field.el.dom.value = r.data[ed.field.name];
56087 }).defer(50, this);
56093 * Stops any active editing
56095 stopEditing : function(){
56096 if(this.activeEditor){
56097 this.activeEditor.completeEdit();
56099 this.activeEditor = null;
56103 * Called to get grid's drag proxy text, by default returns this.ddText.
56106 getDragDropText : function(){
56107 var count = this.selModel.getSelectedCell() ? 1 : 0;
56108 return String.format(this.ddText, count, count == 1 ? '' : 's');
56113 * Ext JS Library 1.1.1
56114 * Copyright(c) 2006-2007, Ext JS, LLC.
56116 * Originally Released Under LGPL - original licence link has changed is not relivant.
56119 * <script type="text/javascript">
56122 // private - not really -- you end up using it !
56123 // This is a support class used internally by the Grid components
56126 * @class Roo.grid.GridEditor
56127 * @extends Roo.Editor
56128 * Class for creating and editable grid elements.
56129 * @param {Object} config any settings (must include field)
56131 Roo.grid.GridEditor = function(field, config){
56132 if (!config && field.field) {
56134 field = Roo.factory(config.field, Roo.form);
56136 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56137 field.monitorTab = false;
56140 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56143 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56146 alignment: "tl-tl",
56149 cls: "x-small-editor x-grid-editor",
56154 * Ext JS Library 1.1.1
56155 * Copyright(c) 2006-2007, Ext JS, LLC.
56157 * Originally Released Under LGPL - original licence link has changed is not relivant.
56160 * <script type="text/javascript">
56165 Roo.grid.PropertyRecord = Roo.data.Record.create([
56166 {name:'name',type:'string'}, 'value'
56170 Roo.grid.PropertyStore = function(grid, source){
56172 this.store = new Roo.data.Store({
56173 recordType : Roo.grid.PropertyRecord
56175 this.store.on('update', this.onUpdate, this);
56177 this.setSource(source);
56179 Roo.grid.PropertyStore.superclass.constructor.call(this);
56184 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56185 setSource : function(o){
56187 this.store.removeAll();
56190 if(this.isEditableValue(o[k])){
56191 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56194 this.store.loadRecords({records: data}, {}, true);
56197 onUpdate : function(ds, record, type){
56198 if(type == Roo.data.Record.EDIT){
56199 var v = record.data['value'];
56200 var oldValue = record.modified['value'];
56201 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56202 this.source[record.id] = v;
56204 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56211 getProperty : function(row){
56212 return this.store.getAt(row);
56215 isEditableValue: function(val){
56216 if(val && val instanceof Date){
56218 }else if(typeof val == 'object' || typeof val == 'function'){
56224 setValue : function(prop, value){
56225 this.source[prop] = value;
56226 this.store.getById(prop).set('value', value);
56229 getSource : function(){
56230 return this.source;
56234 Roo.grid.PropertyColumnModel = function(grid, store){
56237 g.PropertyColumnModel.superclass.constructor.call(this, [
56238 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56239 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56241 this.store = store;
56242 this.bselect = Roo.DomHelper.append(document.body, {
56243 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56244 {tag: 'option', value: 'true', html: 'true'},
56245 {tag: 'option', value: 'false', html: 'false'}
56248 Roo.id(this.bselect);
56251 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56252 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56253 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56254 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56255 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56257 this.renderCellDelegate = this.renderCell.createDelegate(this);
56258 this.renderPropDelegate = this.renderProp.createDelegate(this);
56261 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56265 valueText : 'Value',
56267 dateFormat : 'm/j/Y',
56270 renderDate : function(dateVal){
56271 return dateVal.dateFormat(this.dateFormat);
56274 renderBool : function(bVal){
56275 return bVal ? 'true' : 'false';
56278 isCellEditable : function(colIndex, rowIndex){
56279 return colIndex == 1;
56282 getRenderer : function(col){
56284 this.renderCellDelegate : this.renderPropDelegate;
56287 renderProp : function(v){
56288 return this.getPropertyName(v);
56291 renderCell : function(val){
56293 if(val instanceof Date){
56294 rv = this.renderDate(val);
56295 }else if(typeof val == 'boolean'){
56296 rv = this.renderBool(val);
56298 return Roo.util.Format.htmlEncode(rv);
56301 getPropertyName : function(name){
56302 var pn = this.grid.propertyNames;
56303 return pn && pn[name] ? pn[name] : name;
56306 getCellEditor : function(colIndex, rowIndex){
56307 var p = this.store.getProperty(rowIndex);
56308 var n = p.data['name'], val = p.data['value'];
56310 if(typeof(this.grid.customEditors[n]) == 'string'){
56311 return this.editors[this.grid.customEditors[n]];
56313 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56314 return this.grid.customEditors[n];
56316 if(val instanceof Date){
56317 return this.editors['date'];
56318 }else if(typeof val == 'number'){
56319 return this.editors['number'];
56320 }else if(typeof val == 'boolean'){
56321 return this.editors['boolean'];
56323 return this.editors['string'];
56329 * @class Roo.grid.PropertyGrid
56330 * @extends Roo.grid.EditorGrid
56331 * This class represents the interface of a component based property grid control.
56332 * <br><br>Usage:<pre><code>
56333 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56341 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56342 * The container MUST have some type of size defined for the grid to fill. The container will be
56343 * automatically set to position relative if it isn't already.
56344 * @param {Object} config A config object that sets properties on this grid.
56346 Roo.grid.PropertyGrid = function(container, config){
56347 config = config || {};
56348 var store = new Roo.grid.PropertyStore(this);
56349 this.store = store;
56350 var cm = new Roo.grid.PropertyColumnModel(this, store);
56351 store.store.sort('name', 'ASC');
56352 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56355 enableColLock:false,
56356 enableColumnMove:false,
56358 trackMouseOver: false,
56361 this.getGridEl().addClass('x-props-grid');
56362 this.lastEditRow = null;
56363 this.on('columnresize', this.onColumnResize, this);
56366 * @event beforepropertychange
56367 * Fires before a property changes (return false to stop?)
56368 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56369 * @param {String} id Record Id
56370 * @param {String} newval New Value
56371 * @param {String} oldval Old Value
56373 "beforepropertychange": true,
56375 * @event propertychange
56376 * Fires after a property changes
56377 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56378 * @param {String} id Record Id
56379 * @param {String} newval New Value
56380 * @param {String} oldval Old Value
56382 "propertychange": true
56384 this.customEditors = this.customEditors || {};
56386 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56389 * @cfg {Object} customEditors map of colnames=> custom editors.
56390 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56391 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56392 * false disables editing of the field.
56396 * @cfg {Object} propertyNames map of property Names to their displayed value
56399 render : function(){
56400 Roo.grid.PropertyGrid.superclass.render.call(this);
56401 this.autoSize.defer(100, this);
56404 autoSize : function(){
56405 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56407 this.view.fitColumns();
56411 onColumnResize : function(){
56412 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56416 * Sets the data for the Grid
56417 * accepts a Key => Value object of all the elements avaiable.
56418 * @param {Object} data to appear in grid.
56420 setSource : function(source){
56421 this.store.setSource(source);
56425 * Gets all the data from the grid.
56426 * @return {Object} data data stored in grid
56428 getSource : function(){
56429 return this.store.getSource();
56438 * @class Roo.grid.Calendar
56439 * @extends Roo.util.Grid
56440 * This class extends the Grid to provide a calendar widget
56441 * <br><br>Usage:<pre><code>
56442 var grid = new Roo.grid.Calendar("my-container-id", {
56445 selModel: mySelectionModel,
56446 autoSizeColumns: true,
56447 monitorWindowResize: false,
56448 trackMouseOver: true
56449 eventstore : real data store..
56455 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56456 * The container MUST have some type of size defined for the grid to fill. The container will be
56457 * automatically set to position relative if it isn't already.
56458 * @param {Object} config A config object that sets properties on this grid.
56460 Roo.grid.Calendar = function(container, config){
56461 // initialize the container
56462 this.container = Roo.get(container);
56463 this.container.update("");
56464 this.container.setStyle("overflow", "hidden");
56465 this.container.addClass('x-grid-container');
56467 this.id = this.container.id;
56469 Roo.apply(this, config);
56470 // check and correct shorthanded configs
56474 for (var r = 0;r < 6;r++) {
56477 for (var c =0;c < 7;c++) {
56481 if (this.eventStore) {
56482 this.eventStore= Roo.factory(this.eventStore, Roo.data);
56483 this.eventStore.on('load',this.onLoad, this);
56484 this.eventStore.on('beforeload',this.clearEvents, this);
56488 this.dataSource = new Roo.data.Store({
56489 proxy: new Roo.data.MemoryProxy(rows),
56490 reader: new Roo.data.ArrayReader({}, [
56491 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
56494 this.dataSource.load();
56495 this.ds = this.dataSource;
56496 this.ds.xmodule = this.xmodule || false;
56499 var cellRender = function(v,x,r)
56501 return String.format(
56502 '<div class="fc-day fc-widget-content"><div>' +
56503 '<div class="fc-event-container"></div>' +
56504 '<div class="fc-day-number">{0}</div>'+
56506 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
56507 '</div></div>', v);
56512 this.colModel = new Roo.grid.ColumnModel( [
56514 xtype: 'ColumnModel',
56516 dataIndex : 'weekday0',
56518 renderer : cellRender
56521 xtype: 'ColumnModel',
56523 dataIndex : 'weekday1',
56525 renderer : cellRender
56528 xtype: 'ColumnModel',
56530 dataIndex : 'weekday2',
56531 header : 'Tuesday',
56532 renderer : cellRender
56535 xtype: 'ColumnModel',
56537 dataIndex : 'weekday3',
56538 header : 'Wednesday',
56539 renderer : cellRender
56542 xtype: 'ColumnModel',
56544 dataIndex : 'weekday4',
56545 header : 'Thursday',
56546 renderer : cellRender
56549 xtype: 'ColumnModel',
56551 dataIndex : 'weekday5',
56553 renderer : cellRender
56556 xtype: 'ColumnModel',
56558 dataIndex : 'weekday6',
56559 header : 'Saturday',
56560 renderer : cellRender
56563 this.cm = this.colModel;
56564 this.cm.xmodule = this.xmodule || false;
56568 //this.selModel = new Roo.grid.CellSelectionModel();
56569 //this.sm = this.selModel;
56570 //this.selModel.init(this);
56574 this.container.setWidth(this.width);
56578 this.container.setHeight(this.height);
56585 * The raw click event for the entire grid.
56586 * @param {Roo.EventObject} e
56591 * The raw dblclick event for the entire grid.
56592 * @param {Roo.EventObject} e
56596 * @event contextmenu
56597 * The raw contextmenu event for the entire grid.
56598 * @param {Roo.EventObject} e
56600 "contextmenu" : true,
56603 * The raw mousedown event for the entire grid.
56604 * @param {Roo.EventObject} e
56606 "mousedown" : true,
56609 * The raw mouseup event for the entire grid.
56610 * @param {Roo.EventObject} e
56615 * The raw mouseover event for the entire grid.
56616 * @param {Roo.EventObject} e
56618 "mouseover" : true,
56621 * The raw mouseout event for the entire grid.
56622 * @param {Roo.EventObject} e
56627 * The raw keypress event for the entire grid.
56628 * @param {Roo.EventObject} e
56633 * The raw keydown event for the entire grid.
56634 * @param {Roo.EventObject} e
56642 * Fires when a cell is clicked
56643 * @param {Grid} this
56644 * @param {Number} rowIndex
56645 * @param {Number} columnIndex
56646 * @param {Roo.EventObject} e
56648 "cellclick" : true,
56650 * @event celldblclick
56651 * Fires when a cell is double clicked
56652 * @param {Grid} this
56653 * @param {Number} rowIndex
56654 * @param {Number} columnIndex
56655 * @param {Roo.EventObject} e
56657 "celldblclick" : true,
56660 * Fires when a row is clicked
56661 * @param {Grid} this
56662 * @param {Number} rowIndex
56663 * @param {Roo.EventObject} e
56667 * @event rowdblclick
56668 * Fires when a row is double clicked
56669 * @param {Grid} this
56670 * @param {Number} rowIndex
56671 * @param {Roo.EventObject} e
56673 "rowdblclick" : true,
56675 * @event headerclick
56676 * Fires when a header is clicked
56677 * @param {Grid} this
56678 * @param {Number} columnIndex
56679 * @param {Roo.EventObject} e
56681 "headerclick" : true,
56683 * @event headerdblclick
56684 * Fires when a header cell is double clicked
56685 * @param {Grid} this
56686 * @param {Number} columnIndex
56687 * @param {Roo.EventObject} e
56689 "headerdblclick" : true,
56691 * @event rowcontextmenu
56692 * Fires when a row is right clicked
56693 * @param {Grid} this
56694 * @param {Number} rowIndex
56695 * @param {Roo.EventObject} e
56697 "rowcontextmenu" : true,
56699 * @event cellcontextmenu
56700 * Fires when a cell is right clicked
56701 * @param {Grid} this
56702 * @param {Number} rowIndex
56703 * @param {Number} cellIndex
56704 * @param {Roo.EventObject} e
56706 "cellcontextmenu" : true,
56708 * @event headercontextmenu
56709 * Fires when a header is right clicked
56710 * @param {Grid} this
56711 * @param {Number} columnIndex
56712 * @param {Roo.EventObject} e
56714 "headercontextmenu" : true,
56716 * @event bodyscroll
56717 * Fires when the body element is scrolled
56718 * @param {Number} scrollLeft
56719 * @param {Number} scrollTop
56721 "bodyscroll" : true,
56723 * @event columnresize
56724 * Fires when the user resizes a column
56725 * @param {Number} columnIndex
56726 * @param {Number} newSize
56728 "columnresize" : true,
56730 * @event columnmove
56731 * Fires when the user moves a column
56732 * @param {Number} oldIndex
56733 * @param {Number} newIndex
56735 "columnmove" : true,
56738 * Fires when row(s) start being dragged
56739 * @param {Grid} this
56740 * @param {Roo.GridDD} dd The drag drop object
56741 * @param {event} e The raw browser event
56743 "startdrag" : true,
56746 * Fires when a drag operation is complete
56747 * @param {Grid} this
56748 * @param {Roo.GridDD} dd The drag drop object
56749 * @param {event} e The raw browser event
56754 * Fires when dragged row(s) are dropped on a valid DD target
56755 * @param {Grid} this
56756 * @param {Roo.GridDD} dd The drag drop object
56757 * @param {String} targetId The target drag drop object
56758 * @param {event} e The raw browser event
56763 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
56764 * @param {Grid} this
56765 * @param {Roo.GridDD} dd The drag drop object
56766 * @param {String} targetId The target drag drop object
56767 * @param {event} e The raw browser event
56772 * Fires when the dragged row(s) first cross another DD target while being dragged
56773 * @param {Grid} this
56774 * @param {Roo.GridDD} dd The drag drop object
56775 * @param {String} targetId The target drag drop object
56776 * @param {event} e The raw browser event
56778 "dragenter" : true,
56781 * Fires when the dragged row(s) leave another DD target while being dragged
56782 * @param {Grid} this
56783 * @param {Roo.GridDD} dd The drag drop object
56784 * @param {String} targetId The target drag drop object
56785 * @param {event} e The raw browser event
56790 * Fires when a row is rendered, so you can change add a style to it.
56791 * @param {GridView} gridview The grid view
56792 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
56798 * Fires when the grid is rendered
56799 * @param {Grid} grid
56804 * Fires when a date is selected
56805 * @param {DatePicker} this
56806 * @param {Date} date The selected date
56810 * @event monthchange
56811 * Fires when the displayed month changes
56812 * @param {DatePicker} this
56813 * @param {Date} date The selected month
56815 'monthchange': true,
56817 * @event evententer
56818 * Fires when mouse over an event
56819 * @param {Calendar} this
56820 * @param {event} Event
56822 'evententer': true,
56824 * @event eventleave
56825 * Fires when the mouse leaves an
56826 * @param {Calendar} this
56829 'eventleave': true,
56831 * @event eventclick
56832 * Fires when the mouse click an
56833 * @param {Calendar} this
56836 'eventclick': true,
56838 * @event eventrender
56839 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
56840 * @param {Calendar} this
56841 * @param {data} data to be modified
56843 'eventrender': true
56847 Roo.grid.Grid.superclass.constructor.call(this);
56848 this.on('render', function() {
56849 this.view.el.addClass('x-grid-cal');
56851 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
56855 if (!Roo.grid.Calendar.style) {
56856 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
56859 '.x-grid-cal .x-grid-col' : {
56860 height: 'auto !important',
56861 'vertical-align': 'top'
56863 '.x-grid-cal .fc-event-hori' : {
56874 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
56876 * @cfg {Store} eventStore The store that loads events.
56881 activeDate : false,
56884 monitorWindowResize : false,
56887 resizeColumns : function() {
56888 var col = (this.view.el.getWidth() / 7) - 3;
56889 // loop through cols, and setWidth
56890 for(var i =0 ; i < 7 ; i++){
56891 this.cm.setColumnWidth(i, col);
56894 setDate :function(date) {
56896 Roo.log('setDate?');
56898 this.resizeColumns();
56899 var vd = this.activeDate;
56900 this.activeDate = date;
56901 // if(vd && this.el){
56902 // var t = date.getTime();
56903 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
56904 // Roo.log('using add remove');
56906 // this.fireEvent('monthchange', this, date);
56908 // this.cells.removeClass("fc-state-highlight");
56909 // this.cells.each(function(c){
56910 // if(c.dateValue == t){
56911 // c.addClass("fc-state-highlight");
56912 // setTimeout(function(){
56913 // try{c.dom.firstChild.focus();}catch(e){}
56923 var days = date.getDaysInMonth();
56925 var firstOfMonth = date.getFirstDateOfMonth();
56926 var startingPos = firstOfMonth.getDay()-this.startDay;
56928 if(startingPos < this.startDay){
56932 var pm = date.add(Date.MONTH, -1);
56933 var prevStart = pm.getDaysInMonth()-startingPos;
56937 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
56939 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
56940 //this.cells.addClassOnOver('fc-state-hover');
56942 var cells = this.cells.elements;
56943 var textEls = this.textNodes;
56945 //Roo.each(cells, function(cell){
56946 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
56949 days += startingPos;
56951 // convert everything to numbers so it's fast
56952 var day = 86400000;
56953 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
56956 //Roo.log(prevStart);
56958 var today = new Date().clearTime().getTime();
56959 var sel = date.clearTime().getTime();
56960 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
56961 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
56962 var ddMatch = this.disabledDatesRE;
56963 var ddText = this.disabledDatesText;
56964 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
56965 var ddaysText = this.disabledDaysText;
56966 var format = this.format;
56968 var setCellClass = function(cal, cell){
56970 //Roo.log('set Cell Class');
56972 var t = d.getTime();
56977 cell.dateValue = t;
56979 cell.className += " fc-today";
56980 cell.className += " fc-state-highlight";
56981 cell.title = cal.todayText;
56984 // disable highlight in other month..
56985 cell.className += " fc-state-highlight";
56990 //cell.className = " fc-state-disabled";
56991 cell.title = cal.minText;
56995 //cell.className = " fc-state-disabled";
56996 cell.title = cal.maxText;
57000 if(ddays.indexOf(d.getDay()) != -1){
57001 // cell.title = ddaysText;
57002 // cell.className = " fc-state-disabled";
57005 if(ddMatch && format){
57006 var fvalue = d.dateFormat(format);
57007 if(ddMatch.test(fvalue)){
57008 cell.title = ddText.replace("%0", fvalue);
57009 cell.className = " fc-state-disabled";
57013 if (!cell.initialClassName) {
57014 cell.initialClassName = cell.dom.className;
57017 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57022 for(; i < startingPos; i++) {
57023 cells[i].dayName = (++prevStart);
57024 Roo.log(textEls[i]);
57025 d.setDate(d.getDate()+1);
57027 //cells[i].className = "fc-past fc-other-month";
57028 setCellClass(this, cells[i]);
57033 for(; i < days; i++){
57034 intDay = i - startingPos + 1;
57035 cells[i].dayName = (intDay);
57036 d.setDate(d.getDate()+1);
57038 cells[i].className = ''; // "x-date-active";
57039 setCellClass(this, cells[i]);
57043 for(; i < 42; i++) {
57044 //textEls[i].innerHTML = (++extraDays);
57046 d.setDate(d.getDate()+1);
57047 cells[i].dayName = (++extraDays);
57048 cells[i].className = "fc-future fc-other-month";
57049 setCellClass(this, cells[i]);
57052 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57054 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57056 // this will cause all the cells to mis
57059 for (var r = 0;r < 6;r++) {
57060 for (var c =0;c < 7;c++) {
57061 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57065 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57066 for(i=0;i<cells.length;i++) {
57068 this.cells.elements[i].dayName = cells[i].dayName ;
57069 this.cells.elements[i].className = cells[i].className;
57070 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57071 this.cells.elements[i].title = cells[i].title ;
57072 this.cells.elements[i].dateValue = cells[i].dateValue ;
57078 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57079 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57081 ////if(totalRows != 6){
57082 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57083 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57086 this.fireEvent('monthchange', this, date);
57091 * Returns the grid's SelectionModel.
57092 * @return {SelectionModel}
57094 getSelectionModel : function(){
57095 if(!this.selModel){
57096 this.selModel = new Roo.grid.CellSelectionModel();
57098 return this.selModel;
57102 this.eventStore.load()
57108 findCell : function(dt) {
57109 dt = dt.clearTime().getTime();
57111 this.cells.each(function(c){
57112 //Roo.log("check " +c.dateValue + '?=' + dt);
57113 if(c.dateValue == dt){
57123 findCells : function(rec) {
57124 var s = rec.data.start_dt.clone().clearTime().getTime();
57126 var e= rec.data.end_dt.clone().clearTime().getTime();
57129 this.cells.each(function(c){
57130 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57132 if(c.dateValue > e){
57135 if(c.dateValue < s){
57144 findBestRow: function(cells)
57148 for (var i =0 ; i < cells.length;i++) {
57149 ret = Math.max(cells[i].rows || 0,ret);
57156 addItem : function(rec)
57158 // look for vertical location slot in
57159 var cells = this.findCells(rec);
57161 rec.row = this.findBestRow(cells);
57163 // work out the location.
57167 for(var i =0; i < cells.length; i++) {
57175 if (crow.start.getY() == cells[i].getY()) {
57177 crow.end = cells[i];
57193 for (var i = 0; i < cells.length;i++) {
57194 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57201 clearEvents: function() {
57203 if (!this.eventStore.getCount()) {
57206 // reset number of rows in cells.
57207 Roo.each(this.cells.elements, function(c){
57211 this.eventStore.each(function(e) {
57212 this.clearEvent(e);
57217 clearEvent : function(ev)
57220 Roo.each(ev.els, function(el) {
57221 el.un('mouseenter' ,this.onEventEnter, this);
57222 el.un('mouseleave' ,this.onEventLeave, this);
57230 renderEvent : function(ev,ctr) {
57232 ctr = this.view.el.select('.fc-event-container',true).first();
57236 this.clearEvent(ev);
57242 var cells = ev.cells;
57243 var rows = ev.rows;
57244 this.fireEvent('eventrender', this, ev);
57246 for(var i =0; i < rows.length; i++) {
57250 cls += ' fc-event-start';
57252 if ((i+1) == rows.length) {
57253 cls += ' fc-event-end';
57256 //Roo.log(ev.data);
57257 // how many rows should it span..
57258 var cg = this.eventTmpl.append(ctr,Roo.apply({
57261 }, ev.data) , true);
57264 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57265 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57266 cg.on('click', this.onEventClick, this, ev);
57270 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57271 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57274 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57275 cg.setWidth(ebox.right - sbox.x -2);
57279 renderEvents: function()
57281 // first make sure there is enough space..
57283 if (!this.eventTmpl) {
57284 this.eventTmpl = new Roo.Template(
57285 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57286 '<div class="fc-event-inner">' +
57287 '<span class="fc-event-time">{time}</span>' +
57288 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57290 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57298 this.cells.each(function(c) {
57299 //Roo.log(c.select('.fc-day-content div',true).first());
57300 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57303 var ctr = this.view.el.select('.fc-event-container',true).first();
57306 this.eventStore.each(function(ev){
57308 this.renderEvent(ev);
57312 this.view.layout();
57316 onEventEnter: function (e, el,event,d) {
57317 this.fireEvent('evententer', this, el, event);
57320 onEventLeave: function (e, el,event,d) {
57321 this.fireEvent('eventleave', this, el, event);
57324 onEventClick: function (e, el,event,d) {
57325 this.fireEvent('eventclick', this, el, event);
57328 onMonthChange: function () {
57332 onLoad: function () {
57334 //Roo.log('calendar onload');
57336 if(this.eventStore.getCount() > 0){
57340 this.eventStore.each(function(d){
57345 if (typeof(add.end_dt) == 'undefined') {
57346 Roo.log("Missing End time in calendar data: ");
57350 if (typeof(add.start_dt) == 'undefined') {
57351 Roo.log("Missing Start time in calendar data: ");
57355 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57356 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57357 add.id = add.id || d.id;
57358 add.title = add.title || '??';
57366 this.renderEvents();
57376 render : function ()
57380 if (!this.view.el.hasClass('course-timesheet')) {
57381 this.view.el.addClass('course-timesheet');
57383 if (this.tsStyle) {
57388 Roo.log(_this.grid.view.el.getWidth());
57391 this.tsStyle = Roo.util.CSS.createStyleSheet({
57392 '.course-timesheet .x-grid-row' : {
57395 '.x-grid-row td' : {
57396 'vertical-align' : 0
57398 '.course-edit-link' : {
57400 'text-overflow' : 'ellipsis',
57401 'overflow' : 'hidden',
57402 'white-space' : 'nowrap',
57403 'cursor' : 'pointer'
57408 '.de-act-sup-link' : {
57409 'color' : 'purple',
57410 'text-decoration' : 'line-through'
57414 'text-decoration' : 'line-through'
57416 '.course-timesheet .course-highlight' : {
57417 'border-top-style': 'dashed !important',
57418 'border-bottom-bottom': 'dashed !important'
57420 '.course-timesheet .course-item' : {
57421 'font-family' : 'tahoma, arial, helvetica',
57422 'font-size' : '11px',
57423 'overflow' : 'hidden',
57424 'padding-left' : '10px',
57425 'padding-right' : '10px',
57426 'padding-top' : '10px'
57434 monitorWindowResize : false,
57435 cellrenderer : function(v,x,r)
57440 xtype: 'CellSelectionModel',
57447 beforeload : function (_self, options)
57449 options.params = options.params || {};
57450 options.params._month = _this.monthField.getValue();
57451 options.params.limit = 9999;
57452 options.params['sort'] = 'when_dt';
57453 options.params['dir'] = 'ASC';
57454 this.proxy.loadResponse = this.loadResponse;
57456 //this.addColumns();
57458 load : function (_self, records, options)
57460 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
57461 // if you click on the translation.. you can edit it...
57462 var el = Roo.get(this);
57463 var id = el.dom.getAttribute('data-id');
57464 var d = el.dom.getAttribute('data-date');
57465 var t = el.dom.getAttribute('data-time');
57466 //var id = this.child('span').dom.textContent;
57469 Pman.Dialog.CourseCalendar.show({
57473 productitem_active : id ? 1 : 0
57475 _this.grid.ds.load({});
57480 _this.panel.fireEvent('resize', [ '', '' ]);
57483 loadResponse : function(o, success, response){
57484 // this is overridden on before load..
57486 Roo.log("our code?");
57487 //Roo.log(success);
57488 //Roo.log(response)
57489 delete this.activeRequest;
57491 this.fireEvent("loadexception", this, o, response);
57492 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57497 result = o.reader.read(response);
57499 Roo.log("load exception?");
57500 this.fireEvent("loadexception", this, o, response, e);
57501 o.request.callback.call(o.request.scope, null, o.request.arg, false);
57504 Roo.log("ready...");
57505 // loop through result.records;
57506 // and set this.tdate[date] = [] << array of records..
57508 Roo.each(result.records, function(r){
57510 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
57511 _this.tdata[r.data.when_dt.format('j')] = [];
57513 _this.tdata[r.data.when_dt.format('j')].push(r.data);
57516 //Roo.log(_this.tdata);
57518 result.records = [];
57519 result.totalRecords = 6;
57521 // let's generate some duumy records for the rows.
57522 //var st = _this.dateField.getValue();
57524 // work out monday..
57525 //st = st.add(Date.DAY, -1 * st.format('w'));
57527 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57529 var firstOfMonth = date.getFirstDayOfMonth();
57530 var days = date.getDaysInMonth();
57532 var firstAdded = false;
57533 for (var i = 0; i < result.totalRecords ; i++) {
57534 //var d= st.add(Date.DAY, i);
57537 for(var w = 0 ; w < 7 ; w++){
57538 if(!firstAdded && firstOfMonth != w){
57545 var dd = (d > 0 && d < 10) ? "0"+d : d;
57546 row['weekday'+w] = String.format(
57547 '<span style="font-size: 16px;"><b>{0}</b></span>'+
57548 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
57550 date.format('Y-m-')+dd
57553 if(typeof(_this.tdata[d]) != 'undefined'){
57554 Roo.each(_this.tdata[d], function(r){
57558 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
57559 if(r.parent_id*1>0){
57560 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
57563 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
57564 deactive = 'de-act-link';
57567 row['weekday'+w] += String.format(
57568 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
57570 r.product_id_name, //1
57571 r.when_dt.format('h:ia'), //2
57581 // only do this if something added..
57583 result.records.push(_this.grid.dataSource.reader.newRow(row));
57587 // push it twice. (second one with an hour..
57591 this.fireEvent("load", this, o, o.request.arg);
57592 o.request.callback.call(o.request.scope, result, o.request.arg, true);
57594 sortInfo : {field: 'when_dt', direction : 'ASC' },
57596 xtype: 'HttpProxy',
57599 url : baseURL + '/Roo/Shop_course.php'
57602 xtype: 'JsonReader',
57619 'name': 'parent_id',
57623 'name': 'product_id',
57627 'name': 'productitem_id',
57645 click : function (_self, e)
57647 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57648 sd.setMonth(sd.getMonth()-1);
57649 _this.monthField.setValue(sd.format('Y-m-d'));
57650 _this.grid.ds.load({});
57656 xtype: 'Separator',
57660 xtype: 'MonthField',
57663 render : function (_self)
57665 _this.monthField = _self;
57666 // _this.monthField.set today
57668 select : function (combo, date)
57670 _this.grid.ds.load({});
57673 value : (function() { return new Date(); })()
57676 xtype: 'Separator',
57682 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
57692 click : function (_self, e)
57694 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
57695 sd.setMonth(sd.getMonth()+1);
57696 _this.monthField.setValue(sd.format('Y-m-d'));
57697 _this.grid.ds.load({});
57710 * Ext JS Library 1.1.1
57711 * Copyright(c) 2006-2007, Ext JS, LLC.
57713 * Originally Released Under LGPL - original licence link has changed is not relivant.
57716 * <script type="text/javascript">
57720 * @class Roo.LoadMask
57721 * A simple utility class for generically masking elements while loading data. If the element being masked has
57722 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
57723 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
57724 * element's UpdateManager load indicator and will be destroyed after the initial load.
57726 * Create a new LoadMask
57727 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
57728 * @param {Object} config The config object
57730 Roo.LoadMask = function(el, config){
57731 this.el = Roo.get(el);
57732 Roo.apply(this, config);
57734 this.store.on('beforeload', this.onBeforeLoad, this);
57735 this.store.on('load', this.onLoad, this);
57736 this.store.on('loadexception', this.onLoadException, this);
57737 this.removeMask = false;
57739 var um = this.el.getUpdateManager();
57740 um.showLoadIndicator = false; // disable the default indicator
57741 um.on('beforeupdate', this.onBeforeLoad, this);
57742 um.on('update', this.onLoad, this);
57743 um.on('failure', this.onLoad, this);
57744 this.removeMask = true;
57748 Roo.LoadMask.prototype = {
57750 * @cfg {Boolean} removeMask
57751 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
57752 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
57755 * @cfg {String} msg
57756 * The text to display in a centered loading message box (defaults to 'Loading...')
57758 msg : 'Loading...',
57760 * @cfg {String} msgCls
57761 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
57763 msgCls : 'x-mask-loading',
57766 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
57772 * Disables the mask to prevent it from being displayed
57774 disable : function(){
57775 this.disabled = true;
57779 * Enables the mask so that it can be displayed
57781 enable : function(){
57782 this.disabled = false;
57785 onLoadException : function()
57787 Roo.log(arguments);
57789 if (typeof(arguments[3]) != 'undefined') {
57790 Roo.MessageBox.alert("Error loading",arguments[3]);
57794 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
57795 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
57804 this.el.unmask(this.removeMask);
57807 onLoad : function()
57809 this.el.unmask(this.removeMask);
57813 onBeforeLoad : function(){
57814 if(!this.disabled){
57815 this.el.mask(this.msg, this.msgCls);
57820 destroy : function(){
57822 this.store.un('beforeload', this.onBeforeLoad, this);
57823 this.store.un('load', this.onLoad, this);
57824 this.store.un('loadexception', this.onLoadException, this);
57826 var um = this.el.getUpdateManager();
57827 um.un('beforeupdate', this.onBeforeLoad, this);
57828 um.un('update', this.onLoad, this);
57829 um.un('failure', this.onLoad, this);
57834 * Ext JS Library 1.1.1
57835 * Copyright(c) 2006-2007, Ext JS, LLC.
57837 * Originally Released Under LGPL - original licence link has changed is not relivant.
57840 * <script type="text/javascript">
57845 * @class Roo.XTemplate
57846 * @extends Roo.Template
57847 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
57849 var t = new Roo.XTemplate(
57850 '<select name="{name}">',
57851 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
57855 // then append, applying the master template values
57858 * Supported features:
57863 {a_variable} - output encoded.
57864 {a_variable.format:("Y-m-d")} - call a method on the variable
57865 {a_variable:raw} - unencoded output
57866 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
57867 {a_variable:this.method_on_template(...)} - call a method on the template object.
57872 <tpl for="a_variable or condition.."></tpl>
57873 <tpl if="a_variable or condition"></tpl>
57874 <tpl exec="some javascript"></tpl>
57875 <tpl name="named_template"></tpl> (experimental)
57877 <tpl for="."></tpl> - just iterate the property..
57878 <tpl for=".."></tpl> - iterates with the parent (probably the template)
57882 Roo.XTemplate = function()
57884 Roo.XTemplate.superclass.constructor.apply(this, arguments);
57891 Roo.extend(Roo.XTemplate, Roo.Template, {
57894 * The various sub templates
57899 * basic tag replacing syntax
57902 * // you can fake an object call by doing this
57906 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
57909 * compile the template
57911 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
57914 compile: function()
57918 s = ['<tpl>', s, '</tpl>'].join('');
57920 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
57921 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
57922 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
57923 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
57924 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
57929 while(true == !!(m = s.match(re))){
57930 var forMatch = m[0].match(nameRe),
57931 ifMatch = m[0].match(ifRe),
57932 execMatch = m[0].match(execRe),
57933 namedMatch = m[0].match(namedRe),
57938 name = forMatch && forMatch[1] ? forMatch[1] : '';
57941 // if - puts fn into test..
57942 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
57944 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
57949 // exec - calls a function... returns empty if true is returned.
57950 exp = execMatch && execMatch[1] ? execMatch[1] : null;
57952 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
57960 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
57961 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
57962 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
57965 var uid = namedMatch ? namedMatch[1] : id;
57969 id: namedMatch ? namedMatch[1] : id,
57976 s = s.replace(m[0], '');
57978 s = s.replace(m[0], '{xtpl'+ id + '}');
57983 for(var i = tpls.length-1; i >= 0; --i){
57984 this.compileTpl(tpls[i]);
57985 this.tpls[tpls[i].id] = tpls[i];
57987 this.master = tpls[tpls.length-1];
57991 * same as applyTemplate, except it's done to one of the subTemplates
57992 * when using named templates, you can do:
57994 * var str = pl.applySubTemplate('your-name', values);
57997 * @param {Number} id of the template
57998 * @param {Object} values to apply to template
57999 * @param {Object} parent (normaly the instance of this object)
58001 applySubTemplate : function(id, values, parent)
58005 var t = this.tpls[id];
58009 if(t.test && !t.test.call(this, values, parent)){
58013 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58014 Roo.log(e.toString());
58020 if(t.exec && t.exec.call(this, values, parent)){
58024 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58025 Roo.log(e.toString());
58030 var vs = t.target ? t.target.call(this, values, parent) : values;
58031 parent = t.target ? values : parent;
58032 if(t.target && vs instanceof Array){
58034 for(var i = 0, len = vs.length; i < len; i++){
58035 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58037 return buf.join('');
58039 return t.compiled.call(this, vs, parent);
58041 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58042 Roo.log(e.toString());
58043 Roo.log(t.compiled);
58048 compileTpl : function(tpl)
58050 var fm = Roo.util.Format;
58051 var useF = this.disableFormats !== true;
58052 var sep = Roo.isGecko ? "+" : ",";
58053 var undef = function(str) {
58054 Roo.log("Property not found :" + str);
58058 var fn = function(m, name, format, args)
58060 //Roo.log(arguments);
58061 args = args ? args.replace(/\\'/g,"'") : args;
58062 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58063 if (typeof(format) == 'undefined') {
58064 format= 'htmlEncode';
58066 if (format == 'raw' ) {
58070 if(name.substr(0, 4) == 'xtpl'){
58071 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58074 // build an array of options to determine if value is undefined..
58076 // basically get 'xxxx.yyyy' then do
58077 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58078 // (function () { Roo.log("Property not found"); return ''; })() :
58083 Roo.each(name.split('.'), function(st) {
58084 lookfor += (lookfor.length ? '.': '') + st;
58085 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58088 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58091 if(format && useF){
58093 args = args ? ',' + args : "";
58095 if(format.substr(0, 5) != "this."){
58096 format = "fm." + format + '(';
58098 format = 'this.call("'+ format.substr(5) + '", ';
58102 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58106 // called with xxyx.yuu:(test,test)
58108 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58110 // raw.. - :raw modifier..
58111 return "'"+ sep + udef_st + name + ")"+sep+"'";
58115 // branched to use + in gecko and [].join() in others
58117 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58118 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58121 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58122 body.push(tpl.body.replace(/(\r\n|\n)/g,
58123 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58124 body.push("'].join('');};};");
58125 body = body.join('');
58128 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58130 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58136 applyTemplate : function(values){
58137 return this.master.compiled.call(this, values, {});
58138 //var s = this.subs;
58141 apply : function(){
58142 return this.applyTemplate.apply(this, arguments);
58147 Roo.XTemplate.from = function(el){
58148 el = Roo.getDom(el);
58149 return new Roo.XTemplate(el.value || el.innerHTML);