4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /Trident.*rv\:11\./.test(ua),
60 isGecko = !isSafari && ua.indexOf("gecko") > -1,
61 isBorderBox = isIE && !isStrict,
62 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64 isLinux = (ua.indexOf("linux") != -1),
65 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66 isTouch = (function() {
68 document.createEvent("TouchEvent");
75 // remove css image flicker
78 document.execCommand("BackgroundImageCache", false, true);
84 * True if the browser is in strict mode
89 * True if the page is running over SSL
94 * True when the document is fully initialized and ready for action
99 * Turn on debugging output (currently only the factory uses this)
106 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
109 enableGarbageCollector : true,
112 * True to automatically purge event listeners after uncaching an element (defaults to false).
113 * Note: this only happens if enableGarbageCollector is true.
116 enableListenerCollection:false,
119 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
120 * the IE insecure content warning (defaults to javascript:false).
123 SSL_SECURE_URL : "javascript:false",
126 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
127 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
130 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
132 emptyFn : function(){},
135 * Copies all the properties of config to obj if they don't already exist.
136 * @param {Object} obj The receiver of the properties
137 * @param {Object} config The source of the properties
138 * @return {Object} returns obj
140 applyIf : function(o, c){
143 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
150 * Applies event listeners to elements by selectors when the document is ready.
151 * The event name is specified with an @ suffix.
154 // add a listener for click on all anchors in element with id foo
155 '#foo a@click' : function(e, t){
159 // add the same listener to multiple selectors (separated by comma BEFORE the @)
160 '#foo a, #bar span.some-class@mouseover' : function(){
165 * @param {Object} obj The list of behaviors to apply
167 addBehaviors : function(o){
169 Roo.onReady(function(){
174 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
176 var parts = b.split('@');
177 if(parts[1]){ // for Object prototype breakers
180 cache[s] = Roo.select(s);
182 cache[s].on(parts[1], o[b]);
189 * Generates unique ids. If the element already has an id, it is unchanged
190 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
191 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
192 * @return {String} The generated Id.
194 id : function(el, prefix){
195 prefix = prefix || "roo-gen";
197 var id = prefix + (++idSeed);
198 return el ? (el.id ? el.id : (el.id = id)) : id;
203 * Extends one class with another class and optionally overrides members with the passed literal. This class
204 * also adds the function "override()" to the class that can be used to override
205 * members on an instance.
206 * @param {Object} subclass The class inheriting the functionality
207 * @param {Object} superclass The class being extended
208 * @param {Object} overrides (optional) A literal with members
213 var io = function(o){
218 return function(sb, sp, overrides){
219 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
222 sb = function(){sp.apply(this, arguments);};
224 var F = function(){}, sbp, spp = sp.prototype;
226 sbp = sb.prototype = new F();
230 if(spp.constructor == Object.prototype.constructor){
235 sb.override = function(o){
239 Roo.override(sb, overrides);
245 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
247 Roo.override(MyClass, {
248 newMethod1: function(){
251 newMethod2: function(foo){
256 * @param {Object} origclass The class to override
257 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
258 * containing one or more methods.
261 override : function(origclass, overrides){
263 var p = origclass.prototype;
264 for(var method in overrides){
265 p[method] = overrides[method];
270 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
272 Roo.namespace('Company', 'Company.data');
273 Company.Widget = function() { ... }
274 Company.data.CustomStore = function(config) { ... }
276 * @param {String} namespace1
277 * @param {String} namespace2
278 * @param {String} etc
281 namespace : function(){
282 var a=arguments, o=null, i, j, d, rt;
283 for (i=0; i<a.length; ++i) {
287 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
288 for (j=1; j<d.length; ++j) {
289 o[d[j]]=o[d[j]] || {};
295 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
297 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
298 Roo.factory(conf, Roo.data);
300 * @param {String} classname
301 * @param {String} namespace (optional)
305 factory : function(c, ns)
307 // no xtype, no ns or c.xns - or forced off by c.xns
308 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
311 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
312 if (c.constructor == ns[c.xtype]) {// already created...
316 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
317 var ret = new ns[c.xtype](c);
321 c.xns = false; // prevent recursion..
325 * Logs to console if it can.
327 * @param {String|Object} string
332 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
339 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
343 urlEncode : function(o){
349 var ov = o[key], k = Roo.encodeURIComponent(key);
350 var type = typeof ov;
351 if(type == 'undefined'){
353 }else if(type != "function" && type != "object"){
354 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
355 }else if(ov instanceof Array){
357 for(var i = 0, len = ov.length; i < len; i++) {
358 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
369 * Safe version of encodeURIComponent
370 * @param {String} data
374 encodeURIComponent : function (data)
377 return encodeURIComponent(data);
378 } catch(e) {} // should be an uri encode error.
380 if (data == '' || data == null){
383 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
384 function nibble_to_hex(nibble){
385 var chars = '0123456789ABCDEF';
386 return chars.charAt(nibble);
388 data = data.toString();
390 for(var i=0; i<data.length; i++){
391 var c = data.charCodeAt(i);
392 var bs = new Array();
395 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
396 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
397 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
398 bs[3] = 0x80 | (c & 0x3F);
399 }else if (c > 0x800){
401 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
402 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
403 bs[2] = 0x80 | (c & 0x3F);
406 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
407 bs[1] = 0x80 | (c & 0x3F);
412 for(var j=0; j<bs.length; j++){
414 var hex = nibble_to_hex((b & 0xF0) >>> 4)
415 + nibble_to_hex(b &0x0F);
424 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
425 * @param {String} string
426 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
427 * @return {Object} A literal with members
429 urlDecode : function(string, overwrite){
430 if(!string || !string.length){
434 var pairs = string.split('&');
435 var pair, name, value;
436 for(var i = 0, len = pairs.length; i < len; i++){
437 pair = pairs[i].split('=');
438 name = decodeURIComponent(pair[0]);
439 value = decodeURIComponent(pair[1]);
440 if(overwrite !== true){
441 if(typeof obj[name] == "undefined"){
443 }else if(typeof obj[name] == "string"){
444 obj[name] = [obj[name]];
445 obj[name].push(value);
447 obj[name].push(value);
457 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
458 * passed array is not really an array, your function is called once with it.
459 * The supplied function is called with (Object item, Number index, Array allItems).
460 * @param {Array/NodeList/Mixed} array
461 * @param {Function} fn
462 * @param {Object} scope
464 each : function(array, fn, scope){
465 if(typeof array.length == "undefined" || typeof array == "string"){
468 for(var i = 0, len = array.length; i < len; i++){
469 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
474 combine : function(){
475 var as = arguments, l = as.length, r = [];
476 for(var i = 0; i < l; i++){
478 if(a instanceof Array){
480 }else if(a.length !== undefined && !a.substr){
481 r = r.concat(Array.prototype.slice.call(a, 0));
490 * Escapes the passed string for use in a regular expression
491 * @param {String} str
494 escapeRe : function(s) {
495 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
499 callback : function(cb, scope, args, delay){
500 if(typeof cb == "function"){
502 cb.defer(delay, scope, args || []);
504 cb.apply(scope, args || []);
510 * Return the dom node for the passed string (id), dom node, or Roo.Element
511 * @param {String/HTMLElement/Roo.Element} el
512 * @return HTMLElement
514 getDom : function(el){
518 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
522 * Shorthand for {@link Roo.ComponentMgr#get}
524 * @return Roo.Component
526 getCmp : function(id){
527 return Roo.ComponentMgr.get(id);
530 num : function(v, defaultValue){
531 if(typeof v != 'number'){
537 destroy : function(){
538 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
542 as.removeAllListeners();
546 if(typeof as.purgeListeners == 'function'){
549 if(typeof as.destroy == 'function'){
556 // inpired by a similar function in mootools library
558 * Returns the type of object that is passed in. If the object passed in is null or undefined it
559 * return false otherwise it returns one of the following values:<ul>
560 * <li><b>string</b>: If the object passed is a string</li>
561 * <li><b>number</b>: If the object passed is a number</li>
562 * <li><b>boolean</b>: If the object passed is a boolean value</li>
563 * <li><b>function</b>: If the object passed is a function reference</li>
564 * <li><b>object</b>: If the object passed is an object</li>
565 * <li><b>array</b>: If the object passed is an array</li>
566 * <li><b>regexp</b>: If the object passed is a regular expression</li>
567 * <li><b>element</b>: If the object passed is a DOM Element</li>
568 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
569 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
570 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
571 * @param {Mixed} object
575 if(o === undefined || o === null){
582 if(t == 'object' && o.nodeName) {
584 case 1: return 'element';
585 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
588 if(t == 'object' || t == 'function') {
589 switch(o.constructor) {
590 case Array: return 'array';
591 case RegExp: return 'regexp';
593 if(typeof o.length == 'number' && typeof o.item == 'function') {
601 * Returns true if the passed value is null, undefined or an empty string (optional).
602 * @param {Mixed} value The value to test
603 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
606 isEmpty : function(v, allowBlank){
607 return v === null || v === undefined || (!allowBlank ? v === '' : false);
615 isFirefox : isFirefox,
625 isBorderBox : isBorderBox,
627 isWindows : isWindows,
636 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
637 * you may want to set this to true.
640 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
645 * Selects a single element as a Roo Element
646 * This is about as close as you can get to jQuery's $('do crazy stuff')
647 * @param {String} selector The selector/xpath query
648 * @param {Node} root (optional) The start of the query (defaults to document).
649 * @return {Roo.Element}
651 selectNode : function(selector, root)
653 var node = Roo.DomQuery.selectNode(selector,root);
654 return node ? Roo.get(node) : new Roo.Element(false);
662 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
663 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
666 "Roo.bootstrap.dash");
669 * Ext JS Library 1.1.1
670 * Copyright(c) 2006-2007, Ext JS, LLC.
672 * Originally Released Under LGPL - original licence link has changed is not relivant.
675 * <script type="text/javascript">
679 // wrappedn so fnCleanup is not in global scope...
681 function fnCleanUp() {
682 var p = Function.prototype;
683 delete p.createSequence;
685 delete p.createDelegate;
686 delete p.createCallback;
687 delete p.createInterceptor;
689 window.detachEvent("onunload", fnCleanUp);
691 window.attachEvent("onunload", fnCleanUp);
698 * These functions are available on every Function object (any JavaScript function).
700 Roo.apply(Function.prototype, {
702 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
703 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
704 * Will create a function that is bound to those 2 args.
705 * @return {Function} The new function
707 createCallback : function(/*args...*/){
708 // make args available, in function below
709 var args = arguments;
712 return method.apply(window, args);
717 * Creates a delegate (callback) that sets the scope to obj.
718 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
719 * Will create a function that is automatically scoped to this.
720 * @param {Object} obj (optional) The object for which the scope is set
721 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
722 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
723 * if a number the args are inserted at the specified position
724 * @return {Function} The new function
726 createDelegate : function(obj, args, appendArgs){
729 var callArgs = args || arguments;
730 if(appendArgs === true){
731 callArgs = Array.prototype.slice.call(arguments, 0);
732 callArgs = callArgs.concat(args);
733 }else if(typeof appendArgs == "number"){
734 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
735 var applyArgs = [appendArgs, 0].concat(args); // create method call params
736 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
738 return method.apply(obj || window, callArgs);
743 * Calls this function after the number of millseconds specified.
744 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
745 * @param {Object} obj (optional) The object for which the scope is set
746 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
747 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
748 * if a number the args are inserted at the specified position
749 * @return {Number} The timeout id that can be used with clearTimeout
751 defer : function(millis, obj, args, appendArgs){
752 var fn = this.createDelegate(obj, args, appendArgs);
754 return setTimeout(fn, millis);
760 * Create a combined function call sequence of the original function + the passed function.
761 * The resulting function returns the results of the original function.
762 * The passed fcn is called with the parameters of the original function
763 * @param {Function} fcn The function to sequence
764 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
765 * @return {Function} The new function
767 createSequence : function(fcn, scope){
768 if(typeof fcn != "function"){
773 var retval = method.apply(this || window, arguments);
774 fcn.apply(scope || this || window, arguments);
780 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
781 * The resulting function returns the results of the original function.
782 * The passed fcn is called with the parameters of the original function.
784 * @param {Function} fcn The function to call before the original
785 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
786 * @return {Function} The new function
788 createInterceptor : function(fcn, scope){
789 if(typeof fcn != "function"){
796 if(fcn.apply(scope || this || window, arguments) === false){
799 return method.apply(this || window, arguments);
805 * Ext JS Library 1.1.1
806 * Copyright(c) 2006-2007, Ext JS, LLC.
808 * Originally Released Under LGPL - original licence link has changed is not relivant.
811 * <script type="text/javascript">
814 Roo.applyIf(String, {
819 * Escapes the passed string for ' and \
820 * @param {String} string The string to escape
821 * @return {String} The escaped string
824 escape : function(string) {
825 return string.replace(/('|\\)/g, "\\$1");
829 * Pads the left side of a string with a specified character. This is especially useful
830 * for normalizing number and date strings. Example usage:
832 var s = String.leftPad('123', 5, '0');
833 // s now contains the string: '00123'
835 * @param {String} string The original string
836 * @param {Number} size The total length of the output string
837 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
838 * @return {String} The padded string
841 leftPad : function (val, size, ch) {
842 var result = new String(val);
843 if(ch === null || ch === undefined || ch === '') {
846 while (result.length < size) {
847 result = ch + result;
853 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
854 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
856 var cls = 'my-class', text = 'Some text';
857 var s = String.format('<div class="{0}">{1}</div>', cls, text);
858 // s now contains the string: '<div class="my-class">Some text</div>'
860 * @param {String} string The tokenized string to be formatted
861 * @param {String} value1 The value to replace token {0}
862 * @param {String} value2 Etc...
863 * @return {String} The formatted string
866 format : function(format){
867 var args = Array.prototype.slice.call(arguments, 1);
868 return format.replace(/\{(\d+)\}/g, function(m, i){
869 return Roo.util.Format.htmlEncode(args[i]);
875 * Utility function that allows you to easily switch a string between two alternating values. The passed value
876 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
877 * they are already different, the first value passed in is returned. Note that this method returns the new value
878 * but does not change the current string.
880 // alternate sort directions
881 sort = sort.toggle('ASC', 'DESC');
883 // instead of conditional logic:
884 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
886 * @param {String} value The value to compare to the current string
887 * @param {String} other The new value to use if the string already equals the first value passed in
888 * @return {String} The new value
891 String.prototype.toggle = function(value, other){
892 return this == value ? other : value;
895 * Ext JS Library 1.1.1
896 * Copyright(c) 2006-2007, Ext JS, LLC.
898 * Originally Released Under LGPL - original licence link has changed is not relivant.
901 * <script type="text/javascript">
907 Roo.applyIf(Number.prototype, {
909 * Checks whether or not the current number is within a desired range. If the number is already within the
910 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
911 * exceeded. Note that this method returns the constrained value but does not change the current number.
912 * @param {Number} min The minimum number in the range
913 * @param {Number} max The maximum number in the range
914 * @return {Number} The constrained value if outside the range, otherwise the current value
916 constrain : function(min, max){
917 return Math.min(Math.max(this, min), max);
921 * Ext JS Library 1.1.1
922 * Copyright(c) 2006-2007, Ext JS, LLC.
924 * Originally Released Under LGPL - original licence link has changed is not relivant.
927 * <script type="text/javascript">
932 Roo.applyIf(Array.prototype, {
935 * Checks whether or not the specified object exists in the array.
936 * @param {Object} o The object to check for
937 * @return {Number} The index of o in the array (or -1 if it is not found)
939 indexOf : function(o){
940 for (var i = 0, len = this.length; i < len; i++){
941 if(this[i] == o) return i;
947 * Removes the specified object from the array. If the object is not found nothing happens.
948 * @param {Object} o The object to remove
950 remove : function(o){
951 var index = this.indexOf(o);
953 this.splice(index, 1);
957 * Map (JS 1.6 compatibility)
958 * @param {Function} function to call
962 var len = this.length >>> 0;
963 if (typeof fun != "function")
964 throw new TypeError();
966 var res = new Array(len);
967 var thisp = arguments[1];
968 for (var i = 0; i < len; i++)
971 res[i] = fun.call(thisp, this[i], i, this);
982 * Ext JS Library 1.1.1
983 * Copyright(c) 2006-2007, Ext JS, LLC.
985 * Originally Released Under LGPL - original licence link has changed is not relivant.
988 * <script type="text/javascript">
994 * The date parsing and format syntax is a subset of
995 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
996 * supported will provide results equivalent to their PHP versions.
998 * Following is the list of all currently supported formats:
1001 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1003 Format Output Description
1004 ------ ---------- --------------------------------------------------------------
1005 d 10 Day of the month, 2 digits with leading zeros
1006 D Wed A textual representation of a day, three letters
1007 j 10 Day of the month without leading zeros
1008 l Wednesday A full textual representation of the day of the week
1009 S th English ordinal day of month suffix, 2 chars (use with j)
1010 w 3 Numeric representation of the day of the week
1011 z 9 The julian date, or day of the year (0-365)
1012 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1013 F January A full textual representation of the month
1014 m 01 Numeric representation of a month, with leading zeros
1015 M Jan Month name abbreviation, three letters
1016 n 1 Numeric representation of a month, without leading zeros
1017 t 31 Number of days in the given month
1018 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1019 Y 2007 A full numeric representation of a year, 4 digits
1020 y 07 A two digit representation of a year
1021 a pm Lowercase Ante meridiem and Post meridiem
1022 A PM Uppercase Ante meridiem and Post meridiem
1023 g 3 12-hour format of an hour without leading zeros
1024 G 15 24-hour format of an hour without leading zeros
1025 h 03 12-hour format of an hour with leading zeros
1026 H 15 24-hour format of an hour with leading zeros
1027 i 05 Minutes with leading zeros
1028 s 01 Seconds, with leading zeros
1029 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1030 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1031 T CST Timezone setting of the machine running the code
1032 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1035 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1037 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1038 document.write(dt.format('Y-m-d')); //2007-01-10
1039 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1040 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1043 * Here are some standard date/time patterns that you might find helpful. They
1044 * are not part of the source of Date.js, but to use them you can simply copy this
1045 * block of code into any script that is included after Date.js and they will also become
1046 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1049 ISO8601Long:"Y-m-d H:i:s",
1050 ISO8601Short:"Y-m-d",
1052 LongDate: "l, F d, Y",
1053 FullDateTime: "l, F d, Y g:i:s A",
1056 LongTime: "g:i:s A",
1057 SortableDateTime: "Y-m-d\\TH:i:s",
1058 UniversalSortableDateTime: "Y-m-d H:i:sO",
1065 var dt = new Date();
1066 document.write(dt.format(Date.patterns.ShortDate));
1071 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1072 * They generate precompiled functions from date formats instead of parsing and
1073 * processing the pattern every time you format a date. These functions are available
1074 * on every Date object (any javascript function).
1076 * The original article and download are here:
1077 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1084 Returns the number of milliseconds between this date and date
1085 @param {Date} date (optional) Defaults to now
1086 @return {Number} The diff in milliseconds
1087 @member Date getElapsed
1089 Date.prototype.getElapsed = function(date) {
1090 return Math.abs((date || new Date()).getTime()-this.getTime());
1092 // was in date file..
1096 Date.parseFunctions = {count:0};
1098 Date.parseRegexes = [];
1100 Date.formatFunctions = {count:0};
1103 Date.prototype.dateFormat = function(format) {
1104 if (Date.formatFunctions[format] == null) {
1105 Date.createNewFormat(format);
1107 var func = Date.formatFunctions[format];
1108 return this[func]();
1113 * Formats a date given the supplied format string
1114 * @param {String} format The format string
1115 * @return {String} The formatted date
1118 Date.prototype.format = Date.prototype.dateFormat;
1121 Date.createNewFormat = function(format) {
1122 var funcName = "format" + Date.formatFunctions.count++;
1123 Date.formatFunctions[format] = funcName;
1124 var code = "Date.prototype." + funcName + " = function(){return ";
1125 var special = false;
1127 for (var i = 0; i < format.length; ++i) {
1128 ch = format.charAt(i);
1129 if (!special && ch == "\\") {
1134 code += "'" + String.escape(ch) + "' + ";
1137 code += Date.getFormatCode(ch);
1140 /** eval:var:zzzzzzzzzzzzz */
1141 eval(code.substring(0, code.length - 3) + ";}");
1145 Date.getFormatCode = function(character) {
1146 switch (character) {
1148 return "String.leftPad(this.getDate(), 2, '0') + ";
1150 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1152 return "this.getDate() + ";
1154 return "Date.dayNames[this.getDay()] + ";
1156 return "this.getSuffix() + ";
1158 return "this.getDay() + ";
1160 return "this.getDayOfYear() + ";
1162 return "this.getWeekOfYear() + ";
1164 return "Date.monthNames[this.getMonth()] + ";
1166 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1168 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1170 return "(this.getMonth() + 1) + ";
1172 return "this.getDaysInMonth() + ";
1174 return "(this.isLeapYear() ? 1 : 0) + ";
1176 return "this.getFullYear() + ";
1178 return "('' + this.getFullYear()).substring(2, 4) + ";
1180 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1182 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1184 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1186 return "this.getHours() + ";
1188 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1190 return "String.leftPad(this.getHours(), 2, '0') + ";
1192 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1194 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1196 return "this.getGMTOffset() + ";
1198 return "this.getGMTColonOffset() + ";
1200 return "this.getTimezone() + ";
1202 return "(this.getTimezoneOffset() * -60) + ";
1204 return "'" + String.escape(character) + "' + ";
1209 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1210 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1211 * the date format that is not specified will default to the current date value for that part. Time parts can also
1212 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1213 * string or the parse operation will fail.
1216 //dt = Fri May 25 2007 (current date)
1217 var dt = new Date();
1219 //dt = Thu May 25 2006 (today's month/day in 2006)
1220 dt = Date.parseDate("2006", "Y");
1222 //dt = Sun Jan 15 2006 (all date parts specified)
1223 dt = Date.parseDate("2006-1-15", "Y-m-d");
1225 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1226 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1228 * @param {String} input The unparsed date as a string
1229 * @param {String} format The format the date is in
1230 * @return {Date} The parsed date
1233 Date.parseDate = function(input, format) {
1234 if (Date.parseFunctions[format] == null) {
1235 Date.createParser(format);
1237 var func = Date.parseFunctions[format];
1238 return Date[func](input);
1244 Date.createParser = function(format) {
1245 var funcName = "parse" + Date.parseFunctions.count++;
1246 var regexNum = Date.parseRegexes.length;
1247 var currentGroup = 1;
1248 Date.parseFunctions[format] = funcName;
1250 var code = "Date." + funcName + " = function(input){\n"
1251 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1252 + "var d = new Date();\n"
1253 + "y = d.getFullYear();\n"
1254 + "m = d.getMonth();\n"
1255 + "d = d.getDate();\n"
1256 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1257 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1258 + "if (results && results.length > 0) {";
1261 var special = false;
1263 for (var i = 0; i < format.length; ++i) {
1264 ch = format.charAt(i);
1265 if (!special && ch == "\\") {
1270 regex += String.escape(ch);
1273 var obj = Date.formatCodeToRegex(ch, currentGroup);
1274 currentGroup += obj.g;
1276 if (obj.g && obj.c) {
1282 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1283 + "{v = new Date(y, m, d, h, i, s);}\n"
1284 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1285 + "{v = new Date(y, m, d, h, i);}\n"
1286 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1287 + "{v = new Date(y, m, d, h);}\n"
1288 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1289 + "{v = new Date(y, m, d);}\n"
1290 + "else if (y >= 0 && m >= 0)\n"
1291 + "{v = new Date(y, m);}\n"
1292 + "else if (y >= 0)\n"
1293 + "{v = new Date(y);}\n"
1294 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1295 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1296 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1299 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1300 /** eval:var:zzzzzzzzzzzzz */
1305 Date.formatCodeToRegex = function(character, currentGroup) {
1306 switch (character) {
1310 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1313 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1314 s:"(\\d{1,2})"}; // day of month without leading zeroes
1317 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1318 s:"(\\d{2})"}; // day of month with leading zeroes
1322 s:"(?:" + Date.dayNames.join("|") + ")"};
1326 s:"(?:st|nd|rd|th)"};
1341 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1342 s:"(" + Date.monthNames.join("|") + ")"};
1345 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1346 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1349 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1350 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1353 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1354 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1365 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1369 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1370 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1374 c:"if (results[" + currentGroup + "] == 'am') {\n"
1375 + "if (h == 12) { h = 0; }\n"
1376 + "} else { if (h < 12) { h += 12; }}",
1380 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1381 + "if (h == 12) { h = 0; }\n"
1382 + "} else { if (h < 12) { h += 12; }}",
1387 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1388 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1392 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1393 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1396 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1400 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1405 "o = results[", currentGroup, "];\n",
1406 "var sn = o.substring(0,1);\n", // get + / - sign
1407 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1408 "var mn = o.substring(3,5) % 60;\n", // get minutes
1409 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1410 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1412 s:"([+\-]\\d{2,4})"};
1418 "o = results[", currentGroup, "];\n",
1419 "var sn = o.substring(0,1);\n",
1420 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1421 "var mn = o.substring(4,6) % 60;\n",
1422 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1423 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1429 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1432 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1433 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1434 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1438 s:String.escape(character)};
1443 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1444 * @return {String} The abbreviated timezone name (e.g. 'CST')
1446 Date.prototype.getTimezone = function() {
1447 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1451 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1452 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1454 Date.prototype.getGMTOffset = function() {
1455 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1456 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1457 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1461 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1462 * @return {String} 2-characters representing hours and 2-characters representing minutes
1463 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1465 Date.prototype.getGMTColonOffset = function() {
1466 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1467 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1469 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1473 * Get the numeric day number of the year, adjusted for leap year.
1474 * @return {Number} 0 through 364 (365 in leap years)
1476 Date.prototype.getDayOfYear = function() {
1478 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1479 for (var i = 0; i < this.getMonth(); ++i) {
1480 num += Date.daysInMonth[i];
1482 return num + this.getDate() - 1;
1486 * Get the string representation of the numeric week number of the year
1487 * (equivalent to the format specifier 'W').
1488 * @return {String} '00' through '52'
1490 Date.prototype.getWeekOfYear = function() {
1491 // Skip to Thursday of this week
1492 var now = this.getDayOfYear() + (4 - this.getDay());
1493 // Find the first Thursday of the year
1494 var jan1 = new Date(this.getFullYear(), 0, 1);
1495 var then = (7 - jan1.getDay() + 4);
1496 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1500 * Whether or not the current date is in a leap year.
1501 * @return {Boolean} True if the current date is in a leap year, else false
1503 Date.prototype.isLeapYear = function() {
1504 var year = this.getFullYear();
1505 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1509 * Get the first day of the current month, adjusted for leap year. The returned value
1510 * is the numeric day index within the week (0-6) which can be used in conjunction with
1511 * the {@link #monthNames} array to retrieve the textual day name.
1514 var dt = new Date('1/10/2007');
1515 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1517 * @return {Number} The day number (0-6)
1519 Date.prototype.getFirstDayOfMonth = function() {
1520 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1521 return (day < 0) ? (day + 7) : day;
1525 * Get the last day of the current month, adjusted for leap year. The returned value
1526 * is the numeric day index within the week (0-6) which can be used in conjunction with
1527 * the {@link #monthNames} array to retrieve the textual day name.
1530 var dt = new Date('1/10/2007');
1531 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1533 * @return {Number} The day number (0-6)
1535 Date.prototype.getLastDayOfMonth = function() {
1536 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1537 return (day < 0) ? (day + 7) : day;
1542 * Get the first date of this date's month
1545 Date.prototype.getFirstDateOfMonth = function() {
1546 return new Date(this.getFullYear(), this.getMonth(), 1);
1550 * Get the last date of this date's month
1553 Date.prototype.getLastDateOfMonth = function() {
1554 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1557 * Get the number of days in the current month, adjusted for leap year.
1558 * @return {Number} The number of days in the month
1560 Date.prototype.getDaysInMonth = function() {
1561 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1562 return Date.daysInMonth[this.getMonth()];
1566 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1567 * @return {String} 'st, 'nd', 'rd' or 'th'
1569 Date.prototype.getSuffix = function() {
1570 switch (this.getDate()) {
1587 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1590 * An array of textual month names.
1591 * Override these values for international dates, for example...
1592 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1611 * An array of textual day names.
1612 * Override these values for international dates, for example...
1613 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1629 Date.monthNumbers = {
1644 * Creates and returns a new Date instance with the exact same date value as the called instance.
1645 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1646 * variable will also be changed. When the intention is to create a new variable that will not
1647 * modify the original instance, you should create a clone.
1649 * Example of correctly cloning a date:
1652 var orig = new Date('10/1/2006');
1655 document.write(orig); //returns 'Thu Oct 05 2006'!
1658 var orig = new Date('10/1/2006');
1659 var copy = orig.clone();
1661 document.write(orig); //returns 'Thu Oct 01 2006'
1663 * @return {Date} The new Date instance
1665 Date.prototype.clone = function() {
1666 return new Date(this.getTime());
1670 * Clears any time information from this date
1671 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1672 @return {Date} this or the clone
1674 Date.prototype.clearTime = function(clone){
1676 return this.clone().clearTime();
1681 this.setMilliseconds(0);
1686 // safari setMonth is broken
1688 Date.brokenSetMonth = Date.prototype.setMonth;
1689 Date.prototype.setMonth = function(num){
1691 var n = Math.ceil(-num);
1692 var back_year = Math.ceil(n/12);
1693 var month = (n % 12) ? 12 - n % 12 : 0 ;
1694 this.setFullYear(this.getFullYear() - back_year);
1695 return Date.brokenSetMonth.call(this, month);
1697 return Date.brokenSetMonth.apply(this, arguments);
1702 /** Date interval constant
1706 /** Date interval constant
1710 /** Date interval constant
1714 /** Date interval constant
1718 /** Date interval constant
1722 /** Date interval constant
1726 /** Date interval constant
1732 * Provides a convenient method of performing basic date arithmetic. This method
1733 * does not modify the Date instance being called - it creates and returns
1734 * a new Date instance containing the resulting date value.
1739 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1740 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1742 //Negative values will subtract correctly:
1743 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1744 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1746 //You can even chain several calls together in one line!
1747 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1748 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1751 * @param {String} interval A valid date interval enum value
1752 * @param {Number} value The amount to add to the current date
1753 * @return {Date} The new Date instance
1755 Date.prototype.add = function(interval, value){
1756 var d = this.clone();
1757 if (!interval || value === 0) return d;
1758 switch(interval.toLowerCase()){
1760 d.setMilliseconds(this.getMilliseconds() + value);
1763 d.setSeconds(this.getSeconds() + value);
1766 d.setMinutes(this.getMinutes() + value);
1769 d.setHours(this.getHours() + value);
1772 d.setDate(this.getDate() + value);
1775 var day = this.getDate();
1777 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1780 d.setMonth(this.getMonth() + value);
1783 d.setFullYear(this.getFullYear() + value);
1790 * Ext JS Library 1.1.1
1791 * Copyright(c) 2006-2007, Ext JS, LLC.
1793 * Originally Released Under LGPL - original licence link has changed is not relivant.
1796 * <script type="text/javascript">
1800 * @class Roo.lib.Dom
1803 * Dom utils (from YIU afaik)
1808 * Get the view width
1809 * @param {Boolean} full True will get the full document, otherwise it's the view width
1810 * @return {Number} The width
1813 getViewWidth : function(full) {
1814 return full ? this.getDocumentWidth() : this.getViewportWidth();
1817 * Get the view height
1818 * @param {Boolean} full True will get the full document, otherwise it's the view height
1819 * @return {Number} The height
1821 getViewHeight : function(full) {
1822 return full ? this.getDocumentHeight() : this.getViewportHeight();
1825 getDocumentHeight: function() {
1826 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1827 return Math.max(scrollHeight, this.getViewportHeight());
1830 getDocumentWidth: function() {
1831 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1832 return Math.max(scrollWidth, this.getViewportWidth());
1835 getViewportHeight: function() {
1836 var height = self.innerHeight;
1837 var mode = document.compatMode;
1839 if ((mode || Roo.isIE) && !Roo.isOpera) {
1840 height = (mode == "CSS1Compat") ?
1841 document.documentElement.clientHeight :
1842 document.body.clientHeight;
1848 getViewportWidth: function() {
1849 var width = self.innerWidth;
1850 var mode = document.compatMode;
1852 if (mode || Roo.isIE) {
1853 width = (mode == "CSS1Compat") ?
1854 document.documentElement.clientWidth :
1855 document.body.clientWidth;
1860 isAncestor : function(p, c) {
1867 if (p.contains && !Roo.isSafari) {
1868 return p.contains(c);
1869 } else if (p.compareDocumentPosition) {
1870 return !!(p.compareDocumentPosition(c) & 16);
1872 var parent = c.parentNode;
1877 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1880 parent = parent.parentNode;
1886 getRegion : function(el) {
1887 return Roo.lib.Region.getRegion(el);
1890 getY : function(el) {
1891 return this.getXY(el)[1];
1894 getX : function(el) {
1895 return this.getXY(el)[0];
1898 getXY : function(el) {
1899 var p, pe, b, scroll, bd = document.body;
1900 el = Roo.getDom(el);
1901 var fly = Roo.lib.AnimBase.fly;
1902 if (el.getBoundingClientRect) {
1903 b = el.getBoundingClientRect();
1904 scroll = fly(document).getScroll();
1905 return [b.left + scroll.left, b.top + scroll.top];
1911 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1918 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1925 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1926 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1933 if (p != el && pe.getStyle('overflow') != 'visible') {
1941 if (Roo.isSafari && hasAbsolute) {
1946 if (Roo.isGecko && !hasAbsolute) {
1948 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1949 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1953 while (p && p != bd) {
1954 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1966 setXY : function(el, xy) {
1967 el = Roo.fly(el, '_setXY');
1969 var pts = el.translatePoints(xy);
1970 if (xy[0] !== false) {
1971 el.dom.style.left = pts.left + "px";
1973 if (xy[1] !== false) {
1974 el.dom.style.top = pts.top + "px";
1978 setX : function(el, x) {
1979 this.setXY(el, [x, false]);
1982 setY : function(el, y) {
1983 this.setXY(el, [false, y]);
1987 * Portions of this file are based on pieces of Yahoo User Interface Library
1988 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1989 * YUI licensed under the BSD License:
1990 * http://developer.yahoo.net/yui/license.txt
1991 * <script type="text/javascript">
1995 Roo.lib.Event = function() {
1996 var loadComplete = false;
1998 var unloadListeners = [];
2000 var onAvailStack = [];
2002 var lastError = null;
2015 startInterval: function() {
2016 if (!this._interval) {
2018 var callback = function() {
2019 self._tryPreloadAttach();
2021 this._interval = setInterval(callback, this.POLL_INTERVAL);
2026 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2027 onAvailStack.push({ id: p_id,
2030 override: p_override,
2031 checkReady: false });
2033 retryCount = this.POLL_RETRYS;
2034 this.startInterval();
2038 addListener: function(el, eventName, fn) {
2039 el = Roo.getDom(el);
2044 if ("unload" == eventName) {
2045 unloadListeners[unloadListeners.length] =
2046 [el, eventName, fn];
2050 var wrappedFn = function(e) {
2051 return fn(Roo.lib.Event.getEvent(e));
2054 var li = [el, eventName, fn, wrappedFn];
2056 var index = listeners.length;
2057 listeners[index] = li;
2059 this.doAdd(el, eventName, wrappedFn, false);
2065 removeListener: function(el, eventName, fn) {
2068 el = Roo.getDom(el);
2071 return this.purgeElement(el, false, eventName);
2075 if ("unload" == eventName) {
2077 for (i = 0,len = unloadListeners.length; i < len; i++) {
2078 var li = unloadListeners[i];
2081 li[1] == eventName &&
2083 unloadListeners.splice(i, 1);
2091 var cacheItem = null;
2094 var index = arguments[3];
2096 if ("undefined" == typeof index) {
2097 index = this._getCacheIndex(el, eventName, fn);
2101 cacheItem = listeners[index];
2104 if (!el || !cacheItem) {
2108 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2110 delete listeners[index][this.WFN];
2111 delete listeners[index][this.FN];
2112 listeners.splice(index, 1);
2119 getTarget: function(ev, resolveTextNode) {
2120 ev = ev.browserEvent || ev;
2121 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2122 var t = ev.target || ev.srcElement;
2123 return this.resolveTextNode(t);
2127 resolveTextNode: function(node) {
2128 if (Roo.isSafari && node && 3 == node.nodeType) {
2129 return node.parentNode;
2136 getPageX: function(ev) {
2137 ev = ev.browserEvent || ev;
2138 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2140 if (!x && 0 !== x) {
2141 x = ev.clientX || 0;
2144 x += this.getScroll()[1];
2152 getPageY: function(ev) {
2153 ev = ev.browserEvent || ev;
2154 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2156 if (!y && 0 !== y) {
2157 y = ev.clientY || 0;
2160 y += this.getScroll()[0];
2169 getXY: function(ev) {
2170 ev = ev.browserEvent || ev;
2171 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2172 return [this.getPageX(ev), this.getPageY(ev)];
2176 getRelatedTarget: function(ev) {
2177 ev = ev.browserEvent || ev;
2178 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2179 var t = ev.relatedTarget;
2181 if (ev.type == "mouseout") {
2183 } else if (ev.type == "mouseover") {
2188 return this.resolveTextNode(t);
2192 getTime: function(ev) {
2193 ev = ev.browserEvent || ev;
2194 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2196 var t = new Date().getTime();
2200 this.lastError = ex;
2209 stopEvent: function(ev) {
2210 this.stopPropagation(ev);
2211 this.preventDefault(ev);
2215 stopPropagation: function(ev) {
2216 ev = ev.browserEvent || ev;
2217 if (ev.stopPropagation) {
2218 ev.stopPropagation();
2220 ev.cancelBubble = true;
2225 preventDefault: function(ev) {
2226 ev = ev.browserEvent || ev;
2227 if(ev.preventDefault) {
2228 ev.preventDefault();
2230 ev.returnValue = false;
2235 getEvent: function(e) {
2236 var ev = e || window.event;
2238 var c = this.getEvent.caller;
2240 ev = c.arguments[0];
2241 if (ev && Event == ev.constructor) {
2251 getCharCode: function(ev) {
2252 ev = ev.browserEvent || ev;
2253 return ev.charCode || ev.keyCode || 0;
2257 _getCacheIndex: function(el, eventName, fn) {
2258 for (var i = 0,len = listeners.length; i < len; ++i) {
2259 var li = listeners[i];
2261 li[this.FN] == fn &&
2262 li[this.EL] == el &&
2263 li[this.TYPE] == eventName) {
2275 getEl: function(id) {
2276 return document.getElementById(id);
2280 clearCache: function() {
2284 _load: function(e) {
2285 loadComplete = true;
2286 var EU = Roo.lib.Event;
2290 EU.doRemove(window, "load", EU._load);
2295 _tryPreloadAttach: function() {
2304 var tryAgain = !loadComplete;
2306 tryAgain = (retryCount > 0);
2311 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2312 var item = onAvailStack[i];
2314 var el = this.getEl(item.id);
2317 if (!item.checkReady ||
2320 (document && document.body)) {
2323 if (item.override) {
2324 if (item.override === true) {
2327 scope = item.override;
2330 item.fn.call(scope, item.obj);
2331 onAvailStack[i] = null;
2334 notAvail.push(item);
2339 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2343 this.startInterval();
2345 clearInterval(this._interval);
2346 this._interval = null;
2349 this.locked = false;
2356 purgeElement: function(el, recurse, eventName) {
2357 var elListeners = this.getListeners(el, eventName);
2359 for (var i = 0,len = elListeners.length; i < len; ++i) {
2360 var l = elListeners[i];
2361 this.removeListener(el, l.type, l.fn);
2365 if (recurse && el && el.childNodes) {
2366 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2367 this.purgeElement(el.childNodes[i], recurse, eventName);
2373 getListeners: function(el, eventName) {
2374 var results = [], searchLists;
2376 searchLists = [listeners, unloadListeners];
2377 } else if (eventName == "unload") {
2378 searchLists = [unloadListeners];
2380 searchLists = [listeners];
2383 for (var j = 0; j < searchLists.length; ++j) {
2384 var searchList = searchLists[j];
2385 if (searchList && searchList.length > 0) {
2386 for (var i = 0,len = searchList.length; i < len; ++i) {
2387 var l = searchList[i];
2388 if (l && l[this.EL] === el &&
2389 (!eventName || eventName === l[this.TYPE])) {
2394 adjust: l[this.ADJ_SCOPE],
2402 return (results.length) ? results : null;
2406 _unload: function(e) {
2408 var EU = Roo.lib.Event, i, j, l, len, index;
2410 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2411 l = unloadListeners[i];
2414 if (l[EU.ADJ_SCOPE]) {
2415 if (l[EU.ADJ_SCOPE] === true) {
2418 scope = l[EU.ADJ_SCOPE];
2421 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2422 unloadListeners[i] = null;
2428 unloadListeners = null;
2430 if (listeners && listeners.length > 0) {
2431 j = listeners.length;
2434 l = listeners[index];
2436 EU.removeListener(l[EU.EL], l[EU.TYPE],
2446 EU.doRemove(window, "unload", EU._unload);
2451 getScroll: function() {
2452 var dd = document.documentElement, db = document.body;
2453 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2454 return [dd.scrollTop, dd.scrollLeft];
2456 return [db.scrollTop, db.scrollLeft];
2463 doAdd: function () {
2464 if (window.addEventListener) {
2465 return function(el, eventName, fn, capture) {
2466 el.addEventListener(eventName, fn, (capture));
2468 } else if (window.attachEvent) {
2469 return function(el, eventName, fn, capture) {
2470 el.attachEvent("on" + eventName, fn);
2479 doRemove: function() {
2480 if (window.removeEventListener) {
2481 return function (el, eventName, fn, capture) {
2482 el.removeEventListener(eventName, fn, (capture));
2484 } else if (window.detachEvent) {
2485 return function (el, eventName, fn) {
2486 el.detachEvent("on" + eventName, fn);
2498 var E = Roo.lib.Event;
2499 E.on = E.addListener;
2500 E.un = E.removeListener;
2502 if (document && document.body) {
2505 E.doAdd(window, "load", E._load);
2507 E.doAdd(window, "unload", E._unload);
2508 E._tryPreloadAttach();
2512 * Portions of this file are based on pieces of Yahoo User Interface Library
2513 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2514 * YUI licensed under the BSD License:
2515 * http://developer.yahoo.net/yui/license.txt
2516 * <script type="text/javascript">
2522 * @class Roo.lib.Ajax
2529 request : function(method, uri, cb, data, options) {
2531 var hs = options.headers;
2534 if(hs.hasOwnProperty(h)){
2535 this.initHeader(h, hs[h], false);
2539 if(options.xmlData){
2540 this.initHeader('Content-Type', 'text/xml', false);
2542 data = options.xmlData;
2546 return this.asyncRequest(method, uri, cb, data);
2549 serializeForm : function(form) {
2550 if(typeof form == 'string') {
2551 form = (document.getElementById(form) || document.forms[form]);
2554 var el, name, val, disabled, data = '', hasSubmit = false;
2555 for (var i = 0; i < form.elements.length; i++) {
2556 el = form.elements[i];
2557 disabled = form.elements[i].disabled;
2558 name = form.elements[i].name;
2559 val = form.elements[i].value;
2561 if (!disabled && name){
2565 case 'select-multiple':
2566 for (var j = 0; j < el.options.length; j++) {
2567 if (el.options[j].selected) {
2569 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2572 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2580 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2593 if(hasSubmit == false) {
2594 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2599 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2604 data = data.substr(0, data.length - 1);
2612 useDefaultHeader:true,
2614 defaultPostHeader:'application/x-www-form-urlencoded',
2616 useDefaultXhrHeader:true,
2618 defaultXhrHeader:'XMLHttpRequest',
2620 hasDefaultHeaders:true,
2632 setProgId:function(id)
2634 this.activeX.unshift(id);
2637 setDefaultPostHeader:function(b)
2639 this.useDefaultHeader = b;
2642 setDefaultXhrHeader:function(b)
2644 this.useDefaultXhrHeader = b;
2647 setPollingInterval:function(i)
2649 if (typeof i == 'number' && isFinite(i)) {
2650 this.pollInterval = i;
2654 createXhrObject:function(transactionId)
2660 http = new XMLHttpRequest();
2662 obj = { conn:http, tId:transactionId };
2666 for (var i = 0; i < this.activeX.length; ++i) {
2670 http = new ActiveXObject(this.activeX[i]);
2672 obj = { conn:http, tId:transactionId };
2685 getConnectionObject:function()
2688 var tId = this.transactionId;
2692 o = this.createXhrObject(tId);
2694 this.transactionId++;
2705 asyncRequest:function(method, uri, callback, postData)
2707 var o = this.getConnectionObject();
2713 o.conn.open(method, uri, true);
2715 if (this.useDefaultXhrHeader) {
2716 if (!this.defaultHeaders['X-Requested-With']) {
2717 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2721 if(postData && this.useDefaultHeader){
2722 this.initHeader('Content-Type', this.defaultPostHeader);
2725 if (this.hasDefaultHeaders || this.hasHeaders) {
2729 this.handleReadyState(o, callback);
2730 o.conn.send(postData || null);
2736 handleReadyState:function(o, callback)
2740 if (callback && callback.timeout) {
2742 this.timeout[o.tId] = window.setTimeout(function() {
2743 oConn.abort(o, callback, true);
2744 }, callback.timeout);
2747 this.poll[o.tId] = window.setInterval(
2749 if (o.conn && o.conn.readyState == 4) {
2750 window.clearInterval(oConn.poll[o.tId]);
2751 delete oConn.poll[o.tId];
2753 if(callback && callback.timeout) {
2754 window.clearTimeout(oConn.timeout[o.tId]);
2755 delete oConn.timeout[o.tId];
2758 oConn.handleTransactionResponse(o, callback);
2761 , this.pollInterval);
2764 handleTransactionResponse:function(o, callback, isAbort)
2768 this.releaseObject(o);
2772 var httpStatus, responseObject;
2776 if (o.conn.status !== undefined && o.conn.status != 0) {
2777 httpStatus = o.conn.status;
2789 if (httpStatus >= 200 && httpStatus < 300) {
2790 responseObject = this.createResponseObject(o, callback.argument);
2791 if (callback.success) {
2792 if (!callback.scope) {
2793 callback.success(responseObject);
2798 callback.success.apply(callback.scope, [responseObject]);
2803 switch (httpStatus) {
2811 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2812 if (callback.failure) {
2813 if (!callback.scope) {
2814 callback.failure(responseObject);
2817 callback.failure.apply(callback.scope, [responseObject]);
2822 responseObject = this.createResponseObject(o, callback.argument);
2823 if (callback.failure) {
2824 if (!callback.scope) {
2825 callback.failure(responseObject);
2828 callback.failure.apply(callback.scope, [responseObject]);
2834 this.releaseObject(o);
2835 responseObject = null;
2838 createResponseObject:function(o, callbackArg)
2845 var headerStr = o.conn.getAllResponseHeaders();
2846 var header = headerStr.split('\n');
2847 for (var i = 0; i < header.length; i++) {
2848 var delimitPos = header[i].indexOf(':');
2849 if (delimitPos != -1) {
2850 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2858 obj.status = o.conn.status;
2859 obj.statusText = o.conn.statusText;
2860 obj.getResponseHeader = headerObj;
2861 obj.getAllResponseHeaders = headerStr;
2862 obj.responseText = o.conn.responseText;
2863 obj.responseXML = o.conn.responseXML;
2865 if (typeof callbackArg !== undefined) {
2866 obj.argument = callbackArg;
2872 createExceptionObject:function(tId, callbackArg, isAbort)
2875 var COMM_ERROR = 'communication failure';
2876 var ABORT_CODE = -1;
2877 var ABORT_ERROR = 'transaction aborted';
2883 obj.status = ABORT_CODE;
2884 obj.statusText = ABORT_ERROR;
2887 obj.status = COMM_CODE;
2888 obj.statusText = COMM_ERROR;
2892 obj.argument = callbackArg;
2898 initHeader:function(label, value, isDefault)
2900 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2902 if (headerObj[label] === undefined) {
2903 headerObj[label] = value;
2908 headerObj[label] = value + "," + headerObj[label];
2912 this.hasDefaultHeaders = true;
2915 this.hasHeaders = true;
2920 setHeader:function(o)
2922 if (this.hasDefaultHeaders) {
2923 for (var prop in this.defaultHeaders) {
2924 if (this.defaultHeaders.hasOwnProperty(prop)) {
2925 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2930 if (this.hasHeaders) {
2931 for (var prop in this.headers) {
2932 if (this.headers.hasOwnProperty(prop)) {
2933 o.conn.setRequestHeader(prop, this.headers[prop]);
2937 this.hasHeaders = false;
2941 resetDefaultHeaders:function() {
2942 delete this.defaultHeaders;
2943 this.defaultHeaders = {};
2944 this.hasDefaultHeaders = false;
2947 abort:function(o, callback, isTimeout)
2949 if(this.isCallInProgress(o)) {
2951 window.clearInterval(this.poll[o.tId]);
2952 delete this.poll[o.tId];
2954 delete this.timeout[o.tId];
2957 this.handleTransactionResponse(o, callback, true);
2967 isCallInProgress:function(o)
2970 return o.conn.readyState != 4 && o.conn.readyState != 0;
2979 releaseObject:function(o)
2988 'MSXML2.XMLHTTP.3.0',
2996 * Portions of this file are based on pieces of Yahoo User Interface Library
2997 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2998 * YUI licensed under the BSD License:
2999 * http://developer.yahoo.net/yui/license.txt
3000 * <script type="text/javascript">
3004 Roo.lib.Region = function(t, r, b, l) {
3014 Roo.lib.Region.prototype = {
3015 contains : function(region) {
3016 return ( region.left >= this.left &&
3017 region.right <= this.right &&
3018 region.top >= this.top &&
3019 region.bottom <= this.bottom );
3023 getArea : function() {
3024 return ( (this.bottom - this.top) * (this.right - this.left) );
3027 intersect : function(region) {
3028 var t = Math.max(this.top, region.top);
3029 var r = Math.min(this.right, region.right);
3030 var b = Math.min(this.bottom, region.bottom);
3031 var l = Math.max(this.left, region.left);
3033 if (b >= t && r >= l) {
3034 return new Roo.lib.Region(t, r, b, l);
3039 union : function(region) {
3040 var t = Math.min(this.top, region.top);
3041 var r = Math.max(this.right, region.right);
3042 var b = Math.max(this.bottom, region.bottom);
3043 var l = Math.min(this.left, region.left);
3045 return new Roo.lib.Region(t, r, b, l);
3048 adjust : function(t, l, b, r) {
3057 Roo.lib.Region.getRegion = function(el) {
3058 var p = Roo.lib.Dom.getXY(el);
3061 var r = p[0] + el.offsetWidth;
3062 var b = p[1] + el.offsetHeight;
3065 return new Roo.lib.Region(t, r, b, l);
3068 * Portions of this file are based on pieces of Yahoo User Interface Library
3069 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3070 * YUI licensed under the BSD License:
3071 * http://developer.yahoo.net/yui/license.txt
3072 * <script type="text/javascript">
3075 //@@dep Roo.lib.Region
3078 Roo.lib.Point = function(x, y) {
3079 if (x instanceof Array) {
3083 this.x = this.right = this.left = this[0] = x;
3084 this.y = this.top = this.bottom = this[1] = y;
3087 Roo.lib.Point.prototype = new Roo.lib.Region();
3089 * Portions of this file are based on pieces of Yahoo User Interface Library
3090 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3091 * YUI licensed under the BSD License:
3092 * http://developer.yahoo.net/yui/license.txt
3093 * <script type="text/javascript">
3100 scroll : function(el, args, duration, easing, cb, scope) {
3101 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3104 motion : function(el, args, duration, easing, cb, scope) {
3105 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3108 color : function(el, args, duration, easing, cb, scope) {
3109 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3112 run : function(el, args, duration, easing, cb, scope, type) {
3113 type = type || Roo.lib.AnimBase;
3114 if (typeof easing == "string") {
3115 easing = Roo.lib.Easing[easing];
3117 var anim = new type(el, args, duration, easing);
3118 anim.animateX(function() {
3119 Roo.callback(cb, scope);
3125 * Portions of this file are based on pieces of Yahoo User Interface Library
3126 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3127 * YUI licensed under the BSD License:
3128 * http://developer.yahoo.net/yui/license.txt
3129 * <script type="text/javascript">
3137 if (!libFlyweight) {
3138 libFlyweight = new Roo.Element.Flyweight();
3140 libFlyweight.dom = el;
3141 return libFlyweight;
3144 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3148 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3150 this.init(el, attributes, duration, method);
3154 Roo.lib.AnimBase.fly = fly;
3158 Roo.lib.AnimBase.prototype = {
3160 toString: function() {
3161 var el = this.getEl();
3162 var id = el.id || el.tagName;
3163 return ("Anim " + id);
3167 noNegatives: /width|height|opacity|padding/i,
3168 offsetAttribute: /^((width|height)|(top|left))$/,
3169 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3170 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3174 doMethod: function(attr, start, end) {
3175 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3179 setAttribute: function(attr, val, unit) {
3180 if (this.patterns.noNegatives.test(attr)) {
3181 val = (val > 0) ? val : 0;
3184 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3188 getAttribute: function(attr) {
3189 var el = this.getEl();
3190 var val = fly(el).getStyle(attr);
3192 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3193 return parseFloat(val);
3196 var a = this.patterns.offsetAttribute.exec(attr) || [];
3197 var pos = !!( a[3] );
3198 var box = !!( a[2] );
3201 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3202 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3211 getDefaultUnit: function(attr) {
3212 if (this.patterns.defaultUnit.test(attr)) {
3219 animateX : function(callback, scope) {
3220 var f = function() {
3221 this.onComplete.removeListener(f);
3222 if (typeof callback == "function") {
3223 callback.call(scope || this, this);
3226 this.onComplete.addListener(f, this);
3231 setRuntimeAttribute: function(attr) {
3234 var attributes = this.attributes;
3236 this.runtimeAttributes[attr] = {};
3238 var isset = function(prop) {
3239 return (typeof prop !== 'undefined');
3242 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3246 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3249 if (isset(attributes[attr]['to'])) {
3250 end = attributes[attr]['to'];
3251 } else if (isset(attributes[attr]['by'])) {
3252 if (start.constructor == Array) {
3254 for (var i = 0, len = start.length; i < len; ++i) {
3255 end[i] = start[i] + attributes[attr]['by'][i];
3258 end = start + attributes[attr]['by'];
3262 this.runtimeAttributes[attr].start = start;
3263 this.runtimeAttributes[attr].end = end;
3266 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3270 init: function(el, attributes, duration, method) {
3272 var isAnimated = false;
3275 var startTime = null;
3278 var actualFrames = 0;
3281 el = Roo.getDom(el);
3284 this.attributes = attributes || {};
3287 this.duration = duration || 1;
3290 this.method = method || Roo.lib.Easing.easeNone;
3293 this.useSeconds = true;
3296 this.currentFrame = 0;
3299 this.totalFrames = Roo.lib.AnimMgr.fps;
3302 this.getEl = function() {
3307 this.isAnimated = function() {
3312 this.getStartTime = function() {
3316 this.runtimeAttributes = {};
3319 this.animate = function() {
3320 if (this.isAnimated()) {
3324 this.currentFrame = 0;
3326 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3328 Roo.lib.AnimMgr.registerElement(this);
3332 this.stop = function(finish) {
3334 this.currentFrame = this.totalFrames;
3335 this._onTween.fire();
3337 Roo.lib.AnimMgr.stop(this);
3340 var onStart = function() {
3341 this.onStart.fire();
3343 this.runtimeAttributes = {};
3344 for (var attr in this.attributes) {
3345 this.setRuntimeAttribute(attr);
3350 startTime = new Date();
3354 var onTween = function() {
3356 duration: new Date() - this.getStartTime(),
3357 currentFrame: this.currentFrame
3360 data.toString = function() {
3362 'duration: ' + data.duration +
3363 ', currentFrame: ' + data.currentFrame
3367 this.onTween.fire(data);
3369 var runtimeAttributes = this.runtimeAttributes;
3371 for (var attr in runtimeAttributes) {
3372 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3378 var onComplete = function() {
3379 var actual_duration = (new Date() - startTime) / 1000 ;
3382 duration: actual_duration,
3383 frames: actualFrames,
3384 fps: actualFrames / actual_duration
3387 data.toString = function() {
3389 'duration: ' + data.duration +
3390 ', frames: ' + data.frames +
3391 ', fps: ' + data.fps
3397 this.onComplete.fire(data);
3401 this._onStart = new Roo.util.Event(this);
3402 this.onStart = new Roo.util.Event(this);
3403 this.onTween = new Roo.util.Event(this);
3404 this._onTween = new Roo.util.Event(this);
3405 this.onComplete = new Roo.util.Event(this);
3406 this._onComplete = new Roo.util.Event(this);
3407 this._onStart.addListener(onStart);
3408 this._onTween.addListener(onTween);
3409 this._onComplete.addListener(onComplete);
3414 * Portions of this file are based on pieces of Yahoo User Interface Library
3415 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3416 * YUI licensed under the BSD License:
3417 * http://developer.yahoo.net/yui/license.txt
3418 * <script type="text/javascript">
3422 Roo.lib.AnimMgr = new function() {
3439 this.registerElement = function(tween) {
3440 queue[queue.length] = tween;
3442 tween._onStart.fire();
3447 this.unRegister = function(tween, index) {
3448 tween._onComplete.fire();
3449 index = index || getIndex(tween);
3451 queue.splice(index, 1);
3455 if (tweenCount <= 0) {
3461 this.start = function() {
3462 if (thread === null) {
3463 thread = setInterval(this.run, this.delay);
3468 this.stop = function(tween) {
3470 clearInterval(thread);
3472 for (var i = 0, len = queue.length; i < len; ++i) {
3473 if (queue[0].isAnimated()) {
3474 this.unRegister(queue[0], 0);
3483 this.unRegister(tween);
3488 this.run = function() {
3489 for (var i = 0, len = queue.length; i < len; ++i) {
3490 var tween = queue[i];
3491 if (!tween || !tween.isAnimated()) {
3495 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3497 tween.currentFrame += 1;
3499 if (tween.useSeconds) {
3500 correctFrame(tween);
3502 tween._onTween.fire();
3505 Roo.lib.AnimMgr.stop(tween, i);
3510 var getIndex = function(anim) {
3511 for (var i = 0, len = queue.length; i < len; ++i) {
3512 if (queue[i] == anim) {
3520 var correctFrame = function(tween) {
3521 var frames = tween.totalFrames;
3522 var frame = tween.currentFrame;
3523 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3524 var elapsed = (new Date() - tween.getStartTime());
3527 if (elapsed < tween.duration * 1000) {
3528 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3530 tweak = frames - (frame + 1);
3532 if (tweak > 0 && isFinite(tweak)) {
3533 if (tween.currentFrame + tweak >= frames) {
3534 tweak = frames - (frame + 1);
3537 tween.currentFrame += tweak;
3543 * Portions of this file are based on pieces of Yahoo User Interface Library
3544 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545 * YUI licensed under the BSD License:
3546 * http://developer.yahoo.net/yui/license.txt
3547 * <script type="text/javascript">
3550 Roo.lib.Bezier = new function() {
3552 this.getPosition = function(points, t) {
3553 var n = points.length;
3556 for (var i = 0; i < n; ++i) {
3557 tmp[i] = [points[i][0], points[i][1]];
3560 for (var j = 1; j < n; ++j) {
3561 for (i = 0; i < n - j; ++i) {
3562 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3563 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3567 return [ tmp[0][0], tmp[0][1] ];
3571 * Portions of this file are based on pieces of Yahoo User Interface Library
3572 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3573 * YUI licensed under the BSD License:
3574 * http://developer.yahoo.net/yui/license.txt
3575 * <script type="text/javascript">
3580 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3581 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3584 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3586 var fly = Roo.lib.AnimBase.fly;
3588 var superclass = Y.ColorAnim.superclass;
3589 var proto = Y.ColorAnim.prototype;
3591 proto.toString = function() {
3592 var el = this.getEl();
3593 var id = el.id || el.tagName;
3594 return ("ColorAnim " + id);
3597 proto.patterns.color = /color$/i;
3598 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3599 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3600 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3601 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3604 proto.parseColor = function(s) {
3605 if (s.length == 3) {
3609 var c = this.patterns.hex.exec(s);
3610 if (c && c.length == 4) {
3611 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3614 c = this.patterns.rgb.exec(s);
3615 if (c && c.length == 4) {
3616 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3619 c = this.patterns.hex3.exec(s);
3620 if (c && c.length == 4) {
3621 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3626 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3627 proto.getAttribute = function(attr) {
3628 var el = this.getEl();
3629 if (this.patterns.color.test(attr)) {
3630 var val = fly(el).getStyle(attr);
3632 if (this.patterns.transparent.test(val)) {
3633 var parent = el.parentNode;
3634 val = fly(parent).getStyle(attr);
3636 while (parent && this.patterns.transparent.test(val)) {
3637 parent = parent.parentNode;
3638 val = fly(parent).getStyle(attr);
3639 if (parent.tagName.toUpperCase() == 'HTML') {
3645 val = superclass.getAttribute.call(this, attr);
3650 proto.getAttribute = function(attr) {
3651 var el = this.getEl();
3652 if (this.patterns.color.test(attr)) {
3653 var val = fly(el).getStyle(attr);
3655 if (this.patterns.transparent.test(val)) {
3656 var parent = el.parentNode;
3657 val = fly(parent).getStyle(attr);
3659 while (parent && this.patterns.transparent.test(val)) {
3660 parent = parent.parentNode;
3661 val = fly(parent).getStyle(attr);
3662 if (parent.tagName.toUpperCase() == 'HTML') {
3668 val = superclass.getAttribute.call(this, attr);
3674 proto.doMethod = function(attr, start, end) {
3677 if (this.patterns.color.test(attr)) {
3679 for (var i = 0, len = start.length; i < len; ++i) {
3680 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3683 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3686 val = superclass.doMethod.call(this, attr, start, end);
3692 proto.setRuntimeAttribute = function(attr) {
3693 superclass.setRuntimeAttribute.call(this, attr);
3695 if (this.patterns.color.test(attr)) {
3696 var attributes = this.attributes;
3697 var start = this.parseColor(this.runtimeAttributes[attr].start);
3698 var end = this.parseColor(this.runtimeAttributes[attr].end);
3700 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3701 end = this.parseColor(attributes[attr].by);
3703 for (var i = 0, len = start.length; i < len; ++i) {
3704 end[i] = start[i] + end[i];
3708 this.runtimeAttributes[attr].start = start;
3709 this.runtimeAttributes[attr].end = end;
3715 * Portions of this file are based on pieces of Yahoo User Interface Library
3716 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3717 * YUI licensed under the BSD License:
3718 * http://developer.yahoo.net/yui/license.txt
3719 * <script type="text/javascript">
3725 easeNone: function (t, b, c, d) {
3726 return c * t / d + b;
3730 easeIn: function (t, b, c, d) {
3731 return c * (t /= d) * t + b;
3735 easeOut: function (t, b, c, d) {
3736 return -c * (t /= d) * (t - 2) + b;
3740 easeBoth: function (t, b, c, d) {
3741 if ((t /= d / 2) < 1) {
3742 return c / 2 * t * t + b;
3745 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3749 easeInStrong: function (t, b, c, d) {
3750 return c * (t /= d) * t * t * t + b;
3754 easeOutStrong: function (t, b, c, d) {
3755 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3759 easeBothStrong: function (t, b, c, d) {
3760 if ((t /= d / 2) < 1) {
3761 return c / 2 * t * t * t * t + b;
3764 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3769 elasticIn: function (t, b, c, d, a, p) {
3773 if ((t /= d) == 1) {
3780 if (!a || a < Math.abs(c)) {
3785 var s = p / (2 * Math.PI) * Math.asin(c / a);
3788 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3792 elasticOut: function (t, b, c, d, a, p) {
3796 if ((t /= d) == 1) {
3803 if (!a || a < Math.abs(c)) {
3808 var s = p / (2 * Math.PI) * Math.asin(c / a);
3811 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3815 elasticBoth: function (t, b, c, d, a, p) {
3820 if ((t /= d / 2) == 2) {
3828 if (!a || a < Math.abs(c)) {
3833 var s = p / (2 * Math.PI) * Math.asin(c / a);
3837 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3838 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3840 return a * Math.pow(2, -10 * (t -= 1)) *
3841 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3846 backIn: function (t, b, c, d, s) {
3847 if (typeof s == 'undefined') {
3850 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3854 backOut: function (t, b, c, d, s) {
3855 if (typeof s == 'undefined') {
3858 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3862 backBoth: function (t, b, c, d, s) {
3863 if (typeof s == 'undefined') {
3867 if ((t /= d / 2 ) < 1) {
3868 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3870 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3874 bounceIn: function (t, b, c, d) {
3875 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3879 bounceOut: function (t, b, c, d) {
3880 if ((t /= d) < (1 / 2.75)) {
3881 return c * (7.5625 * t * t) + b;
3882 } else if (t < (2 / 2.75)) {
3883 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3884 } else if (t < (2.5 / 2.75)) {
3885 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3887 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3891 bounceBoth: function (t, b, c, d) {
3893 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3895 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3898 * Portions of this file are based on pieces of Yahoo User Interface Library
3899 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3900 * YUI licensed under the BSD License:
3901 * http://developer.yahoo.net/yui/license.txt
3902 * <script type="text/javascript">
3906 Roo.lib.Motion = function(el, attributes, duration, method) {
3908 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3912 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3916 var superclass = Y.Motion.superclass;
3917 var proto = Y.Motion.prototype;
3919 proto.toString = function() {
3920 var el = this.getEl();
3921 var id = el.id || el.tagName;
3922 return ("Motion " + id);
3925 proto.patterns.points = /^points$/i;
3927 proto.setAttribute = function(attr, val, unit) {
3928 if (this.patterns.points.test(attr)) {
3929 unit = unit || 'px';
3930 superclass.setAttribute.call(this, 'left', val[0], unit);
3931 superclass.setAttribute.call(this, 'top', val[1], unit);
3933 superclass.setAttribute.call(this, attr, val, unit);
3937 proto.getAttribute = function(attr) {
3938 if (this.patterns.points.test(attr)) {
3940 superclass.getAttribute.call(this, 'left'),
3941 superclass.getAttribute.call(this, 'top')
3944 val = superclass.getAttribute.call(this, attr);
3950 proto.doMethod = function(attr, start, end) {
3953 if (this.patterns.points.test(attr)) {
3954 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3955 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3957 val = superclass.doMethod.call(this, attr, start, end);
3962 proto.setRuntimeAttribute = function(attr) {
3963 if (this.patterns.points.test(attr)) {
3964 var el = this.getEl();
3965 var attributes = this.attributes;
3967 var control = attributes['points']['control'] || [];
3971 if (control.length > 0 && !(control[0] instanceof Array)) {
3972 control = [control];
3975 for (i = 0,len = control.length; i < len; ++i) {
3976 tmp[i] = control[i];
3981 Roo.fly(el).position();
3983 if (isset(attributes['points']['from'])) {
3984 Roo.lib.Dom.setXY(el, attributes['points']['from']);
3987 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3990 start = this.getAttribute('points');
3993 if (isset(attributes['points']['to'])) {
3994 end = translateValues.call(this, attributes['points']['to'], start);
3996 var pageXY = Roo.lib.Dom.getXY(this.getEl());
3997 for (i = 0,len = control.length; i < len; ++i) {
3998 control[i] = translateValues.call(this, control[i], start);
4002 } else if (isset(attributes['points']['by'])) {
4003 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4005 for (i = 0,len = control.length; i < len; ++i) {
4006 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4010 this.runtimeAttributes[attr] = [start];
4012 if (control.length > 0) {
4013 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4016 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4019 superclass.setRuntimeAttribute.call(this, attr);
4023 var translateValues = function(val, start) {
4024 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4025 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4030 var isset = function(prop) {
4031 return (typeof prop !== 'undefined');
4035 * Portions of this file are based on pieces of Yahoo User Interface Library
4036 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4037 * YUI licensed under the BSD License:
4038 * http://developer.yahoo.net/yui/license.txt
4039 * <script type="text/javascript">
4043 Roo.lib.Scroll = function(el, attributes, duration, method) {
4045 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4049 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4053 var superclass = Y.Scroll.superclass;
4054 var proto = Y.Scroll.prototype;
4056 proto.toString = function() {
4057 var el = this.getEl();
4058 var id = el.id || el.tagName;
4059 return ("Scroll " + id);
4062 proto.doMethod = function(attr, start, end) {
4065 if (attr == 'scroll') {
4067 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4068 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4072 val = superclass.doMethod.call(this, attr, start, end);
4077 proto.getAttribute = function(attr) {
4079 var el = this.getEl();
4081 if (attr == 'scroll') {
4082 val = [ el.scrollLeft, el.scrollTop ];
4084 val = superclass.getAttribute.call(this, attr);
4090 proto.setAttribute = function(attr, val, unit) {
4091 var el = this.getEl();
4093 if (attr == 'scroll') {
4094 el.scrollLeft = val[0];
4095 el.scrollTop = val[1];
4097 superclass.setAttribute.call(this, attr, val, unit);
4103 * Ext JS Library 1.1.1
4104 * Copyright(c) 2006-2007, Ext JS, LLC.
4106 * Originally Released Under LGPL - original licence link has changed is not relivant.
4109 * <script type="text/javascript">
4113 // nasty IE9 hack - what a pile of crap that is..
4115 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4116 Range.prototype.createContextualFragment = function (html) {
4117 var doc = window.document;
4118 var container = doc.createElement("div");
4119 container.innerHTML = html;
4120 var frag = doc.createDocumentFragment(), n;
4121 while ((n = container.firstChild)) {
4122 frag.appendChild(n);
4129 * @class Roo.DomHelper
4130 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4131 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4134 Roo.DomHelper = function(){
4135 var tempTableEl = null;
4136 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4137 var tableRe = /^table|tbody|tr|td$/i;
4139 // build as innerHTML where available
4141 var createHtml = function(o){
4142 if(typeof o == 'string'){
4151 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4152 if(attr == "style"){
4154 if(typeof s == "function"){
4157 if(typeof s == "string"){
4158 b += ' style="' + s + '"';
4159 }else if(typeof s == "object"){
4162 if(typeof s[key] != "function"){
4163 b += key + ":" + s[key] + ";";
4170 b += ' class="' + o["cls"] + '"';
4171 }else if(attr == "htmlFor"){
4172 b += ' for="' + o["htmlFor"] + '"';
4174 b += " " + attr + '="' + o[attr] + '"';
4178 if(emptyTags.test(o.tag)){
4182 var cn = o.children || o.cn;
4184 //http://bugs.kde.org/show_bug.cgi?id=71506
4185 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4186 for(var i = 0, len = cn.length; i < len; i++) {
4187 b += createHtml(cn[i], b);
4190 b += createHtml(cn, b);
4196 b += "</" + o.tag + ">";
4203 var createDom = function(o, parentNode){
4205 // defininition craeted..
4207 if (o.ns && o.ns != 'html') {
4209 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4210 xmlns[o.ns] = o.xmlns;
4213 if (typeof(xmlns[o.ns]) == 'undefined') {
4214 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4220 if (typeof(o) == 'string') {
4221 return parentNode.appendChild(document.createTextNode(o));
4223 o.tag = o.tag || div;
4224 if (o.ns && Roo.isIE) {
4226 o.tag = o.ns + ':' + o.tag;
4229 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4230 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4233 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4234 attr == "style" || typeof o[attr] == "function") continue;
4236 if(attr=="cls" && Roo.isIE){
4237 el.className = o["cls"];
4239 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4240 else el[attr] = o[attr];
4243 Roo.DomHelper.applyStyles(el, o.style);
4244 var cn = o.children || o.cn;
4246 //http://bugs.kde.org/show_bug.cgi?id=71506
4247 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4248 for(var i = 0, len = cn.length; i < len; i++) {
4249 createDom(cn[i], el);
4256 el.innerHTML = o.html;
4259 parentNode.appendChild(el);
4264 var ieTable = function(depth, s, h, e){
4265 tempTableEl.innerHTML = [s, h, e].join('');
4266 var i = -1, el = tempTableEl;
4273 // kill repeat to save bytes
4277 tbe = '</tbody>'+te,
4283 * Nasty code for IE's broken table implementation
4285 var insertIntoTable = function(tag, where, el, html){
4287 tempTableEl = document.createElement('div');
4292 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4295 if(where == 'beforebegin'){
4299 before = el.nextSibling;
4302 node = ieTable(4, trs, html, tre);
4304 else if(tag == 'tr'){
4305 if(where == 'beforebegin'){
4308 node = ieTable(3, tbs, html, tbe);
4309 } else if(where == 'afterend'){
4310 before = el.nextSibling;
4312 node = ieTable(3, tbs, html, tbe);
4313 } else{ // INTO a TR
4314 if(where == 'afterbegin'){
4315 before = el.firstChild;
4317 node = ieTable(4, trs, html, tre);
4319 } else if(tag == 'tbody'){
4320 if(where == 'beforebegin'){
4323 node = ieTable(2, ts, html, te);
4324 } else if(where == 'afterend'){
4325 before = el.nextSibling;
4327 node = ieTable(2, ts, html, te);
4329 if(where == 'afterbegin'){
4330 before = el.firstChild;
4332 node = ieTable(3, tbs, html, tbe);
4335 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4338 if(where == 'afterbegin'){
4339 before = el.firstChild;
4341 node = ieTable(2, ts, html, te);
4343 el.insertBefore(node, before);
4348 /** True to force the use of DOM instead of html fragments @type Boolean */
4352 * Returns the markup for the passed Element(s) config
4353 * @param {Object} o The Dom object spec (and children)
4356 markup : function(o){
4357 return createHtml(o);
4361 * Applies a style specification to an element
4362 * @param {String/HTMLElement} el The element to apply styles to
4363 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4364 * a function which returns such a specification.
4366 applyStyles : function(el, styles){
4369 if(typeof styles == "string"){
4370 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4372 while ((matches = re.exec(styles)) != null){
4373 el.setStyle(matches[1], matches[2]);
4375 }else if (typeof styles == "object"){
4376 for (var style in styles){
4377 el.setStyle(style, styles[style]);
4379 }else if (typeof styles == "function"){
4380 Roo.DomHelper.applyStyles(el, styles.call());
4386 * Inserts an HTML fragment into the Dom
4387 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4388 * @param {HTMLElement} el The context element
4389 * @param {String} html The HTML fragmenet
4390 * @return {HTMLElement} The new node
4392 insertHtml : function(where, el, html){
4393 where = where.toLowerCase();
4394 if(el.insertAdjacentHTML){
4395 if(tableRe.test(el.tagName)){
4397 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4403 el.insertAdjacentHTML('BeforeBegin', html);
4404 return el.previousSibling;
4406 el.insertAdjacentHTML('AfterBegin', html);
4407 return el.firstChild;
4409 el.insertAdjacentHTML('BeforeEnd', html);
4410 return el.lastChild;
4412 el.insertAdjacentHTML('AfterEnd', html);
4413 return el.nextSibling;
4415 throw 'Illegal insertion point -> "' + where + '"';
4417 var range = el.ownerDocument.createRange();
4421 range.setStartBefore(el);
4422 frag = range.createContextualFragment(html);
4423 el.parentNode.insertBefore(frag, el);
4424 return el.previousSibling;
4427 range.setStartBefore(el.firstChild);
4428 frag = range.createContextualFragment(html);
4429 el.insertBefore(frag, el.firstChild);
4430 return el.firstChild;
4432 el.innerHTML = html;
4433 return el.firstChild;
4437 range.setStartAfter(el.lastChild);
4438 frag = range.createContextualFragment(html);
4439 el.appendChild(frag);
4440 return el.lastChild;
4442 el.innerHTML = html;
4443 return el.lastChild;
4446 range.setStartAfter(el);
4447 frag = range.createContextualFragment(html);
4448 el.parentNode.insertBefore(frag, el.nextSibling);
4449 return el.nextSibling;
4451 throw 'Illegal insertion point -> "' + where + '"';
4455 * Creates new Dom element(s) and inserts them before el
4456 * @param {String/HTMLElement/Element} el The context element
4457 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4458 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4459 * @return {HTMLElement/Roo.Element} The new node
4461 insertBefore : function(el, o, returnElement){
4462 return this.doInsert(el, o, returnElement, "beforeBegin");
4466 * Creates new Dom element(s) and inserts them after el
4467 * @param {String/HTMLElement/Element} el The context element
4468 * @param {Object} o The Dom object spec (and children)
4469 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4470 * @return {HTMLElement/Roo.Element} The new node
4472 insertAfter : function(el, o, returnElement){
4473 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4477 * Creates new Dom element(s) and inserts them as the first child of el
4478 * @param {String/HTMLElement/Element} el The context element
4479 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4480 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4481 * @return {HTMLElement/Roo.Element} The new node
4483 insertFirst : function(el, o, returnElement){
4484 return this.doInsert(el, o, returnElement, "afterBegin");
4488 doInsert : function(el, o, returnElement, pos, sibling){
4489 el = Roo.getDom(el);
4491 if(this.useDom || o.ns){
4492 newNode = createDom(o, null);
4493 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4495 var html = createHtml(o);
4496 newNode = this.insertHtml(pos, el, html);
4498 return returnElement ? Roo.get(newNode, true) : newNode;
4502 * Creates new Dom element(s) and appends them to el
4503 * @param {String/HTMLElement/Element} el The context element
4504 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506 * @return {HTMLElement/Roo.Element} The new node
4508 append : function(el, o, returnElement){
4509 el = Roo.getDom(el);
4511 if(this.useDom || o.ns){
4512 newNode = createDom(o, null);
4513 el.appendChild(newNode);
4515 var html = createHtml(o);
4516 newNode = this.insertHtml("beforeEnd", el, html);
4518 return returnElement ? Roo.get(newNode, true) : newNode;
4522 * Creates new Dom element(s) and overwrites the contents of el with them
4523 * @param {String/HTMLElement/Element} el The context element
4524 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4525 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4526 * @return {HTMLElement/Roo.Element} The new node
4528 overwrite : function(el, o, returnElement){
4529 el = Roo.getDom(el);
4532 while (el.childNodes.length) {
4533 el.removeChild(el.firstChild);
4537 el.innerHTML = createHtml(o);
4540 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4544 * Creates a new Roo.DomHelper.Template from the Dom object spec
4545 * @param {Object} o The Dom object spec (and children)
4546 * @return {Roo.DomHelper.Template} The new template
4548 createTemplate : function(o){
4549 var html = createHtml(o);
4550 return new Roo.Template(html);
4556 * Ext JS Library 1.1.1
4557 * Copyright(c) 2006-2007, Ext JS, LLC.
4559 * Originally Released Under LGPL - original licence link has changed is not relivant.
4562 * <script type="text/javascript">
4566 * @class Roo.Template
4567 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4568 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4571 var t = new Roo.Template({
4572 html : '<div name="{id}">' +
4573 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4575 myformat: function (value, allValues) {
4576 return 'XX' + value;
4579 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4581 * For more information see this blog post with examples:
4582 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4583 - Create Elements using DOM, HTML fragments and Templates</a>.
4585 * @param {Object} cfg - Configuration object.
4587 Roo.Template = function(cfg){
4589 if(cfg instanceof Array){
4591 }else if(arguments.length > 1){
4592 cfg = Array.prototype.join.call(arguments, "");
4596 if (typeof(cfg) == 'object') {
4607 Roo.Template.prototype = {
4610 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4611 * it should be fixed so that template is observable...
4615 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4619 * Returns an HTML fragment of this template with the specified values applied.
4620 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4621 * @return {String} The HTML fragment
4623 applyTemplate : function(values){
4627 return this.compiled(values);
4629 var useF = this.disableFormats !== true;
4630 var fm = Roo.util.Format, tpl = this;
4631 var fn = function(m, name, format, args){
4633 if(format.substr(0, 5) == "this."){
4634 return tpl.call(format.substr(5), values[name], values);
4637 // quoted values are required for strings in compiled templates,
4638 // but for non compiled we need to strip them
4639 // quoted reversed for jsmin
4640 var re = /^\s*['"](.*)["']\s*$/;
4641 args = args.split(',');
4642 for(var i = 0, len = args.length; i < len; i++){
4643 args[i] = args[i].replace(re, "$1");
4645 args = [values[name]].concat(args);
4647 args = [values[name]];
4649 return fm[format].apply(fm, args);
4652 return values[name] !== undefined ? values[name] : "";
4655 return this.html.replace(this.re, fn);
4673 this.loading = true;
4674 this.compiled = false;
4676 var cx = new Roo.data.Connection();
4680 success : function (response) {
4682 _t.html = response.responseText;
4686 failure : function(response) {
4687 Roo.log("Template failed to load from " + _t.url);
4694 * Sets the HTML used as the template and optionally compiles it.
4695 * @param {String} html
4696 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4697 * @return {Roo.Template} this
4699 set : function(html, compile){
4701 this.compiled = null;
4709 * True to disable format functions (defaults to false)
4712 disableFormats : false,
4715 * The regular expression used to match template variables
4719 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4722 * Compiles the template into an internal function, eliminating the RegEx overhead.
4723 * @return {Roo.Template} this
4725 compile : function(){
4726 var fm = Roo.util.Format;
4727 var useF = this.disableFormats !== true;
4728 var sep = Roo.isGecko ? "+" : ",";
4729 var fn = function(m, name, format, args){
4731 args = args ? ',' + args : "";
4732 if(format.substr(0, 5) != "this."){
4733 format = "fm." + format + '(';
4735 format = 'this.call("'+ format.substr(5) + '", ';
4739 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4741 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4744 // branched to use + in gecko and [].join() in others
4746 body = "this.compiled = function(values){ return '" +
4747 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4750 body = ["this.compiled = function(values){ return ['"];
4751 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4752 body.push("'].join('');};");
4753 body = body.join('');
4763 // private function used to call members
4764 call : function(fnName, value, allValues){
4765 return this[fnName](value, allValues);
4769 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4770 * @param {String/HTMLElement/Roo.Element} el The context element
4771 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4772 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4773 * @return {HTMLElement/Roo.Element} The new node or Element
4775 insertFirst: function(el, values, returnElement){
4776 return this.doInsert('afterBegin', el, values, returnElement);
4780 * Applies the supplied values to the template and inserts the new node(s) before el.
4781 * @param {String/HTMLElement/Roo.Element} el The context element
4782 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4783 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4784 * @return {HTMLElement/Roo.Element} The new node or Element
4786 insertBefore: function(el, values, returnElement){
4787 return this.doInsert('beforeBegin', el, values, returnElement);
4791 * Applies the supplied values to the template and inserts the new node(s) after el.
4792 * @param {String/HTMLElement/Roo.Element} el The context element
4793 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4794 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4795 * @return {HTMLElement/Roo.Element} The new node or Element
4797 insertAfter : function(el, values, returnElement){
4798 return this.doInsert('afterEnd', el, values, returnElement);
4802 * Applies the supplied values to the template and appends the new node(s) to el.
4803 * @param {String/HTMLElement/Roo.Element} el The context element
4804 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4805 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4806 * @return {HTMLElement/Roo.Element} The new node or Element
4808 append : function(el, values, returnElement){
4809 return this.doInsert('beforeEnd', el, values, returnElement);
4812 doInsert : function(where, el, values, returnEl){
4813 el = Roo.getDom(el);
4814 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4815 return returnEl ? Roo.get(newNode, true) : newNode;
4819 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4820 * @param {String/HTMLElement/Roo.Element} el The context element
4821 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4822 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823 * @return {HTMLElement/Roo.Element} The new node or Element
4825 overwrite : function(el, values, returnElement){
4826 el = Roo.getDom(el);
4827 el.innerHTML = this.applyTemplate(values);
4828 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4832 * Alias for {@link #applyTemplate}
4835 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4838 Roo.DomHelper.Template = Roo.Template;
4841 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4842 * @param {String/HTMLElement} el A DOM element or its id
4843 * @returns {Roo.Template} The created template
4846 Roo.Template.from = function(el){
4847 el = Roo.getDom(el);
4848 return new Roo.Template(el.value || el.innerHTML);
4851 * Ext JS Library 1.1.1
4852 * Copyright(c) 2006-2007, Ext JS, LLC.
4854 * Originally Released Under LGPL - original licence link has changed is not relivant.
4857 * <script type="text/javascript">
4862 * This is code is also distributed under MIT license for use
4863 * with jQuery and prototype JavaScript libraries.
4866 * @class Roo.DomQuery
4867 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4869 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4872 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4874 <h4>Element Selectors:</h4>
4876 <li> <b>*</b> any element</li>
4877 <li> <b>E</b> an element with the tag E</li>
4878 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4879 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4880 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4881 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4883 <h4>Attribute Selectors:</h4>
4884 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4886 <li> <b>E[foo]</b> has an attribute "foo"</li>
4887 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4888 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4889 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4890 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4891 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4892 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4894 <h4>Pseudo Classes:</h4>
4896 <li> <b>E:first-child</b> E is the first child of its parent</li>
4897 <li> <b>E:last-child</b> E is the last child of its parent</li>
4898 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4899 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4900 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4901 <li> <b>E:only-child</b> E is the only child of its parent</li>
4902 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4903 <li> <b>E:first</b> the first E in the resultset</li>
4904 <li> <b>E:last</b> the last E in the resultset</li>
4905 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4906 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4907 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4908 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4909 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4910 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4911 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4912 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4913 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4915 <h4>CSS Value Selectors:</h4>
4917 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4918 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4919 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4920 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4921 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4922 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4926 Roo.DomQuery = function(){
4927 var cache = {}, simpleCache = {}, valueCache = {};
4928 var nonSpace = /\S/;
4929 var trimRe = /^\s+|\s+$/g;
4930 var tplRe = /\{(\d+)\}/g;
4931 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4932 var tagTokenRe = /^(#)?([\w-\*]+)/;
4933 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4935 function child(p, index){
4937 var n = p.firstChild;
4939 if(n.nodeType == 1){
4950 while((n = n.nextSibling) && n.nodeType != 1);
4955 while((n = n.previousSibling) && n.nodeType != 1);
4959 function children(d){
4960 var n = d.firstChild, ni = -1;
4962 var nx = n.nextSibling;
4963 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4973 function byClassName(c, a, v){
4977 var r = [], ri = -1, cn;
4978 for(var i = 0, ci; ci = c[i]; i++){
4979 if((' '+ci.className+' ').indexOf(v) != -1){
4986 function attrValue(n, attr){
4987 if(!n.tagName && typeof n.length != "undefined"){
4996 if(attr == "class" || attr == "className"){
4999 return n.getAttribute(attr) || n[attr];
5003 function getNodes(ns, mode, tagName){
5004 var result = [], ri = -1, cs;
5008 tagName = tagName || "*";
5009 if(typeof ns.getElementsByTagName != "undefined"){
5013 for(var i = 0, ni; ni = ns[i]; i++){
5014 cs = ni.getElementsByTagName(tagName);
5015 for(var j = 0, ci; ci = cs[j]; j++){
5019 }else if(mode == "/" || mode == ">"){
5020 var utag = tagName.toUpperCase();
5021 for(var i = 0, ni, cn; ni = ns[i]; i++){
5022 cn = ni.children || ni.childNodes;
5023 for(var j = 0, cj; cj = cn[j]; j++){
5024 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5029 }else if(mode == "+"){
5030 var utag = tagName.toUpperCase();
5031 for(var i = 0, n; n = ns[i]; i++){
5032 while((n = n.nextSibling) && n.nodeType != 1);
5033 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5037 }else if(mode == "~"){
5038 for(var i = 0, n; n = ns[i]; i++){
5039 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5048 function concat(a, b){
5052 for(var i = 0, l = b.length; i < l; i++){
5058 function byTag(cs, tagName){
5059 if(cs.tagName || cs == document){
5065 var r = [], ri = -1;
5066 tagName = tagName.toLowerCase();
5067 for(var i = 0, ci; ci = cs[i]; i++){
5068 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5075 function byId(cs, attr, id){
5076 if(cs.tagName || cs == document){
5082 var r = [], ri = -1;
5083 for(var i = 0,ci; ci = cs[i]; i++){
5084 if(ci && ci.id == id){
5092 function byAttribute(cs, attr, value, op, custom){
5093 var r = [], ri = -1, st = custom=="{";
5094 var f = Roo.DomQuery.operators[op];
5095 for(var i = 0, ci; ci = cs[i]; i++){
5098 a = Roo.DomQuery.getStyle(ci, attr);
5100 else if(attr == "class" || attr == "className"){
5102 }else if(attr == "for"){
5104 }else if(attr == "href"){
5105 a = ci.getAttribute("href", 2);
5107 a = ci.getAttribute(attr);
5109 if((f && f(a, value)) || (!f && a)){
5116 function byPseudo(cs, name, value){
5117 return Roo.DomQuery.pseudos[name](cs, value);
5120 // This is for IE MSXML which does not support expandos.
5121 // IE runs the same speed using setAttribute, however FF slows way down
5122 // and Safari completely fails so they need to continue to use expandos.
5123 var isIE = window.ActiveXObject ? true : false;
5125 // this eval is stop the compressor from
5126 // renaming the variable to something shorter
5128 /** eval:var:batch */
5133 function nodupIEXml(cs){
5135 cs[0].setAttribute("_nodup", d);
5137 for(var i = 1, len = cs.length; i < len; i++){
5139 if(!c.getAttribute("_nodup") != d){
5140 c.setAttribute("_nodup", d);
5144 for(var i = 0, len = cs.length; i < len; i++){
5145 cs[i].removeAttribute("_nodup");
5154 var len = cs.length, c, i, r = cs, cj, ri = -1;
5155 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5158 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5159 return nodupIEXml(cs);
5163 for(i = 1; c = cs[i]; i++){
5168 for(var j = 0; j < i; j++){
5171 for(j = i+1; cj = cs[j]; j++){
5183 function quickDiffIEXml(c1, c2){
5185 for(var i = 0, len = c1.length; i < len; i++){
5186 c1[i].setAttribute("_qdiff", d);
5189 for(var i = 0, len = c2.length; i < len; i++){
5190 if(c2[i].getAttribute("_qdiff") != d){
5191 r[r.length] = c2[i];
5194 for(var i = 0, len = c1.length; i < len; i++){
5195 c1[i].removeAttribute("_qdiff");
5200 function quickDiff(c1, c2){
5201 var len1 = c1.length;
5205 if(isIE && c1[0].selectSingleNode){
5206 return quickDiffIEXml(c1, c2);
5209 for(var i = 0; i < len1; i++){
5213 for(var i = 0, len = c2.length; i < len; i++){
5214 if(c2[i]._qdiff != d){
5215 r[r.length] = c2[i];
5221 function quickId(ns, mode, root, id){
5223 var d = root.ownerDocument || root;
5224 return d.getElementById(id);
5226 ns = getNodes(ns, mode, "*");
5227 return byId(ns, null, id);
5231 getStyle : function(el, name){
5232 return Roo.fly(el).getStyle(name);
5235 * Compiles a selector/xpath query into a reusable function. The returned function
5236 * takes one parameter "root" (optional), which is the context node from where the query should start.
5237 * @param {String} selector The selector/xpath query
5238 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5239 * @return {Function}
5241 compile : function(path, type){
5242 type = type || "select";
5244 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5245 var q = path, mode, lq;
5246 var tk = Roo.DomQuery.matchers;
5247 var tklen = tk.length;
5250 // accept leading mode switch
5251 var lmode = q.match(modeRe);
5252 if(lmode && lmode[1]){
5253 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5254 q = q.replace(lmode[1], "");
5256 // strip leading slashes
5257 while(path.substr(0, 1)=="/"){
5258 path = path.substr(1);
5261 while(q && lq != q){
5263 var tm = q.match(tagTokenRe);
5264 if(type == "select"){
5267 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5269 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5271 q = q.replace(tm[0], "");
5272 }else if(q.substr(0, 1) != '@'){
5273 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5278 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5280 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5282 q = q.replace(tm[0], "");
5285 while(!(mm = q.match(modeRe))){
5286 var matched = false;
5287 for(var j = 0; j < tklen; j++){
5289 var m = q.match(t.re);
5291 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5294 q = q.replace(m[0], "");
5299 // prevent infinite loop on bad selector
5301 throw 'Error parsing selector, parsing failed at "' + q + '"';
5305 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5306 q = q.replace(mm[1], "");
5309 fn[fn.length] = "return nodup(n);\n}";
5312 * list of variables that need from compression as they are used by eval.
5322 * eval:var:byClassName
5324 * eval:var:byAttribute
5325 * eval:var:attrValue
5333 * Selects a group of elements.
5334 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5335 * @param {Node} root (optional) The start of the query (defaults to document).
5338 select : function(path, root, type){
5339 if(!root || root == document){
5342 if(typeof root == "string"){
5343 root = document.getElementById(root);
5345 var paths = path.split(",");
5347 for(var i = 0, len = paths.length; i < len; i++){
5348 var p = paths[i].replace(trimRe, "");
5350 cache[p] = Roo.DomQuery.compile(p);
5352 throw p + " is not a valid selector";
5355 var result = cache[p](root);
5356 if(result && result != document){
5357 results = results.concat(result);
5360 if(paths.length > 1){
5361 return nodup(results);
5367 * Selects a single element.
5368 * @param {String} selector The selector/xpath query
5369 * @param {Node} root (optional) The start of the query (defaults to document).
5372 selectNode : function(path, root){
5373 return Roo.DomQuery.select(path, root)[0];
5377 * Selects the value of a node, optionally replacing null with the defaultValue.
5378 * @param {String} selector The selector/xpath query
5379 * @param {Node} root (optional) The start of the query (defaults to document).
5380 * @param {String} defaultValue
5382 selectValue : function(path, root, defaultValue){
5383 path = path.replace(trimRe, "");
5384 if(!valueCache[path]){
5385 valueCache[path] = Roo.DomQuery.compile(path, "select");
5387 var n = valueCache[path](root);
5388 n = n[0] ? n[0] : n;
5389 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5390 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5394 * Selects the value of a node, parsing integers and floats.
5395 * @param {String} selector The selector/xpath query
5396 * @param {Node} root (optional) The start of the query (defaults to document).
5397 * @param {Number} defaultValue
5400 selectNumber : function(path, root, defaultValue){
5401 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5402 return parseFloat(v);
5406 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5407 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5408 * @param {String} selector The simple selector to test
5411 is : function(el, ss){
5412 if(typeof el == "string"){
5413 el = document.getElementById(el);
5415 var isArray = (el instanceof Array);
5416 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5417 return isArray ? (result.length == el.length) : (result.length > 0);
5421 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5422 * @param {Array} el An array of elements to filter
5423 * @param {String} selector The simple selector to test
5424 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5425 * the selector instead of the ones that match
5428 filter : function(els, ss, nonMatches){
5429 ss = ss.replace(trimRe, "");
5430 if(!simpleCache[ss]){
5431 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5433 var result = simpleCache[ss](els);
5434 return nonMatches ? quickDiff(result, els) : result;
5438 * Collection of matching regular expressions and code snippets.
5442 select: 'n = byClassName(n, null, " {1} ");'
5444 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5445 select: 'n = byPseudo(n, "{1}", "{2}");'
5447 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5448 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5451 select: 'n = byId(n, null, "{1}");'
5454 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5459 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5460 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5463 "=" : function(a, v){
5466 "!=" : function(a, v){
5469 "^=" : function(a, v){
5470 return a && a.substr(0, v.length) == v;
5472 "$=" : function(a, v){
5473 return a && a.substr(a.length-v.length) == v;
5475 "*=" : function(a, v){
5476 return a && a.indexOf(v) !== -1;
5478 "%=" : function(a, v){
5479 return (a % v) == 0;
5481 "|=" : function(a, v){
5482 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5484 "~=" : function(a, v){
5485 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5490 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5491 * and the argument (if any) supplied in the selector.
5494 "first-child" : function(c){
5495 var r = [], ri = -1, n;
5496 for(var i = 0, ci; ci = n = c[i]; i++){
5497 while((n = n.previousSibling) && n.nodeType != 1);
5505 "last-child" : function(c){
5506 var r = [], ri = -1, n;
5507 for(var i = 0, ci; ci = n = c[i]; i++){
5508 while((n = n.nextSibling) && n.nodeType != 1);
5516 "nth-child" : function(c, a) {
5517 var r = [], ri = -1;
5518 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5519 var f = (m[1] || 1) - 0, l = m[2] - 0;
5520 for(var i = 0, n; n = c[i]; i++){
5521 var pn = n.parentNode;
5522 if (batch != pn._batch) {
5524 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5525 if(cn.nodeType == 1){
5532 if (l == 0 || n.nodeIndex == l){
5535 } else if ((n.nodeIndex + l) % f == 0){
5543 "only-child" : function(c){
5544 var r = [], ri = -1;;
5545 for(var i = 0, ci; ci = c[i]; i++){
5546 if(!prev(ci) && !next(ci)){
5553 "empty" : function(c){
5554 var r = [], ri = -1;
5555 for(var i = 0, ci; ci = c[i]; i++){
5556 var cns = ci.childNodes, j = 0, cn, empty = true;
5559 if(cn.nodeType == 1 || cn.nodeType == 3){
5571 "contains" : function(c, v){
5572 var r = [], ri = -1;
5573 for(var i = 0, ci; ci = c[i]; i++){
5574 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5581 "nodeValue" : function(c, v){
5582 var r = [], ri = -1;
5583 for(var i = 0, ci; ci = c[i]; i++){
5584 if(ci.firstChild && ci.firstChild.nodeValue == v){
5591 "checked" : function(c){
5592 var r = [], ri = -1;
5593 for(var i = 0, ci; ci = c[i]; i++){
5594 if(ci.checked == true){
5601 "not" : function(c, ss){
5602 return Roo.DomQuery.filter(c, ss, true);
5605 "odd" : function(c){
5606 return this["nth-child"](c, "odd");
5609 "even" : function(c){
5610 return this["nth-child"](c, "even");
5613 "nth" : function(c, a){
5614 return c[a-1] || [];
5617 "first" : function(c){
5621 "last" : function(c){
5622 return c[c.length-1] || [];
5625 "has" : function(c, ss){
5626 var s = Roo.DomQuery.select;
5627 var r = [], ri = -1;
5628 for(var i = 0, ci; ci = c[i]; i++){
5629 if(s(ss, ci).length > 0){
5636 "next" : function(c, ss){
5637 var is = Roo.DomQuery.is;
5638 var r = [], ri = -1;
5639 for(var i = 0, ci; ci = c[i]; i++){
5648 "prev" : function(c, ss){
5649 var is = Roo.DomQuery.is;
5650 var r = [], ri = -1;
5651 for(var i = 0, ci; ci = c[i]; i++){
5664 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5665 * @param {String} path The selector/xpath query
5666 * @param {Node} root (optional) The start of the query (defaults to document).
5671 Roo.query = Roo.DomQuery.select;
5674 * Ext JS Library 1.1.1
5675 * Copyright(c) 2006-2007, Ext JS, LLC.
5677 * Originally Released Under LGPL - original licence link has changed is not relivant.
5680 * <script type="text/javascript">
5684 * @class Roo.util.Observable
5685 * Base class that provides a common interface for publishing events. Subclasses are expected to
5686 * to have a property "events" with all the events defined.<br>
5689 Employee = function(name){
5696 Roo.extend(Employee, Roo.util.Observable);
5698 * @param {Object} config properties to use (incuding events / listeners)
5701 Roo.util.Observable = function(cfg){
5704 this.addEvents(cfg.events || {});
5706 delete cfg.events; // make sure
5709 Roo.apply(this, cfg);
5712 this.on(this.listeners);
5713 delete this.listeners;
5716 Roo.util.Observable.prototype = {
5718 * @cfg {Object} listeners list of events and functions to call for this object,
5722 'click' : function(e) {
5732 * Fires the specified event with the passed parameters (minus the event name).
5733 * @param {String} eventName
5734 * @param {Object...} args Variable number of parameters are passed to handlers
5735 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5737 fireEvent : function(){
5738 var ce = this.events[arguments[0].toLowerCase()];
5739 if(typeof ce == "object"){
5740 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5747 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5750 * Appends an event handler to this component
5751 * @param {String} eventName The type of event to listen for
5752 * @param {Function} handler The method the event invokes
5753 * @param {Object} scope (optional) The scope in which to execute the handler
5754 * function. The handler function's "this" context.
5755 * @param {Object} options (optional) An object containing handler configuration
5756 * properties. This may contain any of the following properties:<ul>
5757 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5758 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5759 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5760 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5761 * by the specified number of milliseconds. If the event fires again within that time, the original
5762 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5765 * <b>Combining Options</b><br>
5766 * Using the options argument, it is possible to combine different types of listeners:<br>
5768 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5770 el.on('click', this.onClick, this, {
5777 * <b>Attaching multiple handlers in 1 call</b><br>
5778 * The method also allows for a single argument to be passed which is a config object containing properties
5779 * which specify multiple handlers.
5788 fn: this.onMouseOver,
5792 fn: this.onMouseOut,
5798 * Or a shorthand syntax which passes the same scope object to all handlers:
5801 'click': this.onClick,
5802 'mouseover': this.onMouseOver,
5803 'mouseout': this.onMouseOut,
5808 addListener : function(eventName, fn, scope, o){
5809 if(typeof eventName == "object"){
5812 if(this.filterOptRe.test(e)){
5815 if(typeof o[e] == "function"){
5817 this.addListener(e, o[e], o.scope, o);
5819 // individual options
5820 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5825 o = (!o || typeof o == "boolean") ? {} : o;
5826 eventName = eventName.toLowerCase();
5827 var ce = this.events[eventName] || true;
5828 if(typeof ce == "boolean"){
5829 ce = new Roo.util.Event(this, eventName);
5830 this.events[eventName] = ce;
5832 ce.addListener(fn, scope, o);
5836 * Removes a listener
5837 * @param {String} eventName The type of event to listen for
5838 * @param {Function} handler The handler to remove
5839 * @param {Object} scope (optional) The scope (this object) for the handler
5841 removeListener : function(eventName, fn, scope){
5842 var ce = this.events[eventName.toLowerCase()];
5843 if(typeof ce == "object"){
5844 ce.removeListener(fn, scope);
5849 * Removes all listeners for this object
5851 purgeListeners : function(){
5852 for(var evt in this.events){
5853 if(typeof this.events[evt] == "object"){
5854 this.events[evt].clearListeners();
5859 relayEvents : function(o, events){
5860 var createHandler = function(ename){
5862 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5865 for(var i = 0, len = events.length; i < len; i++){
5866 var ename = events[i];
5867 if(!this.events[ename]){ this.events[ename] = true; };
5868 o.on(ename, createHandler(ename), this);
5873 * Used to define events on this Observable
5874 * @param {Object} object The object with the events defined
5876 addEvents : function(o){
5880 Roo.applyIf(this.events, o);
5884 * Checks to see if this object has any listeners for a specified event
5885 * @param {String} eventName The name of the event to check for
5886 * @return {Boolean} True if the event is being listened for, else false
5888 hasListener : function(eventName){
5889 var e = this.events[eventName];
5890 return typeof e == "object" && e.listeners.length > 0;
5894 * Appends an event handler to this element (shorthand for addListener)
5895 * @param {String} eventName The type of event to listen for
5896 * @param {Function} handler The method the event invokes
5897 * @param {Object} scope (optional) The scope in which to execute the handler
5898 * function. The handler function's "this" context.
5899 * @param {Object} options (optional)
5902 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5904 * Removes a listener (shorthand for removeListener)
5905 * @param {String} eventName The type of event to listen for
5906 * @param {Function} handler The handler to remove
5907 * @param {Object} scope (optional) The scope (this object) for the handler
5910 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5913 * Starts capture on the specified Observable. All events will be passed
5914 * to the supplied function with the event name + standard signature of the event
5915 * <b>before</b> the event is fired. If the supplied function returns false,
5916 * the event will not fire.
5917 * @param {Observable} o The Observable to capture
5918 * @param {Function} fn The function to call
5919 * @param {Object} scope (optional) The scope (this object) for the fn
5922 Roo.util.Observable.capture = function(o, fn, scope){
5923 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5927 * Removes <b>all</b> added captures from the Observable.
5928 * @param {Observable} o The Observable to release
5931 Roo.util.Observable.releaseCapture = function(o){
5932 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5937 var createBuffered = function(h, o, scope){
5938 var task = new Roo.util.DelayedTask();
5940 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5944 var createSingle = function(h, e, fn, scope){
5946 e.removeListener(fn, scope);
5947 return h.apply(scope, arguments);
5951 var createDelayed = function(h, o, scope){
5953 var args = Array.prototype.slice.call(arguments, 0);
5954 setTimeout(function(){
5955 h.apply(scope, args);
5960 Roo.util.Event = function(obj, name){
5963 this.listeners = [];
5966 Roo.util.Event.prototype = {
5967 addListener : function(fn, scope, options){
5968 var o = options || {};
5969 scope = scope || this.obj;
5970 if(!this.isListening(fn, scope)){
5971 var l = {fn: fn, scope: scope, options: o};
5974 h = createDelayed(h, o, scope);
5977 h = createSingle(h, this, fn, scope);
5980 h = createBuffered(h, o, scope);
5983 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5984 this.listeners.push(l);
5986 this.listeners = this.listeners.slice(0);
5987 this.listeners.push(l);
5992 findListener : function(fn, scope){
5993 scope = scope || this.obj;
5994 var ls = this.listeners;
5995 for(var i = 0, len = ls.length; i < len; i++){
5997 if(l.fn == fn && l.scope == scope){
6004 isListening : function(fn, scope){
6005 return this.findListener(fn, scope) != -1;
6008 removeListener : function(fn, scope){
6010 if((index = this.findListener(fn, scope)) != -1){
6012 this.listeners.splice(index, 1);
6014 this.listeners = this.listeners.slice(0);
6015 this.listeners.splice(index, 1);
6022 clearListeners : function(){
6023 this.listeners = [];
6027 var ls = this.listeners, scope, len = ls.length;
6030 var args = Array.prototype.slice.call(arguments, 0);
6031 for(var i = 0; i < len; i++){
6033 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6034 this.firing = false;
6038 this.firing = false;
6045 * Ext JS Library 1.1.1
6046 * Copyright(c) 2006-2007, Ext JS, LLC.
6048 * Originally Released Under LGPL - original licence link has changed is not relivant.
6051 * <script type="text/javascript">
6055 * @class Roo.EventManager
6056 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6057 * several useful events directly.
6058 * See {@link Roo.EventObject} for more details on normalized event objects.
6061 Roo.EventManager = function(){
6062 var docReadyEvent, docReadyProcId, docReadyState = false;
6063 var resizeEvent, resizeTask, textEvent, textSize;
6064 var E = Roo.lib.Event;
6065 var D = Roo.lib.Dom;
6070 var fireDocReady = function(){
6072 docReadyState = true;
6075 clearInterval(docReadyProcId);
6077 if(Roo.isGecko || Roo.isOpera) {
6078 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6081 var defer = document.getElementById("ie-deferred-loader");
6083 defer.onreadystatechange = null;
6084 defer.parentNode.removeChild(defer);
6088 docReadyEvent.fire();
6089 docReadyEvent.clearListeners();
6094 var initDocReady = function(){
6095 docReadyEvent = new Roo.util.Event();
6096 if(Roo.isGecko || Roo.isOpera) {
6097 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6099 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6100 var defer = document.getElementById("ie-deferred-loader");
6101 defer.onreadystatechange = function(){
6102 if(this.readyState == "complete"){
6106 }else if(Roo.isSafari){
6107 docReadyProcId = setInterval(function(){
6108 var rs = document.readyState;
6109 if(rs == "complete") {
6114 // no matter what, make sure it fires on load
6115 E.on(window, "load", fireDocReady);
6118 var createBuffered = function(h, o){
6119 var task = new Roo.util.DelayedTask(h);
6121 // create new event object impl so new events don't wipe out properties
6122 e = new Roo.EventObjectImpl(e);
6123 task.delay(o.buffer, h, null, [e]);
6127 var createSingle = function(h, el, ename, fn){
6129 Roo.EventManager.removeListener(el, ename, fn);
6134 var createDelayed = function(h, o){
6136 // create new event object impl so new events don't wipe out properties
6137 e = new Roo.EventObjectImpl(e);
6138 setTimeout(function(){
6143 var transitionEndVal = false;
6145 var transitionEnd = function()
6147 if (transitionEndVal) {
6148 return transitionEndVal;
6150 var el = document.createElement('div');
6152 var transEndEventNames = {
6153 WebkitTransition : 'webkitTransitionEnd',
6154 MozTransition : 'transitionend',
6155 OTransition : 'oTransitionEnd otransitionend',
6156 transition : 'transitionend'
6159 for (var name in transEndEventNames) {
6160 if (el.style[name] !== undefined) {
6161 transitionEndVal = transEndEventNames[name];
6162 return transitionEndVal ;
6168 var listen = function(element, ename, opt, fn, scope){
6169 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6170 fn = fn || o.fn; scope = scope || o.scope;
6171 var el = Roo.getDom(element);
6175 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6178 if (ename == 'transitionend') {
6179 ename = transitionEnd();
6181 var h = function(e){
6182 e = Roo.EventObject.setEvent(e);
6185 t = e.getTarget(o.delegate, el);
6192 if(o.stopEvent === true){
6195 if(o.preventDefault === true){
6198 if(o.stopPropagation === true){
6199 e.stopPropagation();
6202 if(o.normalized === false){
6206 fn.call(scope || el, e, t, o);
6209 h = createDelayed(h, o);
6212 h = createSingle(h, el, ename, fn);
6215 h = createBuffered(h, o);
6217 fn._handlers = fn._handlers || [];
6220 fn._handlers.push([Roo.id(el), ename, h]);
6225 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6226 el.addEventListener("DOMMouseScroll", h, false);
6227 E.on(window, 'unload', function(){
6228 el.removeEventListener("DOMMouseScroll", h, false);
6231 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6232 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6237 var stopListening = function(el, ename, fn){
6238 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6240 for(var i = 0, len = hds.length; i < len; i++){
6242 if(h[0] == id && h[1] == ename){
6249 E.un(el, ename, hd);
6250 el = Roo.getDom(el);
6251 if(ename == "mousewheel" && el.addEventListener){
6252 el.removeEventListener("DOMMouseScroll", hd, false);
6254 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6255 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6259 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6266 * @scope Roo.EventManager
6271 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6272 * object with a Roo.EventObject
6273 * @param {Function} fn The method the event invokes
6274 * @param {Object} scope An object that becomes the scope of the handler
6275 * @param {boolean} override If true, the obj passed in becomes
6276 * the execution scope of the listener
6277 * @return {Function} The wrapped function
6280 wrap : function(fn, scope, override){
6282 Roo.EventObject.setEvent(e);
6283 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6288 * Appends an event handler to an element (shorthand for addListener)
6289 * @param {String/HTMLElement} element The html element or id to assign the
6290 * @param {String} eventName The type of event to listen for
6291 * @param {Function} handler The method the event invokes
6292 * @param {Object} scope (optional) The scope in which to execute the handler
6293 * function. The handler function's "this" context.
6294 * @param {Object} options (optional) An object containing handler configuration
6295 * properties. This may contain any of the following properties:<ul>
6296 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6297 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6298 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6299 * <li>preventDefault {Boolean} True to prevent the default action</li>
6300 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6301 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6302 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6303 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6304 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6305 * by the specified number of milliseconds. If the event fires again within that time, the original
6306 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6309 * <b>Combining Options</b><br>
6310 * Using the options argument, it is possible to combine different types of listeners:<br>
6312 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6314 el.on('click', this.onClick, this, {
6321 * <b>Attaching multiple handlers in 1 call</b><br>
6322 * The method also allows for a single argument to be passed which is a config object containing properties
6323 * which specify multiple handlers.
6333 fn: this.onMouseOver
6342 * Or a shorthand syntax:<br>
6345 'click' : this.onClick,
6346 'mouseover' : this.onMouseOver,
6347 'mouseout' : this.onMouseOut
6351 addListener : function(element, eventName, fn, scope, options){
6352 if(typeof eventName == "object"){
6358 if(typeof o[e] == "function"){
6360 listen(element, e, o, o[e], o.scope);
6362 // individual options
6363 listen(element, e, o[e]);
6368 return listen(element, eventName, options, fn, scope);
6372 * Removes an event handler
6374 * @param {String/HTMLElement} element The id or html element to remove the
6376 * @param {String} eventName The type of event
6377 * @param {Function} fn
6378 * @return {Boolean} True if a listener was actually removed
6380 removeListener : function(element, eventName, fn){
6381 return stopListening(element, eventName, fn);
6385 * Fires when the document is ready (before onload and before images are loaded). Can be
6386 * accessed shorthanded Roo.onReady().
6387 * @param {Function} fn The method the event invokes
6388 * @param {Object} scope An object that becomes the scope of the handler
6389 * @param {boolean} options
6391 onDocumentReady : function(fn, scope, options){
6392 if(docReadyState){ // if it already fired
6393 docReadyEvent.addListener(fn, scope, options);
6394 docReadyEvent.fire();
6395 docReadyEvent.clearListeners();
6401 docReadyEvent.addListener(fn, scope, options);
6405 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6406 * @param {Function} fn The method the event invokes
6407 * @param {Object} scope An object that becomes the scope of the handler
6408 * @param {boolean} options
6410 onWindowResize : function(fn, scope, options){
6412 resizeEvent = new Roo.util.Event();
6413 resizeTask = new Roo.util.DelayedTask(function(){
6414 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6416 E.on(window, "resize", function(){
6418 resizeTask.delay(50);
6420 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6424 resizeEvent.addListener(fn, scope, options);
6428 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6429 * @param {Function} fn The method the event invokes
6430 * @param {Object} scope An object that becomes the scope of the handler
6431 * @param {boolean} options
6433 onTextResize : function(fn, scope, options){
6435 textEvent = new Roo.util.Event();
6436 var textEl = new Roo.Element(document.createElement('div'));
6437 textEl.dom.className = 'x-text-resize';
6438 textEl.dom.innerHTML = 'X';
6439 textEl.appendTo(document.body);
6440 textSize = textEl.dom.offsetHeight;
6441 setInterval(function(){
6442 if(textEl.dom.offsetHeight != textSize){
6443 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6445 }, this.textResizeInterval);
6447 textEvent.addListener(fn, scope, options);
6451 * Removes the passed window resize listener.
6452 * @param {Function} fn The method the event invokes
6453 * @param {Object} scope The scope of handler
6455 removeResizeListener : function(fn, scope){
6457 resizeEvent.removeListener(fn, scope);
6462 fireResize : function(){
6464 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6468 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6472 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6474 textResizeInterval : 50
6479 * @scopeAlias pub=Roo.EventManager
6483 * Appends an event handler to an element (shorthand for addListener)
6484 * @param {String/HTMLElement} element The html element or id to assign the
6485 * @param {String} eventName The type of event to listen for
6486 * @param {Function} handler The method the event invokes
6487 * @param {Object} scope (optional) The scope in which to execute the handler
6488 * function. The handler function's "this" context.
6489 * @param {Object} options (optional) An object containing handler configuration
6490 * properties. This may contain any of the following properties:<ul>
6491 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6492 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6493 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6494 * <li>preventDefault {Boolean} True to prevent the default action</li>
6495 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6496 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6497 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6498 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6499 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6500 * by the specified number of milliseconds. If the event fires again within that time, the original
6501 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6504 * <b>Combining Options</b><br>
6505 * Using the options argument, it is possible to combine different types of listeners:<br>
6507 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6509 el.on('click', this.onClick, this, {
6516 * <b>Attaching multiple handlers in 1 call</b><br>
6517 * The method also allows for a single argument to be passed which is a config object containing properties
6518 * which specify multiple handlers.
6528 fn: this.onMouseOver
6537 * Or a shorthand syntax:<br>
6540 'click' : this.onClick,
6541 'mouseover' : this.onMouseOver,
6542 'mouseout' : this.onMouseOut
6546 pub.on = pub.addListener;
6547 pub.un = pub.removeListener;
6549 pub.stoppedMouseDownEvent = new Roo.util.Event();
6553 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6554 * @param {Function} fn The method the event invokes
6555 * @param {Object} scope An object that becomes the scope of the handler
6556 * @param {boolean} override If true, the obj passed in becomes
6557 * the execution scope of the listener
6561 Roo.onReady = Roo.EventManager.onDocumentReady;
6563 Roo.onReady(function(){
6564 var bd = Roo.get(document.body);
6569 : Roo.isGecko ? "roo-gecko"
6570 : Roo.isOpera ? "roo-opera"
6571 : Roo.isSafari ? "roo-safari" : ""];
6574 cls.push("roo-mac");
6577 cls.push("roo-linux");
6579 if(Roo.isBorderBox){
6580 cls.push('roo-border-box');
6582 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6583 var p = bd.dom.parentNode;
6585 p.className += ' roo-strict';
6588 bd.addClass(cls.join(' '));
6592 * @class Roo.EventObject
6593 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6594 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6597 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6599 var target = e.getTarget();
6602 var myDiv = Roo.get("myDiv");
6603 myDiv.on("click", handleClick);
6605 Roo.EventManager.on("myDiv", 'click', handleClick);
6606 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6610 Roo.EventObject = function(){
6612 var E = Roo.lib.Event;
6614 // safari keypress events for special keys return bad keycodes
6617 63235 : 39, // right
6620 63276 : 33, // page up
6621 63277 : 34, // page down
6622 63272 : 46, // delete
6627 // normalize button clicks
6628 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6629 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6631 Roo.EventObjectImpl = function(e){
6633 this.setEvent(e.browserEvent || e);
6636 Roo.EventObjectImpl.prototype = {
6638 * Used to fix doc tools.
6639 * @scope Roo.EventObject.prototype
6645 /** The normal browser event */
6646 browserEvent : null,
6647 /** The button pressed in a mouse event */
6649 /** True if the shift key was down during the event */
6651 /** True if the control key was down during the event */
6653 /** True if the alt key was down during the event */
6712 setEvent : function(e){
6713 if(e == this || (e && e.browserEvent)){ // already wrapped
6716 this.browserEvent = e;
6718 // normalize buttons
6719 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6720 if(e.type == 'click' && this.button == -1){
6724 this.shiftKey = e.shiftKey;
6725 // mac metaKey behaves like ctrlKey
6726 this.ctrlKey = e.ctrlKey || e.metaKey;
6727 this.altKey = e.altKey;
6728 // in getKey these will be normalized for the mac
6729 this.keyCode = e.keyCode;
6730 // keyup warnings on firefox.
6731 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6732 // cache the target for the delayed and or buffered events
6733 this.target = E.getTarget(e);
6735 this.xy = E.getXY(e);
6738 this.shiftKey = false;
6739 this.ctrlKey = false;
6740 this.altKey = false;
6750 * Stop the event (preventDefault and stopPropagation)
6752 stopEvent : function(){
6753 if(this.browserEvent){
6754 if(this.browserEvent.type == 'mousedown'){
6755 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6757 E.stopEvent(this.browserEvent);
6762 * Prevents the browsers default handling of the event.
6764 preventDefault : function(){
6765 if(this.browserEvent){
6766 E.preventDefault(this.browserEvent);
6771 isNavKeyPress : function(){
6772 var k = this.keyCode;
6773 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6774 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6777 isSpecialKey : function(){
6778 var k = this.keyCode;
6779 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6780 (k == 16) || (k == 17) ||
6781 (k >= 18 && k <= 20) ||
6782 (k >= 33 && k <= 35) ||
6783 (k >= 36 && k <= 39) ||
6784 (k >= 44 && k <= 45);
6787 * Cancels bubbling of the event.
6789 stopPropagation : function(){
6790 if(this.browserEvent){
6791 if(this.type == 'mousedown'){
6792 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6794 E.stopPropagation(this.browserEvent);
6799 * Gets the key code for the event.
6802 getCharCode : function(){
6803 return this.charCode || this.keyCode;
6807 * Returns a normalized keyCode for the event.
6808 * @return {Number} The key code
6810 getKey : function(){
6811 var k = this.keyCode || this.charCode;
6812 return Roo.isSafari ? (safariKeys[k] || k) : k;
6816 * Gets the x coordinate of the event.
6819 getPageX : function(){
6824 * Gets the y coordinate of the event.
6827 getPageY : function(){
6832 * Gets the time of the event.
6835 getTime : function(){
6836 if(this.browserEvent){
6837 return E.getTime(this.browserEvent);
6843 * Gets the page coordinates of the event.
6844 * @return {Array} The xy values like [x, y]
6851 * Gets the target for the event.
6852 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6853 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6854 search as a number or element (defaults to 10 || document.body)
6855 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6856 * @return {HTMLelement}
6858 getTarget : function(selector, maxDepth, returnEl){
6859 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6862 * Gets the related target.
6863 * @return {HTMLElement}
6865 getRelatedTarget : function(){
6866 if(this.browserEvent){
6867 return E.getRelatedTarget(this.browserEvent);
6873 * Normalizes mouse wheel delta across browsers
6874 * @return {Number} The delta
6876 getWheelDelta : function(){
6877 var e = this.browserEvent;
6879 if(e.wheelDelta){ /* IE/Opera. */
6880 delta = e.wheelDelta/120;
6881 }else if(e.detail){ /* Mozilla case. */
6882 delta = -e.detail/3;
6888 * Returns true if the control, meta, shift or alt key was pressed during this event.
6891 hasModifier : function(){
6892 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6896 * Returns true if the target of this event equals el or is a child of el
6897 * @param {String/HTMLElement/Element} el
6898 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6901 within : function(el, related){
6902 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6903 return t && Roo.fly(el).contains(t);
6906 getPoint : function(){
6907 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6911 return new Roo.EventObjectImpl();
6916 * Ext JS Library 1.1.1
6917 * Copyright(c) 2006-2007, Ext JS, LLC.
6919 * Originally Released Under LGPL - original licence link has changed is not relivant.
6922 * <script type="text/javascript">
6926 // was in Composite Element!??!?!
6929 var D = Roo.lib.Dom;
6930 var E = Roo.lib.Event;
6931 var A = Roo.lib.Anim;
6933 // local style camelizing for speed
6935 var camelRe = /(-[a-z])/gi;
6936 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6937 var view = document.defaultView;
6940 * @class Roo.Element
6941 * Represents an Element in the DOM.<br><br>
6944 var el = Roo.get("my-div");
6947 var el = getEl("my-div");
6949 // or with a DOM element
6950 var el = Roo.get(myDivElement);
6952 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6953 * each call instead of constructing a new one.<br><br>
6954 * <b>Animations</b><br />
6955 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6956 * should either be a boolean (true) or an object literal with animation options. The animation options are:
6958 Option Default Description
6959 --------- -------- ---------------------------------------------
6960 duration .35 The duration of the animation in seconds
6961 easing easeOut The YUI easing method
6962 callback none A function to execute when the anim completes
6963 scope this The scope (this) of the callback function
6965 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6966 * manipulate the animation. Here's an example:
6968 var el = Roo.get("my-div");
6973 // default animation
6974 el.setWidth(100, true);
6976 // animation with some options set
6983 // using the "anim" property to get the Anim object
6989 el.setWidth(100, opt);
6991 if(opt.anim.isAnimated()){
6995 * <b> Composite (Collections of) Elements</b><br />
6996 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6997 * @constructor Create a new Element directly.
6998 * @param {String/HTMLElement} element
6999 * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class).
7001 Roo.Element = function(element, forceNew){
7002 var dom = typeof element == "string" ?
7003 document.getElementById(element) : element;
7004 if(!dom){ // invalid id/element
7008 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7009 return Roo.Element.cache[id];
7019 * The DOM element ID
7022 this.id = id || Roo.id(dom);
7025 var El = Roo.Element;
7029 * The element's default display mode (defaults to "")
7032 originalDisplay : "",
7036 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7041 * Sets the element's visibility mode. When setVisible() is called it
7042 * will use this to determine whether to set the visibility or the display property.
7043 * @param visMode Element.VISIBILITY or Element.DISPLAY
7044 * @return {Roo.Element} this
7046 setVisibilityMode : function(visMode){
7047 this.visibilityMode = visMode;
7051 * Convenience method for setVisibilityMode(Element.DISPLAY)
7052 * @param {String} display (optional) What to set display to when visible
7053 * @return {Roo.Element} this
7055 enableDisplayMode : function(display){
7056 this.setVisibilityMode(El.DISPLAY);
7057 if(typeof display != "undefined") this.originalDisplay = display;
7062 * Looks at this node and then at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7063 * @param {String} selector The simple selector to test
7064 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7065 search as a number or element (defaults to 10 || document.body)
7066 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7067 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7069 findParent : function(simpleSelector, maxDepth, returnEl){
7070 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7071 maxDepth = maxDepth || 50;
7072 if(typeof maxDepth != "number"){
7073 stopEl = Roo.getDom(maxDepth);
7076 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7077 if(dq.is(p, simpleSelector)){
7078 return returnEl ? Roo.get(p) : p;
7088 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7089 * @param {String} selector The simple selector to test
7090 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7091 search as a number or element (defaults to 10 || document.body)
7092 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7093 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7095 findParentNode : function(simpleSelector, maxDepth, returnEl){
7096 var p = Roo.fly(this.dom.parentNode, '_internal');
7097 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7101 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7102 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7103 * @param {String} selector The simple selector to test
7104 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7105 search as a number or element (defaults to 10 || document.body)
7106 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7108 up : function(simpleSelector, maxDepth){
7109 return this.findParentNode(simpleSelector, maxDepth, true);
7115 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7116 * @param {String} selector The simple selector to test
7117 * @return {Boolean} True if this element matches the selector, else false
7119 is : function(simpleSelector){
7120 return Roo.DomQuery.is(this.dom, simpleSelector);
7124 * Perform animation on this element.
7125 * @param {Object} args The YUI animation control args
7126 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7127 * @param {Function} onComplete (optional) Function to call when animation completes
7128 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7129 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7130 * @return {Roo.Element} this
7132 animate : function(args, duration, onComplete, easing, animType){
7133 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7138 * @private Internal animation call
7140 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7141 animType = animType || 'run';
7143 var anim = Roo.lib.Anim[animType](
7145 (opt.duration || defaultDur) || .35,
7146 (opt.easing || defaultEase) || 'easeOut',
7148 Roo.callback(cb, this);
7149 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7157 // private legacy anim prep
7158 preanim : function(a, i){
7159 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7163 * Removes worthless text nodes
7164 * @param {Boolean} forceReclean (optional) By default the element
7165 * keeps track if it has been cleaned already so
7166 * you can call this over and over. However, if you update the element and
7167 * need to force a reclean, you can pass true.
7169 clean : function(forceReclean){
7170 if(this.isCleaned && forceReclean !== true){
7174 var d = this.dom, n = d.firstChild, ni = -1;
7176 var nx = n.nextSibling;
7177 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7184 this.isCleaned = true;
7189 calcOffsetsTo : function(el){
7192 var restorePos = false;
7193 if(el.getStyle('position') == 'static'){
7194 el.position('relative');
7199 while(op && op != d && op.tagName != 'HTML'){
7202 op = op.offsetParent;
7205 el.position('static');
7211 * Scrolls this element into view within the passed container.
7212 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7213 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7214 * @return {Roo.Element} this
7216 scrollIntoView : function(container, hscroll){
7217 var c = Roo.getDom(container) || document.body;
7220 var o = this.calcOffsetsTo(c),
7223 b = t+el.offsetHeight,
7224 r = l+el.offsetWidth;
7226 var ch = c.clientHeight;
7227 var ct = parseInt(c.scrollTop, 10);
7228 var cl = parseInt(c.scrollLeft, 10);
7230 var cr = cl + c.clientWidth;
7238 if(hscroll !== false){
7242 c.scrollLeft = r-c.clientWidth;
7249 scrollChildIntoView : function(child, hscroll){
7250 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7254 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7255 * the new height may not be available immediately.
7256 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7257 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7258 * @param {Function} onComplete (optional) Function to call when animation completes
7259 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7260 * @return {Roo.Element} this
7262 autoHeight : function(animate, duration, onComplete, easing){
7263 var oldHeight = this.getHeight();
7265 this.setHeight(1); // force clipping
7266 setTimeout(function(){
7267 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7269 this.setHeight(height);
7271 if(typeof onComplete == "function"){
7275 this.setHeight(oldHeight); // restore original height
7276 this.setHeight(height, animate, duration, function(){
7278 if(typeof onComplete == "function") onComplete();
7279 }.createDelegate(this), easing);
7281 }.createDelegate(this), 0);
7286 * Returns true if this element is an ancestor of the passed element
7287 * @param {HTMLElement/String} el The element to check
7288 * @return {Boolean} True if this element is an ancestor of el, else false
7290 contains : function(el){
7291 if(!el){return false;}
7292 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7296 * Checks whether the element is currently visible using both visibility and display properties.
7297 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7298 * @return {Boolean} True if the element is currently visible, else false
7300 isVisible : function(deep) {
7301 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7302 if(deep !== true || !vis){
7305 var p = this.dom.parentNode;
7306 while(p && p.tagName.toLowerCase() != "body"){
7307 if(!Roo.fly(p, '_isVisible').isVisible()){
7316 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7317 * @param {String} selector The CSS selector
7318 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7319 * @return {CompositeElement/CompositeElementLite} The composite element
7321 select : function(selector, unique){
7322 return El.select(selector, unique, this.dom);
7326 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7327 * @param {String} selector The CSS selector
7328 * @return {Array} An array of the matched nodes
7330 query : function(selector, unique){
7331 return Roo.DomQuery.select(selector, this.dom);
7335 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7336 * @param {String} selector The CSS selector
7337 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7338 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7340 child : function(selector, returnDom){
7341 var n = Roo.DomQuery.selectNode(selector, this.dom);
7342 return returnDom ? n : Roo.get(n);
7346 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7347 * @param {String} selector The CSS selector
7348 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7349 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7351 down : function(selector, returnDom){
7352 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7353 return returnDom ? n : Roo.get(n);
7357 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7358 * @param {String} group The group the DD object is member of
7359 * @param {Object} config The DD config object
7360 * @param {Object} overrides An object containing methods to override/implement on the DD object
7361 * @return {Roo.dd.DD} The DD object
7363 initDD : function(group, config, overrides){
7364 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7365 return Roo.apply(dd, overrides);
7369 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7370 * @param {String} group The group the DDProxy object is member of
7371 * @param {Object} config The DDProxy config object
7372 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7373 * @return {Roo.dd.DDProxy} The DDProxy object
7375 initDDProxy : function(group, config, overrides){
7376 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7377 return Roo.apply(dd, overrides);
7381 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7382 * @param {String} group The group the DDTarget object is member of
7383 * @param {Object} config The DDTarget config object
7384 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7385 * @return {Roo.dd.DDTarget} The DDTarget object
7387 initDDTarget : function(group, config, overrides){
7388 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7389 return Roo.apply(dd, overrides);
7393 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7394 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7395 * @param {Boolean} visible Whether the element is visible
7396 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7397 * @return {Roo.Element} this
7399 setVisible : function(visible, animate){
7401 if(this.visibilityMode == El.DISPLAY){
7402 this.setDisplayed(visible);
7405 this.dom.style.visibility = visible ? "visible" : "hidden";
7408 // closure for composites
7410 var visMode = this.visibilityMode;
7412 this.setOpacity(.01);
7413 this.setVisible(true);
7415 this.anim({opacity: { to: (visible?1:0) }},
7416 this.preanim(arguments, 1),
7417 null, .35, 'easeIn', function(){
7419 if(visMode == El.DISPLAY){
7420 dom.style.display = "none";
7422 dom.style.visibility = "hidden";
7424 Roo.get(dom).setOpacity(1);
7432 * Returns true if display is not "none"
7435 isDisplayed : function() {
7436 return this.getStyle("display") != "none";
7440 * Toggles the element's visibility or display, depending on visibility mode.
7441 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7442 * @return {Roo.Element} this
7444 toggle : function(animate){
7445 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7450 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7451 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7452 * @return {Roo.Element} this
7454 setDisplayed : function(value) {
7455 if(typeof value == "boolean"){
7456 value = value ? this.originalDisplay : "none";
7458 this.setStyle("display", value);
7463 * Tries to focus the element. Any exceptions are caught and ignored.
7464 * @return {Roo.Element} this
7466 focus : function() {
7474 * Tries to blur the element. Any exceptions are caught and ignored.
7475 * @return {Roo.Element} this
7485 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7486 * @param {String/Array} className The CSS class to add, or an array of classes
7487 * @return {Roo.Element} this
7489 addClass : function(className){
7490 if(className instanceof Array){
7491 for(var i = 0, len = className.length; i < len; i++) {
7492 this.addClass(className[i]);
7495 if(className && !this.hasClass(className)){
7496 this.dom.className = this.dom.className + " " + className;
7503 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7504 * @param {String/Array} className The CSS class to add, or an array of classes
7505 * @return {Roo.Element} this
7507 radioClass : function(className){
7508 var siblings = this.dom.parentNode.childNodes;
7509 for(var i = 0; i < siblings.length; i++) {
7510 var s = siblings[i];
7511 if(s.nodeType == 1){
7512 Roo.get(s).removeClass(className);
7515 this.addClass(className);
7520 * Removes one or more CSS classes from the element.
7521 * @param {String/Array} className The CSS class to remove, or an array of classes
7522 * @return {Roo.Element} this
7524 removeClass : function(className){
7525 if(!className || !this.dom.className){
7528 if(className instanceof Array){
7529 for(var i = 0, len = className.length; i < len; i++) {
7530 this.removeClass(className[i]);
7533 if(this.hasClass(className)){
7534 var re = this.classReCache[className];
7536 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7537 this.classReCache[className] = re;
7539 this.dom.className =
7540 this.dom.className.replace(re, " ");
7550 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7551 * @param {String} className The CSS class to toggle
7552 * @return {Roo.Element} this
7554 toggleClass : function(className){
7555 if(this.hasClass(className)){
7556 this.removeClass(className);
7558 this.addClass(className);
7564 * Checks if the specified CSS class exists on this element's DOM node.
7565 * @param {String} className The CSS class to check for
7566 * @return {Boolean} True if the class exists, else false
7568 hasClass : function(className){
7569 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7573 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7574 * @param {String} oldClassName The CSS class to replace
7575 * @param {String} newClassName The replacement CSS class
7576 * @return {Roo.Element} this
7578 replaceClass : function(oldClassName, newClassName){
7579 this.removeClass(oldClassName);
7580 this.addClass(newClassName);
7585 * Returns an object with properties matching the styles requested.
7586 * For example, el.getStyles('color', 'font-size', 'width') might return
7587 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7588 * @param {String} style1 A style name
7589 * @param {String} style2 A style name
7590 * @param {String} etc.
7591 * @return {Object} The style object
7593 getStyles : function(){
7594 var a = arguments, len = a.length, r = {};
7595 for(var i = 0; i < len; i++){
7596 r[a[i]] = this.getStyle(a[i]);
7602 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7603 * @param {String} property The style property whose value is returned.
7604 * @return {String} The current value of the style property for this element.
7606 getStyle : function(){
7607 return view && view.getComputedStyle ?
7609 var el = this.dom, v, cs, camel;
7610 if(prop == 'float'){
7613 if(el.style && (v = el.style[prop])){
7616 if(cs = view.getComputedStyle(el, "")){
7617 if(!(camel = propCache[prop])){
7618 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7625 var el = this.dom, v, cs, camel;
7626 if(prop == 'opacity'){
7627 if(typeof el.style.filter == 'string'){
7628 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7630 var fv = parseFloat(m[1]);
7632 return fv ? fv / 100 : 0;
7637 }else if(prop == 'float'){
7638 prop = "styleFloat";
7640 if(!(camel = propCache[prop])){
7641 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7643 if(v = el.style[camel]){
7646 if(cs = el.currentStyle){
7654 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7655 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7656 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7657 * @return {Roo.Element} this
7659 setStyle : function(prop, value){
7660 if(typeof prop == "string"){
7662 if (prop == 'float') {
7663 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7668 if(!(camel = propCache[prop])){
7669 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7672 if(camel == 'opacity') {
7673 this.setOpacity(value);
7675 this.dom.style[camel] = value;
7678 for(var style in prop){
7679 if(typeof prop[style] != "function"){
7680 this.setStyle(style, prop[style]);
7688 * More flexible version of {@link #setStyle} for setting style properties.
7689 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7690 * a function which returns such a specification.
7691 * @return {Roo.Element} this
7693 applyStyles : function(style){
7694 Roo.DomHelper.applyStyles(this.dom, style);
7699 * Gets the current X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7700 * @return {Number} The X position of the element
7703 return D.getX(this.dom);
7707 * Gets the current Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7708 * @return {Number} The Y position of the element
7711 return D.getY(this.dom);
7715 * Gets the current position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7716 * @return {Array} The XY position of the element
7719 return D.getXY(this.dom);
7723 * Sets the X position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7724 * @param {Number} The X position of the element
7725 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7726 * @return {Roo.Element} this
7728 setX : function(x, animate){
7730 D.setX(this.dom, x);
7732 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7738 * Sets the Y position of the element based on page coordinates. Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7739 * @param {Number} The Y position of the element
7740 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741 * @return {Roo.Element} this
7743 setY : function(y, animate){
7745 D.setY(this.dom, y);
7747 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7753 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7754 * @param {String} left The left CSS property value
7755 * @return {Roo.Element} this
7757 setLeft : function(left){
7758 this.setStyle("left", this.addUnits(left));
7763 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7764 * @param {String} top The top CSS property value
7765 * @return {Roo.Element} this
7767 setTop : function(top){
7768 this.setStyle("top", this.addUnits(top));
7773 * Sets the element's CSS right style.
7774 * @param {String} right The right CSS property value
7775 * @return {Roo.Element} this
7777 setRight : function(right){
7778 this.setStyle("right", this.addUnits(right));
7783 * Sets the element's CSS bottom style.
7784 * @param {String} bottom The bottom CSS property value
7785 * @return {Roo.Element} this
7787 setBottom : function(bottom){
7788 this.setStyle("bottom", this.addUnits(bottom));
7793 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7794 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7795 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7796 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7797 * @return {Roo.Element} this
7799 setXY : function(pos, animate){
7801 D.setXY(this.dom, pos);
7803 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7809 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7810 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7811 * @param {Number} x X value for new position (coordinates are page-based)
7812 * @param {Number} y Y value for new position (coordinates are page-based)
7813 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7814 * @return {Roo.Element} this
7816 setLocation : function(x, y, animate){
7817 this.setXY([x, y], this.preanim(arguments, 2));
7822 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7823 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7824 * @param {Number} x X value for new position (coordinates are page-based)
7825 * @param {Number} y Y value for new position (coordinates are page-based)
7826 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7827 * @return {Roo.Element} this
7829 moveTo : function(x, y, animate){
7830 this.setXY([x, y], this.preanim(arguments, 2));
7835 * Returns the region of the given element.
7836 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7837 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7839 getRegion : function(){
7840 return D.getRegion(this.dom);
7844 * Returns the offset height of the element
7845 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7846 * @return {Number} The element's height
7848 getHeight : function(contentHeight){
7849 var h = this.dom.offsetHeight || 0;
7850 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7854 * Returns the offset width of the element
7855 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7856 * @return {Number} The element's width
7858 getWidth : function(contentWidth){
7859 var w = this.dom.offsetWidth || 0;
7860 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7864 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7865 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7866 * if a height has not been set using CSS.
7869 getComputedHeight : function(){
7870 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7872 h = parseInt(this.getStyle('height'), 10) || 0;
7873 if(!this.isBorderBox()){
7874 h += this.getFrameWidth('tb');
7881 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7882 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7883 * if a width has not been set using CSS.
7886 getComputedWidth : function(){
7887 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7889 w = parseInt(this.getStyle('width'), 10) || 0;
7890 if(!this.isBorderBox()){
7891 w += this.getFrameWidth('lr');
7898 * Returns the size of the element.
7899 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7900 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7902 getSize : function(contentSize){
7903 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7907 * Returns the width and height of the viewport.
7908 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7910 getViewSize : function(){
7911 var d = this.dom, doc = document, aw = 0, ah = 0;
7912 if(d == doc || d == doc.body){
7913 return {width : D.getViewWidth(), height: D.getViewHeight()};
7916 width : d.clientWidth,
7917 height: d.clientHeight
7923 * Returns the value of the "value" attribute
7924 * @param {Boolean} asNumber true to parse the value as a number
7925 * @return {String/Number}
7927 getValue : function(asNumber){
7928 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7932 adjustWidth : function(width){
7933 if(typeof width == "number"){
7934 if(this.autoBoxAdjust && !this.isBorderBox()){
7935 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7945 adjustHeight : function(height){
7946 if(typeof height == "number"){
7947 if(this.autoBoxAdjust && !this.isBorderBox()){
7948 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7958 * Set the width of the element
7959 * @param {Number} width The new width
7960 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961 * @return {Roo.Element} this
7963 setWidth : function(width, animate){
7964 width = this.adjustWidth(width);
7966 this.dom.style.width = this.addUnits(width);
7968 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7974 * Set the height of the element
7975 * @param {Number} height The new height
7976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977 * @return {Roo.Element} this
7979 setHeight : function(height, animate){
7980 height = this.adjustHeight(height);
7982 this.dom.style.height = this.addUnits(height);
7984 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7990 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7991 * @param {Number} width The new width
7992 * @param {Number} height The new height
7993 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7994 * @return {Roo.Element} this
7996 setSize : function(width, height, animate){
7997 if(typeof width == "object"){ // in case of object from getSize()
7998 height = width.height; width = width.width;
8000 width = this.adjustWidth(width); height = this.adjustHeight(height);
8002 this.dom.style.width = this.addUnits(width);
8003 this.dom.style.height = this.addUnits(height);
8005 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8011 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8012 * @param {Number} x X value for new position (coordinates are page-based)
8013 * @param {Number} y Y value for new position (coordinates are page-based)
8014 * @param {Number} width The new width
8015 * @param {Number} height The new height
8016 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8017 * @return {Roo.Element} this
8019 setBounds : function(x, y, width, height, animate){
8021 this.setSize(width, height);
8022 this.setLocation(x, y);
8024 width = this.adjustWidth(width); height = this.adjustHeight(height);
8025 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8026 this.preanim(arguments, 4), 'motion');
8032 * Sets the element's position and size the the specified region. If animation is true then width, height, x and y will be animated concurrently.
8033 * @param {Roo.lib.Region} region The region to fill
8034 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8035 * @return {Roo.Element} this
8037 setRegion : function(region, animate){
8038 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8043 * Appends an event handler
8045 * @param {String} eventName The type of event to append
8046 * @param {Function} fn The method the event invokes
8047 * @param {Object} scope (optional) The scope (this object) of the fn
8048 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8050 addListener : function(eventName, fn, scope, options){
8052 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8057 * Removes an event handler from this element
8058 * @param {String} eventName the type of event to remove
8059 * @param {Function} fn the method the event invokes
8060 * @return {Roo.Element} this
8062 removeListener : function(eventName, fn){
8063 Roo.EventManager.removeListener(this.dom, eventName, fn);
8068 * Removes all previous added listeners from this element
8069 * @return {Roo.Element} this
8071 removeAllListeners : function(){
8072 E.purgeElement(this.dom);
8076 relayEvent : function(eventName, observable){
8077 this.on(eventName, function(e){
8078 observable.fireEvent(eventName, e);
8083 * Set the opacity of the element
8084 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8085 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8086 * @return {Roo.Element} this
8088 setOpacity : function(opacity, animate){
8090 var s = this.dom.style;
8093 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8094 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8096 s.opacity = opacity;
8099 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8105 * Gets the left X coordinate
8106 * @param {Boolean} local True to get the local css position instead of page coordinate
8109 getLeft : function(local){
8113 return parseInt(this.getStyle("left"), 10) || 0;
8118 * Gets the right X coordinate of the element (element X position + element width)
8119 * @param {Boolean} local True to get the local css position instead of page coordinate
8122 getRight : function(local){
8124 return this.getX() + this.getWidth();
8126 return (this.getLeft(true) + this.getWidth()) || 0;
8131 * Gets the top Y coordinate
8132 * @param {Boolean} local True to get the local css position instead of page coordinate
8135 getTop : function(local) {
8139 return parseInt(this.getStyle("top"), 10) || 0;
8144 * Gets the bottom Y coordinate of the element (element Y position + element height)
8145 * @param {Boolean} local True to get the local css position instead of page coordinate
8148 getBottom : function(local){
8150 return this.getY() + this.getHeight();
8152 return (this.getTop(true) + this.getHeight()) || 0;
8157 * Initializes positioning on this element. If a desired position is not passed, it will make the
8158 * the element positioned relative IF it is not already positioned.
8159 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8160 * @param {Number} zIndex (optional) The zIndex to apply
8161 * @param {Number} x (optional) Set the page X position
8162 * @param {Number} y (optional) Set the page Y position
8164 position : function(pos, zIndex, x, y){
8166 if(this.getStyle('position') == 'static'){
8167 this.setStyle('position', 'relative');
8170 this.setStyle("position", pos);
8173 this.setStyle("z-index", zIndex);
8175 if(x !== undefined && y !== undefined){
8177 }else if(x !== undefined){
8179 }else if(y !== undefined){
8185 * Clear positioning back to the default when the document was loaded
8186 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8187 * @return {Roo.Element} this
8189 clearPositioning : function(value){
8197 "position" : "static"
8203 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8204 * snapshot before performing an update and then restoring the element.
8207 getPositioning : function(){
8208 var l = this.getStyle("left");
8209 var t = this.getStyle("top");
8211 "position" : this.getStyle("position"),
8213 "right" : l ? "" : this.getStyle("right"),
8215 "bottom" : t ? "" : this.getStyle("bottom"),
8216 "z-index" : this.getStyle("z-index")
8221 * Gets the width of the border(s) for the specified side(s)
8222 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8223 * passing lr would get the border (l)eft width + the border (r)ight width.
8224 * @return {Number} The width of the sides passed added together
8226 getBorderWidth : function(side){
8227 return this.addStyles(side, El.borders);
8231 * Gets the width of the padding(s) for the specified side(s)
8232 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8233 * passing lr would get the padding (l)eft + the padding (r)ight.
8234 * @return {Number} The padding of the sides passed added together
8236 getPadding : function(side){
8237 return this.addStyles(side, El.paddings);
8241 * Set positioning with an object returned by getPositioning().
8242 * @param {Object} posCfg
8243 * @return {Roo.Element} this
8245 setPositioning : function(pc){
8246 this.applyStyles(pc);
8247 if(pc.right == "auto"){
8248 this.dom.style.right = "";
8250 if(pc.bottom == "auto"){
8251 this.dom.style.bottom = "";
8257 fixDisplay : function(){
8258 if(this.getStyle("display") == "none"){
8259 this.setStyle("visibility", "hidden");
8260 this.setStyle("display", this.originalDisplay); // first try reverting to default
8261 if(this.getStyle("display") == "none"){ // if that fails, default to block
8262 this.setStyle("display", "block");
8268 * Quick set left and top adding default units
8269 * @param {String} left The left CSS property value
8270 * @param {String} top The top CSS property value
8271 * @return {Roo.Element} this
8273 setLeftTop : function(left, top){
8274 this.dom.style.left = this.addUnits(left);
8275 this.dom.style.top = this.addUnits(top);
8280 * Move this element relative to its current position.
8281 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8282 * @param {Number} distance How far to move the element in pixels
8283 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8284 * @return {Roo.Element} this
8286 move : function(direction, distance, animate){
8287 var xy = this.getXY();
8288 direction = direction.toLowerCase();
8292 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8296 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8301 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8306 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8313 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8314 * @return {Roo.Element} this
8317 if(!this.isClipped){
8318 this.isClipped = true;
8319 this.originalClip = {
8320 "o": this.getStyle("overflow"),
8321 "x": this.getStyle("overflow-x"),
8322 "y": this.getStyle("overflow-y")
8324 this.setStyle("overflow", "hidden");
8325 this.setStyle("overflow-x", "hidden");
8326 this.setStyle("overflow-y", "hidden");
8332 * Return clipping (overflow) to original clipping before clip() was called
8333 * @return {Roo.Element} this
8335 unclip : function(){
8337 this.isClipped = false;
8338 var o = this.originalClip;
8339 if(o.o){this.setStyle("overflow", o.o);}
8340 if(o.x){this.setStyle("overflow-x", o.x);}
8341 if(o.y){this.setStyle("overflow-y", o.y);}
8348 * Gets the x,y coordinates specified by the anchor position on the element.
8349 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8350 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8351 * {width: (target width), height: (target height)} (defaults to the element's current size)
8352 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8353 * @return {Array} [x, y] An array containing the element's x and y coordinates
8355 getAnchorXY : function(anchor, local, s){
8356 //Passing a different size is useful for pre-calculating anchors,
8357 //especially for anchored animations that change the el size.
8359 var w, h, vp = false;
8362 if(d == document.body || d == document){
8364 w = D.getViewWidth(); h = D.getViewHeight();
8366 w = this.getWidth(); h = this.getHeight();
8369 w = s.width; h = s.height;
8371 var x = 0, y = 0, r = Math.round;
8372 switch((anchor || "tl").toLowerCase()){
8414 var sc = this.getScroll();
8415 return [x + sc.left, y + sc.top];
8417 //Add the element's offset xy
8418 var o = this.getXY();
8419 return [x+o[0], y+o[1]];
8423 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8424 * supported position values.
8425 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8426 * @param {String} position The position to align to.
8427 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8428 * @return {Array} [x, y]
8430 getAlignToXY : function(el, p, o){
8434 throw "Element.alignTo with an element that doesn't exist";
8436 var c = false; //constrain to viewport
8437 var p1 = "", p2 = "";
8444 }else if(p.indexOf("-") == -1){
8447 p = p.toLowerCase();
8448 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8450 throw "Element.alignTo with an invalid alignment " + p;
8452 p1 = m[1]; p2 = m[2]; c = !!m[3];
8454 //Subtract the aligned el's internal xy from the target's offset xy
8455 //plus custom offset to get the aligned el's new offset xy
8456 var a1 = this.getAnchorXY(p1, true);
8457 var a2 = el.getAnchorXY(p2, false);
8458 var x = a2[0] - a1[0] + o[0];
8459 var y = a2[1] - a1[1] + o[1];
8461 //constrain the aligned el to viewport if necessary
8462 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8463 // 5px of margin for ie
8464 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8466 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8467 //perpendicular to the vp border, allow the aligned el to slide on that border,
8468 //otherwise swap the aligned el to the opposite border of the target.
8469 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8470 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8471 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8472 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8475 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8476 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8478 if((x+w) > dw + scrollX){
8479 x = swapX ? r.left-w : dw+scrollX-w;
8482 x = swapX ? r.right : scrollX;
8484 if((y+h) > dh + scrollY){
8485 y = swapY ? r.top-h : dh+scrollY-h;
8488 y = swapY ? r.bottom : scrollY;
8495 getConstrainToXY : function(){
8496 var os = {top:0, left:0, bottom:0, right: 0};
8498 return function(el, local, offsets, proposedXY){
8500 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8502 var vw, vh, vx = 0, vy = 0;
8503 if(el.dom == document.body || el.dom == document){
8504 vw = Roo.lib.Dom.getViewWidth();
8505 vh = Roo.lib.Dom.getViewHeight();
8507 vw = el.dom.clientWidth;
8508 vh = el.dom.clientHeight;
8510 var vxy = el.getXY();
8516 var s = el.getScroll();
8518 vx += offsets.left + s.left;
8519 vy += offsets.top + s.top;
8521 vw -= offsets.right;
8522 vh -= offsets.bottom;
8527 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8528 var x = xy[0], y = xy[1];
8529 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8531 // only move it if it needs it
8534 // first validate right/bottom
8543 // then make sure top/left isn't negative
8552 return moved ? [x, y] : false;
8557 adjustForConstraints : function(xy, parent, offsets){
8558 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8562 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8563 * document it aligns it to the viewport.
8564 * The position parameter is optional, and can be specified in any one of the following formats:
8566 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8567 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8568 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8569 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8570 * <li><b>Two anchors</b>: If two values from the table below are passed separated by a dash, the first value is used as the
8571 * element's anchor point, and the second value is used as the target's anchor point.</li>
8573 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8574 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8575 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8576 * that specified in order to enforce the viewport constraints.
8577 * Following are all of the supported anchor positions:
8580 ----- -----------------------------
8581 tl The top left corner (default)
8582 t The center of the top edge
8583 tr The top right corner
8584 l The center of the left edge
8585 c In the center of the element
8586 r The center of the right edge
8587 bl The bottom left corner
8588 b The center of the bottom edge
8589 br The bottom right corner
8593 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8594 el.alignTo("other-el");
8596 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8597 el.alignTo("other-el", "tr?");
8599 // align the bottom right corner of el with the center left edge of other-el
8600 el.alignTo("other-el", "br-l?");
8602 // align the center of el with the bottom left corner of other-el and
8603 // adjust the x position by -6 pixels (and the y position by 0)
8604 el.alignTo("other-el", "c-bl", [-6, 0]);
8606 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8607 * @param {String} position The position to align to.
8608 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8609 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8610 * @return {Roo.Element} this
8612 alignTo : function(element, position, offsets, animate){
8613 var xy = this.getAlignToXY(element, position, offsets);
8614 this.setXY(xy, this.preanim(arguments, 3));
8619 * Anchors an element to another element and realigns it when the window is resized.
8620 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8621 * @param {String} position The position to align to.
8622 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8623 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8624 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8625 * is a number, it is used as the buffer delay (defaults to 50ms).
8626 * @param {Function} callback The function to call after the animation finishes
8627 * @return {Roo.Element} this
8629 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8630 var action = function(){
8631 this.alignTo(el, alignment, offsets, animate);
8632 Roo.callback(callback, this);
8634 Roo.EventManager.onWindowResize(action, this);
8635 var tm = typeof monitorScroll;
8636 if(tm != 'undefined'){
8637 Roo.EventManager.on(window, 'scroll', action, this,
8638 {buffer: tm == 'number' ? monitorScroll : 50});
8640 action.call(this); // align immediately
8644 * Clears any opacity settings from this element. Required in some cases for IE.
8645 * @return {Roo.Element} this
8647 clearOpacity : function(){
8648 if (window.ActiveXObject) {
8649 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8650 this.dom.style.filter = "";
8653 this.dom.style.opacity = "";
8654 this.dom.style["-moz-opacity"] = "";
8655 this.dom.style["-khtml-opacity"] = "";
8661 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8662 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8663 * @return {Roo.Element} this
8665 hide : function(animate){
8666 this.setVisible(false, this.preanim(arguments, 0));
8671 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8672 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8673 * @return {Roo.Element} this
8675 show : function(animate){
8676 this.setVisible(true, this.preanim(arguments, 0));
8681 * @private Test if size has a unit, otherwise appends the default
8683 addUnits : function(size){
8684 return Roo.Element.addUnits(size, this.defaultUnit);
8688 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8689 * @return {Roo.Element} this
8691 beginMeasure : function(){
8693 if(el.offsetWidth || el.offsetHeight){
8694 return this; // offsets work already
8697 var p = this.dom, b = document.body; // start with this element
8698 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8699 var pe = Roo.get(p);
8700 if(pe.getStyle('display') == 'none'){
8701 changed.push({el: p, visibility: pe.getStyle("visibility")});
8702 p.style.visibility = "hidden";
8703 p.style.display = "block";
8707 this._measureChanged = changed;
8713 * Restores displays to before beginMeasure was called
8714 * @return {Roo.Element} this
8716 endMeasure : function(){
8717 var changed = this._measureChanged;
8719 for(var i = 0, len = changed.length; i < len; i++) {
8721 r.el.style.visibility = r.visibility;
8722 r.el.style.display = "none";
8724 this._measureChanged = null;
8730 * Update the innerHTML of this element, optionally searching for and processing scripts
8731 * @param {String} html The new HTML
8732 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8733 * @param {Function} callback For async script loading you can be noticed when the update completes
8734 * @return {Roo.Element} this
8736 update : function(html, loadScripts, callback){
8737 if(typeof html == "undefined"){
8740 if(loadScripts !== true){
8741 this.dom.innerHTML = html;
8742 if(typeof callback == "function"){
8750 html += '<span id="' + id + '"></span>';
8752 E.onAvailable(id, function(){
8753 var hd = document.getElementsByTagName("head")[0];
8754 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8755 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8756 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8759 while(match = re.exec(html)){
8760 var attrs = match[1];
8761 var srcMatch = attrs ? attrs.match(srcRe) : false;
8762 if(srcMatch && srcMatch[2]){
8763 var s = document.createElement("script");
8764 s.src = srcMatch[2];
8765 var typeMatch = attrs.match(typeRe);
8766 if(typeMatch && typeMatch[2]){
8767 s.type = typeMatch[2];
8770 }else if(match[2] && match[2].length > 0){
8771 if(window.execScript) {
8772 window.execScript(match[2]);
8780 window.eval(match[2]);
8784 var el = document.getElementById(id);
8785 if(el){el.parentNode.removeChild(el);}
8786 if(typeof callback == "function"){
8790 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8795 * Direct access to the UpdateManager update() method (takes the same parameters).
8796 * @param {String/Function} url The url for this request or a function to call to get the url
8797 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
8798 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8799 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
8800 * @return {Roo.Element} this
8803 var um = this.getUpdateManager();
8804 um.update.apply(um, arguments);
8809 * Gets this element's UpdateManager
8810 * @return {Roo.UpdateManager} The UpdateManager
8812 getUpdateManager : function(){
8813 if(!this.updateManager){
8814 this.updateManager = new Roo.UpdateManager(this);
8816 return this.updateManager;
8820 * Disables text selection for this element (normalized across browsers)
8821 * @return {Roo.Element} this
8823 unselectable : function(){
8824 this.dom.unselectable = "on";
8825 this.swallowEvent("selectstart", true);
8826 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8827 this.addClass("x-unselectable");
8832 * Calculates the x, y to center this element on the screen
8833 * @return {Array} The x, y values [x, y]
8835 getCenterXY : function(){
8836 return this.getAlignToXY(document, 'c-c');
8840 * Centers the Element in either the viewport, or another Element.
8841 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8843 center : function(centerIn){
8844 this.alignTo(centerIn || document, 'c-c');
8849 * Tests various css rules/browsers to determine if this element uses a border box
8852 isBorderBox : function(){
8853 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8857 * Return a box {x, y, width, height} that can be used to set another elements
8858 * size/location to match this element.
8859 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8860 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8861 * @return {Object} box An object in the format {x, y, width, height}
8863 getBox : function(contentBox, local){
8868 var left = parseInt(this.getStyle("left"), 10) || 0;
8869 var top = parseInt(this.getStyle("top"), 10) || 0;
8872 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8874 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8876 var l = this.getBorderWidth("l")+this.getPadding("l");
8877 var r = this.getBorderWidth("r")+this.getPadding("r");
8878 var t = this.getBorderWidth("t")+this.getPadding("t");
8879 var b = this.getBorderWidth("b")+this.getPadding("b");
8880 bx = {x: xy[0]+l, y: xy[1]+t, 0: xy[0]+l, 1: xy[1]+t, width: w-(l+r), height: h-(t+b)};
8882 bx.right = bx.x + bx.width;
8883 bx.bottom = bx.y + bx.height;
8888 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8889 for more information about the sides.
8890 * @param {String} sides
8893 getFrameWidth : function(sides, onlyContentBox){
8894 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8898 * Sets the element's box. Use getBox() on another element to get a box obj. If animate is true then width, height, x and y will be animated concurrently.
8899 * @param {Object} box The box to fill {x, y, width, height}
8900 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8901 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8902 * @return {Roo.Element} this
8904 setBox : function(box, adjust, animate){
8905 var w = box.width, h = box.height;
8906 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8907 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8908 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8910 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8915 * Forces the browser to repaint this element
8916 * @return {Roo.Element} this
8918 repaint : function(){
8920 this.addClass("x-repaint");
8921 setTimeout(function(){
8922 Roo.get(dom).removeClass("x-repaint");
8928 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8929 * then it returns the calculated width of the sides (see getPadding)
8930 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8931 * @return {Object/Number}
8933 getMargins : function(side){
8936 top: parseInt(this.getStyle("margin-top"), 10) || 0,
8937 left: parseInt(this.getStyle("margin-left"), 10) || 0,
8938 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8939 right: parseInt(this.getStyle("margin-right"), 10) || 0
8942 return this.addStyles(side, El.margins);
8947 addStyles : function(sides, styles){
8949 for(var i = 0, len = sides.length; i < len; i++){
8950 v = this.getStyle(styles[sides.charAt(i)]);
8952 w = parseInt(v, 10);
8960 * Creates a proxy element of this element
8961 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8962 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8963 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8964 * @return {Roo.Element} The new proxy element
8966 createProxy : function(config, renderTo, matchBox){
8968 renderTo = Roo.getDom(renderTo);
8970 renderTo = document.body;
8972 config = typeof config == "object" ?
8973 config : {tag : "div", cls: config};
8974 var proxy = Roo.DomHelper.append(renderTo, config, true);
8976 proxy.setBox(this.getBox());
8982 * Puts a mask over this element to disable user interaction. Requires core.css.
8983 * This method can only be applied to elements which accept child nodes.
8984 * @param {String} msg (optional) A message to display in the mask
8985 * @param {String} msgCls (optional) A css class to apply to the msg element
8986 * @return {Element} The mask element
8988 mask : function(msg, msgCls)
8990 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8991 this.setStyle("position", "relative");
8994 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8996 this.addClass("x-masked");
8997 this._mask.setDisplayed(true);
9002 while (dom && dom.style) {
9003 if (!isNaN(parseInt(dom.style.zIndex))) {
9004 z = Math.max(z, parseInt(dom.style.zIndex));
9006 dom = dom.parentNode;
9008 // if we are masking the body - then it hides everything..
9009 if (this.dom == document.body) {
9011 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9012 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9015 if(typeof msg == 'string'){
9017 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9019 var mm = this._maskMsg;
9020 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9021 if (mm.dom.firstChild) { // weird IE issue?
9022 mm.dom.firstChild.innerHTML = msg;
9024 mm.setDisplayed(true);
9026 mm.setStyle('z-index', z + 102);
9028 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9029 this._mask.setHeight(this.getHeight());
9031 this._mask.setStyle('z-index', z + 100);
9037 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9038 * it is cached for reuse.
9040 unmask : function(removeEl){
9042 if(removeEl === true){
9043 this._mask.remove();
9046 this._maskMsg.remove();
9047 delete this._maskMsg;
9050 this._mask.setDisplayed(false);
9052 this._maskMsg.setDisplayed(false);
9056 this.removeClass("x-masked");
9060 * Returns true if this element is masked
9063 isMasked : function(){
9064 return this._mask && this._mask.isVisible();
9068 * Creates an iframe shim for this element to keep selects and other windowed objects from
9070 * @return {Roo.Element} The new shim element
9072 createShim : function(){
9073 var el = document.createElement('iframe');
9074 el.frameBorder = 'no';
9075 el.className = 'roo-shim';
9076 if(Roo.isIE && Roo.isSecure){
9077 el.src = Roo.SSL_SECURE_URL;
9079 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9080 shim.autoBoxAdjust = false;
9085 * Removes this element from the DOM and deletes it from the cache
9087 remove : function(){
9088 if(this.dom.parentNode){
9089 this.dom.parentNode.removeChild(this.dom);
9091 delete El.cache[this.dom.id];
9095 * Sets up event handlers to add and remove a css class when the mouse is over this element
9096 * @param {String} className
9097 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9098 * mouseout events for children elements
9099 * @return {Roo.Element} this
9101 addClassOnOver : function(className, preventFlicker){
9102 this.on("mouseover", function(){
9103 Roo.fly(this, '_internal').addClass(className);
9105 var removeFn = function(e){
9106 if(preventFlicker !== true || !e.within(this, true)){
9107 Roo.fly(this, '_internal').removeClass(className);
9110 this.on("mouseout", removeFn, this.dom);
9115 * Sets up event handlers to add and remove a css class when this element has the focus
9116 * @param {String} className
9117 * @return {Roo.Element} this
9119 addClassOnFocus : function(className){
9120 this.on("focus", function(){
9121 Roo.fly(this, '_internal').addClass(className);
9123 this.on("blur", function(){
9124 Roo.fly(this, '_internal').removeClass(className);
9129 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
9130 * @param {String} className
9131 * @return {Roo.Element} this
9133 addClassOnClick : function(className){
9135 this.on("mousedown", function(){
9136 Roo.fly(dom, '_internal').addClass(className);
9137 var d = Roo.get(document);
9138 var fn = function(){
9139 Roo.fly(dom, '_internal').removeClass(className);
9140 d.removeListener("mouseup", fn);
9142 d.on("mouseup", fn);
9148 * Stops the specified event from bubbling and optionally prevents the default action
9149 * @param {String} eventName
9150 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9151 * @return {Roo.Element} this
9153 swallowEvent : function(eventName, preventDefault){
9154 var fn = function(e){
9155 e.stopPropagation();
9160 if(eventName instanceof Array){
9161 for(var i = 0, len = eventName.length; i < len; i++){
9162 this.on(eventName[i], fn);
9166 this.on(eventName, fn);
9173 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9176 * Sizes this element to its parent element's dimensions performing
9177 * neccessary box adjustments.
9178 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9179 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9180 * @return {Roo.Element} this
9182 fitToParent : function(monitorResize, targetParent) {
9183 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9184 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9185 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9188 var p = Roo.get(targetParent || this.dom.parentNode);
9189 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9190 if (monitorResize === true) {
9191 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9192 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9198 * Gets the next sibling, skipping text nodes
9199 * @return {HTMLElement} The next sibling or null
9201 getNextSibling : function(){
9202 var n = this.dom.nextSibling;
9203 while(n && n.nodeType != 1){
9210 * Gets the previous sibling, skipping text nodes
9211 * @return {HTMLElement} The previous sibling or null
9213 getPrevSibling : function(){
9214 var n = this.dom.previousSibling;
9215 while(n && n.nodeType != 1){
9216 n = n.previousSibling;
9223 * Appends the passed element(s) to this element
9224 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9225 * @return {Roo.Element} this
9227 appendChild: function(el){
9234 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9235 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9236 * automatically generated with the specified attributes.
9237 * @param {HTMLElement} insertBefore (optional) a child element of this element
9238 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9239 * @return {Roo.Element} The new child element
9241 createChild: function(config, insertBefore, returnDom){
9242 config = config || {tag:'div'};
9244 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9246 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9250 * Appends this element to the passed element
9251 * @param {String/HTMLElement/Element} el The new parent element
9252 * @return {Roo.Element} this
9254 appendTo: function(el){
9255 el = Roo.getDom(el);
9256 el.appendChild(this.dom);
9261 * Inserts this element before the passed element in the DOM
9262 * @param {String/HTMLElement/Element} el The element to insert before
9263 * @return {Roo.Element} this
9265 insertBefore: function(el){
9266 el = Roo.getDom(el);
9267 el.parentNode.insertBefore(this.dom, el);
9272 * Inserts this element after the passed element in the DOM
9273 * @param {String/HTMLElement/Element} el The element to insert after
9274 * @return {Roo.Element} this
9276 insertAfter: function(el){
9277 el = Roo.getDom(el);
9278 el.parentNode.insertBefore(this.dom, el.nextSibling);
9283 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9284 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9285 * @return {Roo.Element} The new child
9287 insertFirst: function(el, returnDom){
9289 if(typeof el == 'object' && !el.nodeType){ // dh config
9290 return this.createChild(el, this.dom.firstChild, returnDom);
9292 el = Roo.getDom(el);
9293 this.dom.insertBefore(el, this.dom.firstChild);
9294 return !returnDom ? Roo.get(el) : el;
9299 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9300 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9301 * @param {String} where (optional) 'before' or 'after' defaults to before
9302 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9303 * @return {Roo.Element} the inserted Element
9305 insertSibling: function(el, where, returnDom){
9306 where = where ? where.toLowerCase() : 'before';
9308 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9310 if(typeof el == 'object' && !el.nodeType){ // dh config
9311 if(where == 'after' && !this.dom.nextSibling){
9312 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9314 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9318 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9319 where == 'before' ? this.dom : this.dom.nextSibling);
9328 * Creates and wraps this element with another element
9329 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9330 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9331 * @return {HTMLElement/Element} The newly created wrapper element
9333 wrap: function(config, returnDom){
9335 config = {tag: "div"};
9337 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9338 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9343 * Replaces the passed element with this element
9344 * @param {String/HTMLElement/Element} el The element to replace
9345 * @return {Roo.Element} this
9347 replace: function(el){
9349 this.insertBefore(el);
9355 * Inserts an html fragment into this element
9356 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9357 * @param {String} html The HTML fragment
9358 * @param {Boolean} returnEl True to return an Roo.Element
9359 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9361 insertHtml : function(where, html, returnEl){
9362 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9363 return returnEl ? Roo.get(el) : el;
9367 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9368 * @param {Object} o The object with the attributes
9369 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9370 * @return {Roo.Element} this
9372 set : function(o, useSet){
9374 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9376 if(attr == "style" || typeof o[attr] == "function") continue;
9378 el.className = o["cls"];
9380 if(useSet) el.setAttribute(attr, o[attr]);
9381 else el[attr] = o[attr];
9385 Roo.DomHelper.applyStyles(el, o.style);
9391 * Convenience method for constructing a KeyMap
9392 * @param {Number/Array/Object/String} key Either a string with the keys to listen for, the numeric key code, array of key codes or an object with the following options:
9393 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9394 * @param {Function} fn The function to call
9395 * @param {Object} scope (optional) The scope of the function
9396 * @return {Roo.KeyMap} The KeyMap created
9398 addKeyListener : function(key, fn, scope){
9400 if(typeof key != "object" || key instanceof Array){
9416 return new Roo.KeyMap(this, config);
9420 * Creates a KeyMap for this element
9421 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9422 * @return {Roo.KeyMap} The KeyMap created
9424 addKeyMap : function(config){
9425 return new Roo.KeyMap(this, config);
9429 * Returns true if this element is scrollable.
9432 isScrollable : function(){
9434 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9438 * Scrolls this element the specified scroll point. It does NOT do bounds checking so if you scroll to a weird value it will try to do it. For auto bounds checking, use scroll().
9439 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9440 * @param {Number} value The new scroll value
9441 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9442 * @return {Element} this
9445 scrollTo : function(side, value, animate){
9446 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9448 this.dom[prop] = value;
9450 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9451 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9457 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9458 * within this element's scrollable range.
9459 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9460 * @param {Number} distance How far to scroll the element in pixels
9461 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9462 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9463 * was scrolled as far as it could go.
9465 scroll : function(direction, distance, animate){
9466 if(!this.isScrollable()){
9470 var l = el.scrollLeft, t = el.scrollTop;
9471 var w = el.scrollWidth, h = el.scrollHeight;
9472 var cw = el.clientWidth, ch = el.clientHeight;
9473 direction = direction.toLowerCase();
9474 var scrolled = false;
9475 var a = this.preanim(arguments, 2);
9480 var v = Math.min(l + distance, w-cw);
9481 this.scrollTo("left", v, a);
9488 var v = Math.max(l - distance, 0);
9489 this.scrollTo("left", v, a);
9497 var v = Math.max(t - distance, 0);
9498 this.scrollTo("top", v, a);
9506 var v = Math.min(t + distance, h-ch);
9507 this.scrollTo("top", v, a);
9516 * Translates the passed page coordinates into left/top css values for this element
9517 * @param {Number/Array} x The page x or an array containing [x, y]
9518 * @param {Number} y The page y
9519 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9521 translatePoints : function(x, y){
9522 if(typeof x == 'object' || x instanceof Array){
9525 var p = this.getStyle('position');
9526 var o = this.getXY();
9528 var l = parseInt(this.getStyle('left'), 10);
9529 var t = parseInt(this.getStyle('top'), 10);
9532 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9535 t = (p == "relative") ? 0 : this.dom.offsetTop;
9538 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9542 * Returns the current scroll position of the element.
9543 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9545 getScroll : function(){
9546 var d = this.dom, doc = document;
9547 if(d == doc || d == doc.body){
9548 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9549 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9550 return {left: l, top: t};
9552 return {left: d.scrollLeft, top: d.scrollTop};
9557 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9558 * are convert to standard 6 digit hex color.
9559 * @param {String} attr The css attribute
9560 * @param {String} defaultValue The default value to use when a valid color isn't found
9561 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9564 getColor : function(attr, defaultValue, prefix){
9565 var v = this.getStyle(attr);
9566 if(!v || v == "transparent" || v == "inherit") {
9567 return defaultValue;
9569 var color = typeof prefix == "undefined" ? "#" : prefix;
9570 if(v.substr(0, 4) == "rgb("){
9571 var rvs = v.slice(4, v.length -1).split(",");
9572 for(var i = 0; i < 3; i++){
9573 var h = parseInt(rvs[i]).toString(16);
9580 if(v.substr(0, 1) == "#"){
9582 for(var i = 1; i < 4; i++){
9583 var c = v.charAt(i);
9586 }else if(v.length == 7){
9587 color += v.substr(1);
9591 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9595 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9596 * gradient background, rounded corners and a 4-way shadow.
9597 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9598 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9599 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9600 * @return {Roo.Element} this
9602 boxWrap : function(cls){
9603 cls = cls || 'x-box';
9604 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9605 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9610 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9611 * @param {String} namespace The namespace in which to look for the attribute
9612 * @param {String} name The attribute name
9613 * @return {String} The attribute value
9615 getAttributeNS : Roo.isIE ? function(ns, name){
9617 var type = typeof d[ns+":"+name];
9618 if(type != 'undefined' && type != 'unknown'){
9619 return d[ns+":"+name];
9622 } : function(ns, name){
9624 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9629 * Sets or Returns the value the dom attribute value
9630 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9631 * @param {String} value (optional) The value to set the attribute to
9632 * @return {String} The attribute value
9634 attr : function(name){
9635 if (arguments.length > 1) {
9636 this.dom.setAttribute(name, arguments[1]);
9637 return arguments[1];
9639 if (typeof(name) == 'object') {
9640 for(var i in name) {
9641 this.attr(i, name[i]);
9647 if (!this.dom.hasAttribute(name)) {
9650 return this.dom.getAttribute(name);
9657 var ep = El.prototype;
9660 * Appends an event handler (Shorthand for addListener)
9661 * @param {String} eventName The type of event to append
9662 * @param {Function} fn The method the event invokes
9663 * @param {Object} scope (optional) The scope (this object) of the fn
9664 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9667 ep.on = ep.addListener;
9669 ep.mon = ep.addListener;
9672 * Removes an event handler from this element (shorthand for removeListener)
9673 * @param {String} eventName the type of event to remove
9674 * @param {Function} fn the method the event invokes
9675 * @return {Roo.Element} this
9678 ep.un = ep.removeListener;
9681 * true to automatically adjust width and height settings for box-model issues (default to true)
9683 ep.autoBoxAdjust = true;
9686 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9689 El.addUnits = function(v, defaultUnit){
9690 if(v === "" || v == "auto"){
9693 if(v === undefined){
9696 if(typeof v == "number" || !El.unitPattern.test(v)){
9697 return v + (defaultUnit || 'px');
9702 // special markup used throughout Roo when box wrapping elements
9703 El.boxMarkup = '<div class="{0}-tl"><div class="{0}-tr"><div class="{0}-tc"></div></div></div><div class="{0}-ml"><div class="{0}-mr"><div class="{0}-mc"></div></div></div><div class="{0}-bl"><div class="{0}-br"><div class="{0}-bc"></div></div></div>';
9705 * Visibility mode constant - Use visibility to hide element
9711 * Visibility mode constant - Use display to hide element
9717 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9718 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9719 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9731 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9732 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9733 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9734 * @return {Element} The Element object
9737 El.get = function(el){
9739 if(!el){ return null; }
9740 if(typeof el == "string"){ // element id
9741 if(!(elm = document.getElementById(el))){
9744 if(ex = El.cache[el]){
9747 ex = El.cache[el] = new El(elm);
9750 }else if(el.tagName){ // dom element
9754 if(ex = El.cache[id]){
9757 ex = El.cache[id] = new El(el);
9760 }else if(el instanceof El){
9762 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9763 // catch case where it hasn't been appended
9764 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9767 }else if(el.isComposite){
9769 }else if(el instanceof Array){
9770 return El.select(el);
9771 }else if(el == document){
9772 // create a bogus element object representing the document object
9774 var f = function(){};
9775 f.prototype = El.prototype;
9777 docEl.dom = document;
9785 El.uncache = function(el){
9786 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9788 delete El.cache[a[i].id || a[i]];
9794 // Garbage collection - uncache elements/purge listeners on orphaned elements
9795 // so we don't hold a reference and cause the browser to retain them
9796 El.garbageCollect = function(){
9797 if(!Roo.enableGarbageCollector){
9798 clearInterval(El.collectorThread);
9801 for(var eid in El.cache){
9802 var el = El.cache[eid], d = el.dom;
9803 // -------------------------------------------------------
9804 // Determining what is garbage:
9805 // -------------------------------------------------------
9807 // dom node is null, definitely garbage
9808 // -------------------------------------------------------
9810 // no parentNode == direct orphan, definitely garbage
9811 // -------------------------------------------------------
9812 // !d.offsetParent && !document.getElementById(eid)
9813 // display none elements have no offsetParent so we will
9814 // also try to look it up by it's id. However, check
9815 // offsetParent first so we don't do unneeded lookups.
9816 // This enables collection of elements that are not orphans
9817 // directly, but somewhere up the line they have an orphan
9819 // -------------------------------------------------------
9820 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9821 delete El.cache[eid];
9822 if(d && Roo.enableListenerCollection){
9828 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9832 El.Flyweight = function(dom){
9835 El.Flyweight.prototype = El.prototype;
9837 El._flyweights = {};
9839 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9840 * the dom node can be overwritten by other code.
9841 * @param {String/HTMLElement} el The dom node or id
9842 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9843 * prevent conflicts (e.g. internally Roo uses "_internal")
9845 * @return {Element} The shared Element object
9847 El.fly = function(el, named){
9848 named = named || '_global';
9849 el = Roo.getDom(el);
9853 if(!El._flyweights[named]){
9854 El._flyweights[named] = new El.Flyweight();
9856 El._flyweights[named].dom = el;
9857 return El._flyweights[named];
9861 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9862 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9863 * Shorthand of {@link Roo.Element#get}
9864 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9865 * @return {Element} The Element object
9871 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9872 * the dom node can be overwritten by other code.
9873 * Shorthand of {@link Roo.Element#fly}
9874 * @param {String/HTMLElement} el The dom node or id
9875 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9876 * prevent conflicts (e.g. internally Roo uses "_internal")
9878 * @return {Element} The shared Element object
9884 // speedy lookup for elements never to box adjust
9885 var noBoxAdjust = Roo.isStrict ? {
9888 input:1, select:1, textarea:1
9890 if(Roo.isIE || Roo.isGecko){
9891 noBoxAdjust['button'] = 1;
9895 Roo.EventManager.on(window, 'unload', function(){
9897 delete El._flyweights;
9905 Roo.Element.selectorFunction = Roo.DomQuery.select;
9908 Roo.Element.select = function(selector, unique, root){
9910 if(typeof selector == "string"){
9911 els = Roo.Element.selectorFunction(selector, root);
9912 }else if(selector.length !== undefined){
9915 throw "Invalid selector";
9917 if(unique === true){
9918 return new Roo.CompositeElement(els);
9920 return new Roo.CompositeElementLite(els);
9924 * Selects elements based on the passed CSS selector to enable working on them as 1.
9925 * @param {String/Array} selector The CSS selector or an array of elements
9926 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9927 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9928 * @return {CompositeElementLite/CompositeElement}
9932 Roo.select = Roo.Element.select;
9949 * Ext JS Library 1.1.1
9950 * Copyright(c) 2006-2007, Ext JS, LLC.
9952 * Originally Released Under LGPL - original licence link has changed is not relivant.
9955 * <script type="text/javascript">
9960 //Notifies Element that fx methods are available
9961 Roo.enableFx = true;
9965 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
9966 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9967 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
9968 * Element effects to work.</p><br/>
9970 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9971 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9972 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9973 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
9974 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9975 * expected results and should be done with care.</p><br/>
9977 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9978 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
9981 ----- -----------------------------
9982 tl The top left corner
9983 t The center of the top edge
9984 tr The top right corner
9985 l The center of the left edge
9986 r The center of the right edge
9987 bl The bottom left corner
9988 b The center of the bottom edge
9989 br The bottom right corner
9991 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9992 * below are common options that can be passed to any Fx method.</b>
9993 * @cfg {Function} callback A function called when the effect is finished
9994 * @cfg {Object} scope The scope of the effect function
9995 * @cfg {String} easing A valid Easing value for the effect
9996 * @cfg {String} afterCls A css class to apply after the effect
9997 * @cfg {Number} duration The length of time (in seconds) that the effect should last
9998 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9999 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10000 * effects that end with the element being visually hidden, ignored otherwise)
10001 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10002 * a function which returns such a specification that will be applied to the Element after the effect finishes
10003 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10004 * @cfg {Boolean} concurrent Whether to allow subsequently-queued effects to run at the same time as the current effect, or to ensure that they run in sequence
10005 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10009 * Slides the element into view. An anchor point can be optionally passed to set the point of
10010 * origin for the slide effect. This function automatically handles wrapping the element with
10011 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10014 // default: slide the element in from the top
10017 // custom: slide the element in from the right with a 2-second duration
10018 el.slideIn('r', { duration: 2 });
10020 // common config options shown with default values
10026 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10027 * @param {Object} options (optional) Object literal with any of the Fx config options
10028 * @return {Roo.Element} The Element
10030 slideIn : function(anchor, o){
10031 var el = this.getFxEl();
10034 el.queueFx(o, function(){
10036 anchor = anchor || "t";
10038 // fix display to visibility
10041 // restore values after effect
10042 var r = this.getFxRestore();
10043 var b = this.getBox();
10044 // fixed size for slide
10048 var wrap = this.fxWrap(r.pos, o, "hidden");
10050 var st = this.dom.style;
10051 st.visibility = "visible";
10052 st.position = "absolute";
10054 // clear out temp styles after slide and unwrap
10055 var after = function(){
10056 el.fxUnwrap(wrap, r.pos, o);
10057 st.width = r.width;
10058 st.height = r.height;
10061 // time to calc the positions
10062 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10064 switch(anchor.toLowerCase()){
10066 wrap.setSize(b.width, 0);
10067 st.left = st.bottom = "0";
10071 wrap.setSize(0, b.height);
10072 st.right = st.top = "0";
10076 wrap.setSize(0, b.height);
10077 wrap.setX(b.right);
10078 st.left = st.top = "0";
10079 a = {width: bw, points: pt};
10082 wrap.setSize(b.width, 0);
10083 wrap.setY(b.bottom);
10084 st.left = st.top = "0";
10085 a = {height: bh, points: pt};
10088 wrap.setSize(0, 0);
10089 st.right = st.bottom = "0";
10090 a = {width: bw, height: bh};
10093 wrap.setSize(0, 0);
10094 wrap.setY(b.y+b.height);
10095 st.right = st.top = "0";
10096 a = {width: bw, height: bh, points: pt};
10099 wrap.setSize(0, 0);
10100 wrap.setXY([b.right, b.bottom]);
10101 st.left = st.top = "0";
10102 a = {width: bw, height: bh, points: pt};
10105 wrap.setSize(0, 0);
10106 wrap.setX(b.x+b.width);
10107 st.left = st.bottom = "0";
10108 a = {width: bw, height: bh, points: pt};
10111 this.dom.style.visibility = "visible";
10114 arguments.callee.anim = wrap.fxanim(a,
10124 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10125 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10126 * 'hidden') but block elements will still take up space in the document. The element must be removed
10127 * from the DOM using the 'remove' config option if desired. This function automatically handles
10128 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10131 // default: slide the element out to the top
10134 // custom: slide the element out to the right with a 2-second duration
10135 el.slideOut('r', { duration: 2 });
10137 // common config options shown with default values
10145 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10146 * @param {Object} options (optional) Object literal with any of the Fx config options
10147 * @return {Roo.Element} The Element
10149 slideOut : function(anchor, o){
10150 var el = this.getFxEl();
10153 el.queueFx(o, function(){
10155 anchor = anchor || "t";
10157 // restore values after effect
10158 var r = this.getFxRestore();
10160 var b = this.getBox();
10161 // fixed size for slide
10165 var wrap = this.fxWrap(r.pos, o, "visible");
10167 var st = this.dom.style;
10168 st.visibility = "visible";
10169 st.position = "absolute";
10173 var after = function(){
10175 el.setDisplayed(false);
10180 el.fxUnwrap(wrap, r.pos, o);
10182 st.width = r.width;
10183 st.height = r.height;
10188 var a, zero = {to: 0};
10189 switch(anchor.toLowerCase()){
10191 st.left = st.bottom = "0";
10192 a = {height: zero};
10195 st.right = st.top = "0";
10199 st.left = st.top = "0";
10200 a = {width: zero, points: {to:[b.right, b.y]}};
10203 st.left = st.top = "0";
10204 a = {height: zero, points: {to:[b.x, b.bottom]}};
10207 st.right = st.bottom = "0";
10208 a = {width: zero, height: zero};
10211 st.right = st.top = "0";
10212 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10215 st.left = st.top = "0";
10216 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10219 st.left = st.bottom = "0";
10220 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10224 arguments.callee.anim = wrap.fxanim(a,
10234 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10235 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10236 * The element must be removed from the DOM using the 'remove' config option if desired.
10242 // common config options shown with default values
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 puff : function(o){
10254 var el = this.getFxEl();
10257 el.queueFx(o, function(){
10258 this.clearOpacity();
10261 // restore values after effect
10262 var r = this.getFxRestore();
10263 var st = this.dom.style;
10265 var after = function(){
10267 el.setDisplayed(false);
10274 el.setPositioning(r.pos);
10275 st.width = r.width;
10276 st.height = r.height;
10281 var width = this.getWidth();
10282 var height = this.getHeight();
10284 arguments.callee.anim = this.fxanim({
10285 width : {to: this.adjustWidth(width * 2)},
10286 height : {to: this.adjustHeight(height * 2)},
10287 points : {by: [-(width * .5), -(height * .5)]},
10289 fontSize: {to:200, unit: "%"}
10300 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10301 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10302 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10308 // all config options shown with default values
10316 * @param {Object} options (optional) Object literal with any of the Fx config options
10317 * @return {Roo.Element} The Element
10319 switchOff : function(o){
10320 var el = this.getFxEl();
10323 el.queueFx(o, function(){
10324 this.clearOpacity();
10327 // restore values after effect
10328 var r = this.getFxRestore();
10329 var st = this.dom.style;
10331 var after = function(){
10333 el.setDisplayed(false);
10339 el.setPositioning(r.pos);
10340 st.width = r.width;
10341 st.height = r.height;
10346 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10347 this.clearOpacity();
10351 points:{by:[0, this.getHeight() * .5]}
10352 }, o, 'motion', 0.3, 'easeIn', after);
10353 }).defer(100, this);
10360 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10361 * changed using the "attr" config option) and then fading back to the original color. If no original
10362 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10365 // default: highlight background to yellow
10368 // custom: highlight foreground text to blue for 2 seconds
10369 el.highlight("0000ff", { attr: 'color', duration: 2 });
10371 // common config options shown with default values
10372 el.highlight("ffff9c", {
10373 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10374 endColor: (current color) or "ffffff",
10379 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10380 * @param {Object} options (optional) Object literal with any of the Fx config options
10381 * @return {Roo.Element} The Element
10383 highlight : function(color, o){
10384 var el = this.getFxEl();
10387 el.queueFx(o, function(){
10388 color = color || "ffff9c";
10389 attr = o.attr || "backgroundColor";
10391 this.clearOpacity();
10394 var origColor = this.getColor(attr);
10395 var restoreColor = this.dom.style[attr];
10396 endColor = (o.endColor || origColor) || "ffffff";
10398 var after = function(){
10399 el.dom.style[attr] = restoreColor;
10404 a[attr] = {from: color, to: endColor};
10405 arguments.callee.anim = this.fxanim(a,
10415 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10418 // default: a single light blue ripple
10421 // custom: 3 red ripples lasting 3 seconds total
10422 el.frame("ff0000", 3, { duration: 3 });
10424 // common config options shown with default values
10425 el.frame("C3DAF9", 1, {
10426 duration: 1 //duration of entire animation (not each individual ripple)
10427 // Note: Easing is not configurable and will be ignored if included
10430 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10431 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10432 * @param {Object} options (optional) Object literal with any of the Fx config options
10433 * @return {Roo.Element} The Element
10435 frame : function(color, count, o){
10436 var el = this.getFxEl();
10439 el.queueFx(o, function(){
10440 color = color || "#C3DAF9";
10441 if(color.length == 6){
10442 color = "#" + color;
10444 count = count || 1;
10445 duration = o.duration || 1;
10448 var b = this.getBox();
10449 var animFn = function(){
10450 var proxy = this.createProxy({
10453 visbility:"hidden",
10454 position:"absolute",
10455 "z-index":"35000", // yee haw
10456 border:"0px solid " + color
10459 var scale = Roo.isBorderBox ? 2 : 1;
10461 top:{from:b.y, to:b.y - 20},
10462 left:{from:b.x, to:b.x - 20},
10463 borderWidth:{from:0, to:10},
10464 opacity:{from:1, to:0},
10465 height:{from:b.height, to:(b.height + (20*scale))},
10466 width:{from:b.width, to:(b.width + (20*scale))}
10467 }, duration, function(){
10471 animFn.defer((duration/2)*1000, this);
10482 * Creates a pause before any subsequent queued effects begin. If there are
10483 * no effects queued after the pause it will have no effect.
10488 * @param {Number} seconds The length of time to pause (in seconds)
10489 * @return {Roo.Element} The Element
10491 pause : function(seconds){
10492 var el = this.getFxEl();
10495 el.queueFx(o, function(){
10496 setTimeout(function(){
10498 }, seconds * 1000);
10504 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10505 * using the "endOpacity" config option.
10508 // default: fade in from opacity 0 to 100%
10511 // custom: fade in from opacity 0 to 75% over 2 seconds
10512 el.fadeIn({ endOpacity: .75, duration: 2});
10514 // common config options shown with default values
10516 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10521 * @param {Object} options (optional) Object literal with any of the Fx config options
10522 * @return {Roo.Element} The Element
10524 fadeIn : function(o){
10525 var el = this.getFxEl();
10527 el.queueFx(o, function(){
10528 this.setOpacity(0);
10530 this.dom.style.visibility = 'visible';
10531 var to = o.endOpacity || 1;
10532 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10533 o, null, .5, "easeOut", function(){
10535 this.clearOpacity();
10544 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10545 * using the "endOpacity" config option.
10548 // default: fade out from the element's current opacity to 0
10551 // custom: fade out from the element's current opacity to 25% over 2 seconds
10552 el.fadeOut({ endOpacity: .25, duration: 2});
10554 // common config options shown with default values
10556 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10563 * @param {Object} options (optional) Object literal with any of the Fx config options
10564 * @return {Roo.Element} The Element
10566 fadeOut : function(o){
10567 var el = this.getFxEl();
10569 el.queueFx(o, function(){
10570 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10571 o, null, .5, "easeOut", function(){
10572 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10573 this.dom.style.display = "none";
10575 this.dom.style.visibility = "hidden";
10577 this.clearOpacity();
10585 * Animates the transition of an element's dimensions from a starting height/width
10586 * to an ending height/width.
10589 // change height and width to 100x100 pixels
10590 el.scale(100, 100);
10592 // common config options shown with default values. The height and width will default to
10593 // the element's existing values if passed as null.
10596 [element's height], {
10601 * @param {Number} width The new width (pass undefined to keep the original width)
10602 * @param {Number} height The new height (pass undefined to keep the original height)
10603 * @param {Object} options (optional) Object literal with any of the Fx config options
10604 * @return {Roo.Element} The Element
10606 scale : function(w, h, o){
10607 this.shift(Roo.apply({}, o, {
10615 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10616 * Any of these properties not specified in the config object will not be changed. This effect
10617 * requires that at least one new dimension, position or opacity setting must be passed in on
10618 * the config object in order for the function to have any effect.
10621 // slide the element horizontally to x position 200 while changing the height and opacity
10622 el.shift({ x: 200, height: 50, opacity: .8 });
10624 // common config options shown with default values.
10626 width: [element's width],
10627 height: [element's height],
10628 x: [element's x position],
10629 y: [element's y position],
10630 opacity: [element's opacity],
10635 * @param {Object} options Object literal with any of the Fx config options
10636 * @return {Roo.Element} The Element
10638 shift : function(o){
10639 var el = this.getFxEl();
10641 el.queueFx(o, function(){
10642 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10643 if(w !== undefined){
10644 a.width = {to: this.adjustWidth(w)};
10646 if(h !== undefined){
10647 a.height = {to: this.adjustHeight(h)};
10649 if(x !== undefined || y !== undefined){
10651 x !== undefined ? x : this.getX(),
10652 y !== undefined ? y : this.getY()
10655 if(op !== undefined){
10656 a.opacity = {to: op};
10658 if(o.xy !== undefined){
10659 a.points = {to: o.xy};
10661 arguments.callee.anim = this.fxanim(a,
10662 o, 'motion', .35, "easeOut", function(){
10670 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10671 * ending point of the effect.
10674 // default: slide the element downward while fading out
10677 // custom: slide the element out to the right with a 2-second duration
10678 el.ghost('r', { duration: 2 });
10680 // common config options shown with default values
10688 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10689 * @param {Object} options (optional) Object literal with any of the Fx config options
10690 * @return {Roo.Element} The Element
10692 ghost : function(anchor, o){
10693 var el = this.getFxEl();
10696 el.queueFx(o, function(){
10697 anchor = anchor || "b";
10699 // restore values after effect
10700 var r = this.getFxRestore();
10701 var w = this.getWidth(),
10702 h = this.getHeight();
10704 var st = this.dom.style;
10706 var after = function(){
10708 el.setDisplayed(false);
10714 el.setPositioning(r.pos);
10715 st.width = r.width;
10716 st.height = r.height;
10721 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10722 switch(anchor.toLowerCase()){
10749 arguments.callee.anim = this.fxanim(a,
10759 * Ensures that all effects queued after syncFx is called on the element are
10760 * run concurrently. This is the opposite of {@link #sequenceFx}.
10761 * @return {Roo.Element} The Element
10763 syncFx : function(){
10764 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10773 * Ensures that all effects queued after sequenceFx is called on the element are
10774 * run in sequence. This is the opposite of {@link #syncFx}.
10775 * @return {Roo.Element} The Element
10777 sequenceFx : function(){
10778 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10780 concurrent : false,
10787 nextFx : function(){
10788 var ef = this.fxQueue[0];
10795 * Returns true if the element has any effects actively running or queued, else returns false.
10796 * @return {Boolean} True if element has active effects, else false
10798 hasActiveFx : function(){
10799 return this.fxQueue && this.fxQueue[0];
10803 * Stops any running effects and clears the element's internal effects queue if it contains
10804 * any additional effects that haven't started yet.
10805 * @return {Roo.Element} The Element
10807 stopFx : function(){
10808 if(this.hasActiveFx()){
10809 var cur = this.fxQueue[0];
10810 if(cur && cur.anim && cur.anim.isAnimated()){
10811 this.fxQueue = [cur]; // clear out others
10812 cur.anim.stop(true);
10819 beforeFx : function(o){
10820 if(this.hasActiveFx() && !o.concurrent){
10831 * Returns true if the element is currently blocking so that no other effect can be queued
10832 * until this effect is finished, else returns false if blocking is not set. This is commonly
10833 * used to ensure that an effect initiated by a user action runs to completion prior to the
10834 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10835 * @return {Boolean} True if blocking, else false
10837 hasFxBlock : function(){
10838 var q = this.fxQueue;
10839 return q && q[0] && q[0].block;
10843 queueFx : function(o, fn){
10847 if(!this.hasFxBlock()){
10848 Roo.applyIf(o, this.fxDefaults);
10850 var run = this.beforeFx(o);
10851 fn.block = o.block;
10852 this.fxQueue.push(fn);
10864 fxWrap : function(pos, o, vis){
10866 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10869 wrapXY = this.getXY();
10871 var div = document.createElement("div");
10872 div.style.visibility = vis;
10873 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10874 wrap.setPositioning(pos);
10875 if(wrap.getStyle("position") == "static"){
10876 wrap.position("relative");
10878 this.clearPositioning('auto');
10880 wrap.dom.appendChild(this.dom);
10882 wrap.setXY(wrapXY);
10889 fxUnwrap : function(wrap, pos, o){
10890 this.clearPositioning();
10891 this.setPositioning(pos);
10893 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10899 getFxRestore : function(){
10900 var st = this.dom.style;
10901 return {pos: this.getPositioning(), width: st.width, height : st.height};
10905 afterFx : function(o){
10907 this.applyStyles(o.afterStyle);
10910 this.addClass(o.afterCls);
10912 if(o.remove === true){
10915 Roo.callback(o.callback, o.scope, [this]);
10917 this.fxQueue.shift();
10923 getFxEl : function(){ // support for composite element fx
10924 return Roo.get(this.dom);
10928 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10929 animType = animType || 'run';
10931 var anim = Roo.lib.Anim[animType](
10933 (opt.duration || defaultDur) || .35,
10934 (opt.easing || defaultEase) || 'easeOut',
10936 Roo.callback(cb, this);
10945 // backwords compat
10946 Roo.Fx.resize = Roo.Fx.scale;
10948 //When included, Roo.Fx is automatically applied to Element so that all basic
10949 //effects are available directly via the Element API
10950 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10952 * Ext JS Library 1.1.1
10953 * Copyright(c) 2006-2007, Ext JS, LLC.
10955 * Originally Released Under LGPL - original licence link has changed is not relivant.
10958 * <script type="text/javascript">
10963 * @class Roo.CompositeElement
10964 * Standard composite class. Creates a Roo.Element for every element in the collection.
10966 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10967 * actions will be performed on all the elements in this collection.</b>
10969 * All methods return <i>this</i> and can be chained.
10971 var els = Roo.select("#some-el div.some-class", true);
10972 // or select directly from an existing element
10973 var el = Roo.get('some-el');
10974 el.select('div.some-class', true);
10976 els.setWidth(100); // all elements become 100 width
10977 els.hide(true); // all elements fade out and hide
10979 els.setWidth(100).hide(true);
10982 Roo.CompositeElement = function(els){
10983 this.elements = [];
10984 this.addElements(els);
10986 Roo.CompositeElement.prototype = {
10988 addElements : function(els){
10989 if(!els) return this;
10990 if(typeof els == "string"){
10991 els = Roo.Element.selectorFunction(els);
10993 var yels = this.elements;
10994 var index = yels.length-1;
10995 for(var i = 0, len = els.length; i < len; i++) {
10996 yels[++index] = Roo.get(els[i]);
11002 * Clears this composite and adds the elements returned by the passed selector.
11003 * @param {String/Array} els A string CSS selector, an array of elements or an element
11004 * @return {CompositeElement} this
11006 fill : function(els){
11007 this.elements = [];
11013 * Filters this composite to only elements that match the passed selector.
11014 * @param {String} selector A string CSS selector
11015 * @param {Boolean} inverse return inverse filter (not matches)
11016 * @return {CompositeElement} this
11018 filter : function(selector, inverse){
11020 inverse = inverse || false;
11021 this.each(function(el){
11022 var match = inverse ? !el.is(selector) : el.is(selector);
11024 els[els.length] = el.dom;
11031 invoke : function(fn, args){
11032 var els = this.elements;
11033 for(var i = 0, len = els.length; i < len; i++) {
11034 Roo.Element.prototype[fn].apply(els[i], args);
11039 * Adds elements to this composite.
11040 * @param {String/Array} els A string CSS selector, an array of elements or an element
11041 * @return {CompositeElement} this
11043 add : function(els){
11044 if(typeof els == "string"){
11045 this.addElements(Roo.Element.selectorFunction(els));
11046 }else if(els.length !== undefined){
11047 this.addElements(els);
11049 this.addElements([els]);
11054 * Calls the passed function passing (el, this, index) for each element in this composite.
11055 * @param {Function} fn The function to call
11056 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11057 * @return {CompositeElement} this
11059 each : function(fn, scope){
11060 var els = this.elements;
11061 for(var i = 0, len = els.length; i < len; i++){
11062 if(fn.call(scope || els[i], els[i], this, i) === false) {
11070 * Returns the Element object at the specified index
11071 * @param {Number} index
11072 * @return {Roo.Element}
11074 item : function(index){
11075 return this.elements[index] || null;
11079 * Returns the first Element
11080 * @return {Roo.Element}
11082 first : function(){
11083 return this.item(0);
11087 * Returns the last Element
11088 * @return {Roo.Element}
11091 return this.item(this.elements.length-1);
11095 * Returns the number of elements in this composite
11098 getCount : function(){
11099 return this.elements.length;
11103 * Returns true if this composite contains the passed element
11106 contains : function(el){
11107 return this.indexOf(el) !== -1;
11111 * Returns true if this composite contains the passed element
11114 indexOf : function(el){
11115 return this.elements.indexOf(Roo.get(el));
11120 * Removes the specified element(s).
11121 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11122 * or an array of any of those.
11123 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11124 * @return {CompositeElement} this
11126 removeElement : function(el, removeDom){
11127 if(el instanceof Array){
11128 for(var i = 0, len = el.length; i < len; i++){
11129 this.removeElement(el[i]);
11133 var index = typeof el == 'number' ? el : this.indexOf(el);
11136 var d = this.elements[index];
11140 d.parentNode.removeChild(d);
11143 this.elements.splice(index, 1);
11149 * Replaces the specified element with the passed element.
11150 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11152 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11153 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11154 * @return {CompositeElement} this
11156 replaceElement : function(el, replacement, domReplace){
11157 var index = typeof el == 'number' ? el : this.indexOf(el);
11160 this.elements[index].replaceWith(replacement);
11162 this.elements.splice(index, 1, Roo.get(replacement))
11169 * Removes all elements.
11171 clear : function(){
11172 this.elements = [];
11176 Roo.CompositeElement.createCall = function(proto, fnName){
11177 if(!proto[fnName]){
11178 proto[fnName] = function(){
11179 return this.invoke(fnName, arguments);
11183 for(var fnName in Roo.Element.prototype){
11184 if(typeof Roo.Element.prototype[fnName] == "function"){
11185 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11191 * Ext JS Library 1.1.1
11192 * Copyright(c) 2006-2007, Ext JS, LLC.
11194 * Originally Released Under LGPL - original licence link has changed is not relivant.
11197 * <script type="text/javascript">
11201 * @class Roo.CompositeElementLite
11202 * @extends Roo.CompositeElement
11203 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11205 var els = Roo.select("#some-el div.some-class");
11206 // or select directly from an existing element
11207 var el = Roo.get('some-el');
11208 el.select('div.some-class');
11210 els.setWidth(100); // all elements become 100 width
11211 els.hide(true); // all elements fade out and hide
11213 els.setWidth(100).hide(true);
11214 </code></pre><br><br>
11215 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11216 * actions will be performed on all the elements in this collection.</b>
11218 Roo.CompositeElementLite = function(els){
11219 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11220 this.el = new Roo.Element.Flyweight();
11222 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11223 addElements : function(els){
11225 if(els instanceof Array){
11226 this.elements = this.elements.concat(els);
11228 var yels = this.elements;
11229 var index = yels.length-1;
11230 for(var i = 0, len = els.length; i < len; i++) {
11231 yels[++index] = els[i];
11237 invoke : function(fn, args){
11238 var els = this.elements;
11240 for(var i = 0, len = els.length; i < len; i++) {
11242 Roo.Element.prototype[fn].apply(el, args);
11247 * Returns a flyweight Element of the dom element object at the specified index
11248 * @param {Number} index
11249 * @return {Roo.Element}
11251 item : function(index){
11252 if(!this.elements[index]){
11255 this.el.dom = this.elements[index];
11259 // fixes scope with flyweight
11260 addListener : function(eventName, handler, scope, opt){
11261 var els = this.elements;
11262 for(var i = 0, len = els.length; i < len; i++) {
11263 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11269 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11270 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11271 * a reference to the dom node, use el.dom.</b>
11272 * @param {Function} fn The function to call
11273 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11274 * @return {CompositeElement} this
11276 each : function(fn, scope){
11277 var els = this.elements;
11279 for(var i = 0, len = els.length; i < len; i++){
11281 if(fn.call(scope || el, el, this, i) === false){
11288 indexOf : function(el){
11289 return this.elements.indexOf(Roo.getDom(el));
11292 replaceElement : function(el, replacement, domReplace){
11293 var index = typeof el == 'number' ? el : this.indexOf(el);
11295 replacement = Roo.getDom(replacement);
11297 var d = this.elements[index];
11298 d.parentNode.insertBefore(replacement, d);
11299 d.parentNode.removeChild(d);
11301 this.elements.splice(index, 1, replacement);
11306 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11310 * Ext JS Library 1.1.1
11311 * Copyright(c) 2006-2007, Ext JS, LLC.
11313 * Originally Released Under LGPL - original licence link has changed is not relivant.
11316 * <script type="text/javascript">
11322 * @class Roo.data.Connection
11323 * @extends Roo.util.Observable
11324 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11325 * either to a configured URL, or to a URL specified at request time.<br><br>
11327 * Requests made by this class are asynchronous, and will return immediately. No data from
11328 * the server will be available to the statement immediately following the {@link #request} call.
11329 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11331 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11332 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11333 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11334 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11335 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11336 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11337 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11338 * standard DOM methods.
11340 * @param {Object} config a configuration object.
11342 Roo.data.Connection = function(config){
11343 Roo.apply(this, config);
11346 * @event beforerequest
11347 * Fires before a network request is made to retrieve a data object.
11348 * @param {Connection} conn This Connection object.
11349 * @param {Object} options The options config object passed to the {@link #request} method.
11351 "beforerequest" : true,
11353 * @event requestcomplete
11354 * Fires if the request was successfully completed.
11355 * @param {Connection} conn This Connection object.
11356 * @param {Object} response The XHR object containing the response data.
11357 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11358 * @param {Object} options The options config object passed to the {@link #request} method.
11360 "requestcomplete" : true,
11362 * @event requestexception
11363 * Fires if an error HTTP status was returned from the server.
11364 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11365 * @param {Connection} conn This Connection object.
11366 * @param {Object} response The XHR object containing the response data.
11367 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11368 * @param {Object} options The options config object passed to the {@link #request} method.
11370 "requestexception" : true
11372 Roo.data.Connection.superclass.constructor.call(this);
11375 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11377 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11380 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11381 * extra parameters to each request made by this object. (defaults to undefined)
11384 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11385 * to each request made by this object. (defaults to undefined)
11388 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11391 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11395 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11401 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11404 disableCaching: true,
11407 * Sends an HTTP request to a remote server.
11408 * @param {Object} options An object which may contain the following properties:<ul>
11409 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11410 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11411 * request, a url encoded string or a function to call to get either.</li>
11412 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11413 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11414 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11415 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11416 * <li>options {Object} The parameter to the request call.</li>
11417 * <li>success {Boolean} True if the request succeeded.</li>
11418 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11420 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11421 * The callback is passed the following parameters:<ul>
11422 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11423 * <li>options {Object} The parameter to the request call.</li>
11425 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11426 * The callback is passed the following parameters:<ul>
11427 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11428 * <li>options {Object} The parameter to the request call.</li>
11430 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11431 * for the callback function. Defaults to the browser window.</li>
11432 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11433 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11434 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11435 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11436 * params for the post data. Any params will be appended to the URL.</li>
11437 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11439 * @return {Number} transactionId
11441 request : function(o){
11442 if(this.fireEvent("beforerequest", this, o) !== false){
11445 if(typeof p == "function"){
11446 p = p.call(o.scope||window, o);
11448 if(typeof p == "object"){
11449 p = Roo.urlEncode(o.params);
11451 if(this.extraParams){
11452 var extras = Roo.urlEncode(this.extraParams);
11453 p = p ? (p + '&' + extras) : extras;
11456 var url = o.url || this.url;
11457 if(typeof url == 'function'){
11458 url = url.call(o.scope||window, o);
11462 var form = Roo.getDom(o.form);
11463 url = url || form.action;
11465 var enctype = form.getAttribute("enctype");
11466 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11467 return this.doFormUpload(o, p, url);
11469 var f = Roo.lib.Ajax.serializeForm(form);
11470 p = p ? (p + '&' + f) : f;
11473 var hs = o.headers;
11474 if(this.defaultHeaders){
11475 hs = Roo.apply(hs || {}, this.defaultHeaders);
11482 success: this.handleResponse,
11483 failure: this.handleFailure,
11485 argument: {options: o},
11486 timeout : o.timeout || this.timeout
11489 var method = o.method||this.method||(p ? "POST" : "GET");
11491 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11492 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11495 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11499 }else if(this.autoAbort !== false){
11503 if((method == 'GET' && p) || o.xmlData){
11504 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11507 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11508 return this.transId;
11510 Roo.callback(o.callback, o.scope, [o, null, null]);
11516 * Determine whether this object has a request outstanding.
11517 * @param {Number} transactionId (Optional) defaults to the last transaction
11518 * @return {Boolean} True if there is an outstanding request.
11520 isLoading : function(transId){
11522 return Roo.lib.Ajax.isCallInProgress(transId);
11524 return this.transId ? true : false;
11529 * Aborts any outstanding request.
11530 * @param {Number} transactionId (Optional) defaults to the last transaction
11532 abort : function(transId){
11533 if(transId || this.isLoading()){
11534 Roo.lib.Ajax.abort(transId || this.transId);
11539 handleResponse : function(response){
11540 this.transId = false;
11541 var options = response.argument.options;
11542 response.argument = options ? options.argument : null;
11543 this.fireEvent("requestcomplete", this, response, options);
11544 Roo.callback(options.success, options.scope, [response, options]);
11545 Roo.callback(options.callback, options.scope, [options, true, response]);
11549 handleFailure : function(response, e){
11550 this.transId = false;
11551 var options = response.argument.options;
11552 response.argument = options ? options.argument : null;
11553 this.fireEvent("requestexception", this, response, options, e);
11554 Roo.callback(options.failure, options.scope, [response, options]);
11555 Roo.callback(options.callback, options.scope, [options, false, response]);
11559 doFormUpload : function(o, ps, url){
11561 var frame = document.createElement('iframe');
11564 frame.className = 'x-hidden';
11566 frame.src = Roo.SSL_SECURE_URL;
11568 document.body.appendChild(frame);
11571 document.frames[id].name = id;
11574 var form = Roo.getDom(o.form);
11576 form.method = 'POST';
11577 form.enctype = form.encoding = 'multipart/form-data';
11583 if(ps){ // add dynamic params
11585 ps = Roo.urlDecode(ps, false);
11587 if(ps.hasOwnProperty(k)){
11588 hd = document.createElement('input');
11589 hd.type = 'hidden';
11592 form.appendChild(hd);
11599 var r = { // bogus response object
11604 r.argument = o ? o.argument : null;
11609 doc = frame.contentWindow.document;
11611 doc = (frame.contentDocument || window.frames[id].document);
11613 if(doc && doc.body){
11614 r.responseText = doc.body.innerHTML;
11616 if(doc && doc.XMLDocument){
11617 r.responseXML = doc.XMLDocument;
11619 r.responseXML = doc;
11626 Roo.EventManager.removeListener(frame, 'load', cb, this);
11628 this.fireEvent("requestcomplete", this, r, o);
11629 Roo.callback(o.success, o.scope, [r, o]);
11630 Roo.callback(o.callback, o.scope, [o, true, r]);
11632 setTimeout(function(){document.body.removeChild(frame);}, 100);
11635 Roo.EventManager.on(frame, 'load', cb, this);
11638 if(hiddens){ // remove dynamic params
11639 for(var i = 0, len = hiddens.length; i < len; i++){
11640 form.removeChild(hiddens[i]);
11647 * Ext JS Library 1.1.1
11648 * Copyright(c) 2006-2007, Ext JS, LLC.
11650 * Originally Released Under LGPL - original licence link has changed is not relivant.
11653 * <script type="text/javascript">
11657 * Global Ajax request class.
11660 * @extends Roo.data.Connection
11663 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11664 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11665 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11666 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
11667 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11668 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11669 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11671 Roo.Ajax = new Roo.data.Connection({
11680 * Serialize the passed form into a url encoded string
11682 * @param {String/HTMLElement} form
11685 serializeForm : function(form){
11686 return Roo.lib.Ajax.serializeForm(form);
11690 * Ext JS Library 1.1.1
11691 * Copyright(c) 2006-2007, Ext JS, LLC.
11693 * Originally Released Under LGPL - original licence link has changed is not relivant.
11696 * <script type="text/javascript">
11701 * @class Roo.UpdateManager
11702 * @extends Roo.util.Observable
11703 * Provides AJAX-style update for Element object.<br><br>
11706 * // Get it from a Roo.Element object
11707 * var el = Roo.get("foo");
11708 * var mgr = el.getUpdateManager();
11709 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11711 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11713 * // or directly (returns the same UpdateManager instance)
11714 * var mgr = new Roo.UpdateManager("myElementId");
11715 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11716 * mgr.on("update", myFcnNeedsToKnow);
11718 // short handed call directly from the element object
11719 Roo.get("foo").load({
11723 text: "Loading Foo..."
11727 * Create new UpdateManager directly.
11728 * @param {String/HTMLElement/Roo.Element} el The element to update
11729 * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
11731 Roo.UpdateManager = function(el, forceNew){
11733 if(!forceNew && el.updateManager){
11734 return el.updateManager;
11737 * The Element object
11738 * @type Roo.Element
11742 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11745 this.defaultUrl = null;
11749 * @event beforeupdate
11750 * Fired before an update is made, return false from your handler and the update is cancelled.
11751 * @param {Roo.Element} el
11752 * @param {String/Object/Function} url
11753 * @param {String/Object} params
11755 "beforeupdate": true,
11758 * Fired after successful update is made.
11759 * @param {Roo.Element} el
11760 * @param {Object} oResponseObject The response Object
11765 * Fired on update failure.
11766 * @param {Roo.Element} el
11767 * @param {Object} oResponseObject The response Object
11771 var d = Roo.UpdateManager.defaults;
11773 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11776 this.sslBlankUrl = d.sslBlankUrl;
11778 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11781 this.disableCaching = d.disableCaching;
11783 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11786 this.indicatorText = d.indicatorText;
11788 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11791 this.showLoadIndicator = d.showLoadIndicator;
11793 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11796 this.timeout = d.timeout;
11799 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11802 this.loadScripts = d.loadScripts;
11805 * Transaction object of current executing transaction
11807 this.transaction = null;
11812 this.autoRefreshProcId = null;
11814 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11817 this.refreshDelegate = this.refresh.createDelegate(this);
11819 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11822 this.updateDelegate = this.update.createDelegate(this);
11824 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11827 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11831 this.successDelegate = this.processSuccess.createDelegate(this);
11835 this.failureDelegate = this.processFailure.createDelegate(this);
11837 if(!this.renderer){
11839 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11841 this.renderer = new Roo.UpdateManager.BasicRenderer();
11844 Roo.UpdateManager.superclass.constructor.call(this);
11847 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11849 * Get the Element this UpdateManager is bound to
11850 * @return {Roo.Element} The element
11852 getEl : function(){
11856 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11857 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
11860 url: "your-url.php",<br/>
11861 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11862 callback: yourFunction,<br/>
11863 scope: yourObject, //(optional scope) <br/>
11864 discardUrl: false, <br/>
11865 nocache: false,<br/>
11866 text: "Loading...",<br/>
11868 scripts: false<br/>
11871 * The only required property is url. The optional properties nocache, text and scripts
11872 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11873 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
11874 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11875 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
11877 update : function(url, params, callback, discardUrl){
11878 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11879 var method = this.method,
11881 if(typeof url == "object"){ // must be config object
11884 params = params || cfg.params;
11885 callback = callback || cfg.callback;
11886 discardUrl = discardUrl || cfg.discardUrl;
11887 if(callback && cfg.scope){
11888 callback = callback.createDelegate(cfg.scope);
11890 if(typeof cfg.method != "undefined"){method = cfg.method;};
11891 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11892 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11893 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11894 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11896 this.showLoading();
11898 this.defaultUrl = url;
11900 if(typeof url == "function"){
11901 url = url.call(this);
11904 method = method || (params ? "POST" : "GET");
11905 if(method == "GET"){
11906 url = this.prepareUrl(url);
11909 var o = Roo.apply(cfg ||{}, {
11912 success: this.successDelegate,
11913 failure: this.failureDelegate,
11914 callback: undefined,
11915 timeout: (this.timeout*1000),
11916 argument: {"url": url, "form": null, "callback": callback, "params": params}
11918 Roo.log("updated manager called with timeout of " + o.timeout);
11919 this.transaction = Roo.Ajax.request(o);
11924 * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
11925 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11926 * @param {String/HTMLElement} form The form Id or form element
11927 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11928 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11929 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11931 formUpdate : function(form, url, reset, callback){
11932 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11933 if(typeof url == "function"){
11934 url = url.call(this);
11936 form = Roo.getDom(form);
11937 this.transaction = Roo.Ajax.request({
11940 success: this.successDelegate,
11941 failure: this.failureDelegate,
11942 timeout: (this.timeout*1000),
11943 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11945 this.showLoading.defer(1, this);
11950 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11951 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11953 refresh : function(callback){
11954 if(this.defaultUrl == null){
11957 this.update(this.defaultUrl, null, callback, true);
11961 * Set this element to auto refresh.
11962 * @param {Number} interval How often to update (in seconds).
11963 * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
11964 * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "¶m1=1¶m2=2" or as an object {param1: 1, param2: 2}
11965 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11966 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11968 startAutoRefresh : function(interval, url, params, callback, refreshNow){
11970 this.update(url || this.defaultUrl, params, callback, true);
11972 if(this.autoRefreshProcId){
11973 clearInterval(this.autoRefreshProcId);
11975 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11979 * Stop auto refresh on this element.
11981 stopAutoRefresh : function(){
11982 if(this.autoRefreshProcId){
11983 clearInterval(this.autoRefreshProcId);
11984 delete this.autoRefreshProcId;
11988 isAutoRefreshing : function(){
11989 return this.autoRefreshProcId ? true : false;
11992 * Called to update the element to "Loading" state. Override to perform custom action.
11994 showLoading : function(){
11995 if(this.showLoadIndicator){
11996 this.el.update(this.indicatorText);
12001 * Adds unique parameter to query string if disableCaching = true
12004 prepareUrl : function(url){
12005 if(this.disableCaching){
12006 var append = "_dc=" + (new Date().getTime());
12007 if(url.indexOf("?") !== -1){
12008 url += "&" + append;
12010 url += "?" + append;
12019 processSuccess : function(response){
12020 this.transaction = null;
12021 if(response.argument.form && response.argument.reset){
12022 try{ // put in try/catch since some older FF releases had problems with this
12023 response.argument.form.reset();
12026 if(this.loadScripts){
12027 this.renderer.render(this.el, response, this,
12028 this.updateComplete.createDelegate(this, [response]));
12030 this.renderer.render(this.el, response, this);
12031 this.updateComplete(response);
12035 updateComplete : function(response){
12036 this.fireEvent("update", this.el, response);
12037 if(typeof response.argument.callback == "function"){
12038 response.argument.callback(this.el, true, response);
12045 processFailure : function(response){
12046 this.transaction = null;
12047 this.fireEvent("failure", this.el, response);
12048 if(typeof response.argument.callback == "function"){
12049 response.argument.callback(this.el, false, response);
12054 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12055 * @param {Object} renderer The object implementing the render() method
12057 setRenderer : function(renderer){
12058 this.renderer = renderer;
12061 getRenderer : function(){
12062 return this.renderer;
12066 * Set the defaultUrl used for updates
12067 * @param {String/Function} defaultUrl The url or a function to call to get the url
12069 setDefaultUrl : function(defaultUrl){
12070 this.defaultUrl = defaultUrl;
12074 * Aborts the executing transaction
12076 abort : function(){
12077 if(this.transaction){
12078 Roo.Ajax.abort(this.transaction);
12083 * Returns true if an update is in progress
12084 * @return {Boolean}
12086 isUpdating : function(){
12087 if(this.transaction){
12088 return Roo.Ajax.isLoading(this.transaction);
12095 * @class Roo.UpdateManager.defaults
12096 * @static (not really - but it helps the doc tool)
12097 * The defaults collection enables customizing the default properties of UpdateManager
12099 Roo.UpdateManager.defaults = {
12101 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12107 * True to process scripts by default (Defaults to false).
12110 loadScripts : false,
12113 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12116 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12118 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12121 disableCaching : false,
12123 * Whether to show indicatorText when loading (Defaults to true).
12126 showLoadIndicator : true,
12128 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12131 indicatorText : '<div class="loading-indicator">Loading...</div>'
12135 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12137 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12138 * @param {String/HTMLElement/Roo.Element} el The element to update
12139 * @param {String} url The url
12140 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12141 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12144 * @member Roo.UpdateManager
12146 Roo.UpdateManager.updateElement = function(el, url, params, options){
12147 var um = Roo.get(el, true).getUpdateManager();
12148 Roo.apply(um, options);
12149 um.update(url, params, options ? options.callback : null);
12151 // alias for backwards compat
12152 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12154 * @class Roo.UpdateManager.BasicRenderer
12155 * Default Content renderer. Updates the elements innerHTML with the responseText.
12157 Roo.UpdateManager.BasicRenderer = function(){};
12159 Roo.UpdateManager.BasicRenderer.prototype = {
12161 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12162 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12163 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12164 * @param {Roo.Element} el The element being rendered
12165 * @param {Object} response The YUI Connect response object
12166 * @param {UpdateManager} updateManager The calling update manager
12167 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12169 render : function(el, response, updateManager, callback){
12170 el.update(response.responseText, updateManager.loadScripts, callback);
12176 * (c)) Alan Knowles
12182 * @class Roo.DomTemplate
12183 * @extends Roo.Template
12184 * An effort at a dom based template engine..
12186 * Similar to XTemplate, except it uses dom parsing to create the template..
12188 * Supported features:
12193 {a_variable} - output encoded.
12194 {a_variable.format:("Y-m-d")} - call a method on the variable
12195 {a_variable:raw} - unencoded output
12196 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12197 {a_variable:this.method_on_template(...)} - call a method on the template object.
12202 <div roo-for="a_variable or condition.."></div>
12203 <div roo-if="a_variable or condition"></div>
12204 <div roo-exec="some javascript"></div>
12205 <div roo-name="named_template"></div>
12210 Roo.DomTemplate = function()
12212 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12219 Roo.extend(Roo.DomTemplate, Roo.Template, {
12221 * id counter for sub templates.
12225 * flag to indicate if dom parser is inside a pre,
12226 * it will strip whitespace if not.
12231 * The various sub templates
12239 * basic tag replacing syntax
12242 * // you can fake an object call by doing this
12246 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12247 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12249 iterChild : function (node, method) {
12251 var oldPre = this.inPre;
12252 if (node.tagName == 'PRE') {
12255 for( var i = 0; i < node.childNodes.length; i++) {
12256 method.call(this, node.childNodes[i]);
12258 this.inPre = oldPre;
12264 * compile the template
12266 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12269 compile: function()
12273 // covert the html into DOM...
12277 doc = document.implementation.createHTMLDocument("");
12278 doc.documentElement.innerHTML = this.html ;
12279 div = doc.documentElement;
12281 // old IE... - nasty -- it causes all sorts of issues.. with
12282 // images getting pulled from server..
12283 div = document.createElement('div');
12284 div.innerHTML = this.html;
12286 //doc.documentElement.innerHTML = htmlBody
12292 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12294 var tpls = this.tpls;
12296 // create a top level template from the snippet..
12298 //Roo.log(div.innerHTML);
12305 body : div.innerHTML,
12318 Roo.each(tpls, function(tp){
12319 this.compileTpl(tp);
12320 this.tpls[tp.id] = tp;
12323 this.master = tpls[0];
12329 compileNode : function(node, istop) {
12334 // skip anything not a tag..
12335 if (node.nodeType != 1) {
12336 if (node.nodeType == 3 && !this.inPre) {
12337 // reduce white space..
12338 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12361 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12362 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12363 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12364 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12370 // just itterate children..
12371 this.iterChild(node,this.compileNode);
12374 tpl.uid = this.id++;
12375 tpl.value = node.getAttribute('roo-' + tpl.attr);
12376 node.removeAttribute('roo-'+ tpl.attr);
12377 if (tpl.attr != 'name') {
12378 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12379 node.parentNode.replaceChild(placeholder, node);
12382 var placeholder = document.createElement('span');
12383 placeholder.className = 'roo-tpl-' + tpl.value;
12384 node.parentNode.replaceChild(placeholder, node);
12387 // parent now sees '{domtplXXXX}
12388 this.iterChild(node,this.compileNode);
12390 // we should now have node body...
12391 var div = document.createElement('div');
12392 div.appendChild(node);
12394 // this has the unfortunate side effect of converting tagged attributes
12395 // eg. href="{...}" into %7C...%7D
12396 // this has been fixed by searching for those combo's although it's a bit hacky..
12399 tpl.body = div.innerHTML;
12406 switch (tpl.value) {
12407 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12408 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12409 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12414 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12418 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12422 tpl.id = tpl.value; // replace non characters???
12428 this.tpls.push(tpl);
12438 * Compile a segment of the template into a 'sub-template'
12444 compileTpl : function(tpl)
12446 var fm = Roo.util.Format;
12447 var useF = this.disableFormats !== true;
12449 var sep = Roo.isGecko ? "+\n" : ",\n";
12451 var undef = function(str) {
12452 Roo.debug && Roo.log("Property not found :" + str);
12456 //Roo.log(tpl.body);
12460 var fn = function(m, lbrace, name, format, args)
12463 //Roo.log(arguments);
12464 args = args ? args.replace(/\\'/g,"'") : args;
12465 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12466 if (typeof(format) == 'undefined') {
12467 format = 'htmlEncode';
12469 if (format == 'raw' ) {
12473 if(name.substr(0, 6) == 'domtpl'){
12474 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12477 // build an array of options to determine if value is undefined..
12479 // basically get 'xxxx.yyyy' then do
12480 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12481 // (function () { Roo.log("Property not found"); return ''; })() :
12486 Roo.each(name.split('.'), function(st) {
12487 lookfor += (lookfor.length ? '.': '') + st;
12488 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12491 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12494 if(format && useF){
12496 args = args ? ',' + args : "";
12498 if(format.substr(0, 5) != "this."){
12499 format = "fm." + format + '(';
12501 format = 'this.call("'+ format.substr(5) + '", ';
12505 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12508 if (args && args.length) {
12509 // called with xxyx.yuu:(test,test)
12511 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12513 // raw.. - :raw modifier..
12514 return "'"+ sep + udef_st + name + ")"+sep+"'";
12518 // branched to use + in gecko and [].join() in others
12520 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12521 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12524 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12525 body.push(tpl.body.replace(/(\r\n|\n)/g,
12526 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12527 body.push("'].join('');};};");
12528 body = body.join('');
12531 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12533 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12540 * same as applyTemplate, except it's done to one of the subTemplates
12541 * when using named templates, you can do:
12543 * var str = pl.applySubTemplate('your-name', values);
12546 * @param {Number} id of the template
12547 * @param {Object} values to apply to template
12548 * @param {Object} parent (normaly the instance of this object)
12550 applySubTemplate : function(id, values, parent)
12554 var t = this.tpls[id];
12558 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12559 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12563 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12570 if(t.execCall && t.execCall.call(this, values, parent)){
12574 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12580 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12581 parent = t.target ? values : parent;
12582 if(t.forCall && vs instanceof Array){
12584 for(var i = 0, len = vs.length; i < len; i++){
12586 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12588 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12590 //Roo.log(t.compiled);
12594 return buf.join('');
12597 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12602 return t.compiled.call(this, vs, parent);
12604 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12606 //Roo.log(t.compiled);
12614 applyTemplate : function(values){
12615 return this.master.compiled.call(this, values, {});
12616 //var s = this.subs;
12619 apply : function(){
12620 return this.applyTemplate.apply(this, arguments);
12625 Roo.DomTemplate.from = function(el){
12626 el = Roo.getDom(el);
12627 return new Roo.Domtemplate(el.value || el.innerHTML);
12630 * Ext JS Library 1.1.1
12631 * Copyright(c) 2006-2007, Ext JS, LLC.
12633 * Originally Released Under LGPL - original licence link has changed is not relivant.
12636 * <script type="text/javascript">
12640 * @class Roo.util.DelayedTask
12641 * Provides a convenient method of performing setTimeout where a new
12642 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12643 * You can use this class to buffer
12644 * the keypress events for a certain number of milliseconds, and perform only if they stop
12645 * for that amount of time.
12646 * @constructor The parameters to this constructor serve as defaults and are not required.
12647 * @param {Function} fn (optional) The default function to timeout
12648 * @param {Object} scope (optional) The default scope of that timeout
12649 * @param {Array} args (optional) The default Array of arguments
12651 Roo.util.DelayedTask = function(fn, scope, args){
12652 var id = null, d, t;
12654 var call = function(){
12655 var now = new Date().getTime();
12659 fn.apply(scope, args || []);
12663 * Cancels any pending timeout and queues a new one
12664 * @param {Number} delay The milliseconds to delay
12665 * @param {Function} newFn (optional) Overrides function passed to constructor
12666 * @param {Object} newScope (optional) Overrides scope passed to constructor
12667 * @param {Array} newArgs (optional) Overrides args passed to constructor
12669 this.delay = function(delay, newFn, newScope, newArgs){
12670 if(id && delay != d){
12674 t = new Date().getTime();
12676 scope = newScope || scope;
12677 args = newArgs || args;
12679 id = setInterval(call, d);
12684 * Cancel the last queued timeout
12686 this.cancel = function(){
12694 * Ext JS Library 1.1.1
12695 * Copyright(c) 2006-2007, Ext JS, LLC.
12697 * Originally Released Under LGPL - original licence link has changed is not relivant.
12700 * <script type="text/javascript">
12704 Roo.util.TaskRunner = function(interval){
12705 interval = interval || 10;
12706 var tasks = [], removeQueue = [];
12708 var running = false;
12710 var stopThread = function(){
12716 var startThread = function(){
12719 id = setInterval(runTasks, interval);
12723 var removeTask = function(task){
12724 removeQueue.push(task);
12730 var runTasks = function(){
12731 if(removeQueue.length > 0){
12732 for(var i = 0, len = removeQueue.length; i < len; i++){
12733 tasks.remove(removeQueue[i]);
12736 if(tasks.length < 1){
12741 var now = new Date().getTime();
12742 for(var i = 0, len = tasks.length; i < len; ++i){
12744 var itime = now - t.taskRunTime;
12745 if(t.interval <= itime){
12746 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12747 t.taskRunTime = now;
12748 if(rt === false || t.taskRunCount === t.repeat){
12753 if(t.duration && t.duration <= (now - t.taskStartTime)){
12760 * Queues a new task.
12761 * @param {Object} task
12763 this.start = function(task){
12765 task.taskStartTime = new Date().getTime();
12766 task.taskRunTime = 0;
12767 task.taskRunCount = 0;
12772 this.stop = function(task){
12777 this.stopAll = function(){
12779 for(var i = 0, len = tasks.length; i < len; i++){
12780 if(tasks[i].onStop){
12789 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12791 * Ext JS Library 1.1.1
12792 * Copyright(c) 2006-2007, Ext JS, LLC.
12794 * Originally Released Under LGPL - original licence link has changed is not relivant.
12797 * <script type="text/javascript">
12802 * @class Roo.util.MixedCollection
12803 * @extends Roo.util.Observable
12804 * A Collection class that maintains both numeric indexes and keys and exposes events.
12806 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12807 * collection (defaults to false)
12808 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12809 * and return the key value for that item. This is used when available to look up the key on items that
12810 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12811 * equivalent to providing an implementation for the {@link #getKey} method.
12813 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12821 * Fires when the collection is cleared.
12826 * Fires when an item is added to the collection.
12827 * @param {Number} index The index at which the item was added.
12828 * @param {Object} o The item added.
12829 * @param {String} key The key associated with the added item.
12834 * Fires when an item is replaced in the collection.
12835 * @param {String} key he key associated with the new added.
12836 * @param {Object} old The item being replaced.
12837 * @param {Object} new The new item.
12842 * Fires when an item is removed from the collection.
12843 * @param {Object} o The item being removed.
12844 * @param {String} key (optional) The key associated with the removed item.
12849 this.allowFunctions = allowFunctions === true;
12851 this.getKey = keyFn;
12853 Roo.util.MixedCollection.superclass.constructor.call(this);
12856 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12857 allowFunctions : false,
12860 * Adds an item to the collection.
12861 * @param {String} key The key to associate with the item
12862 * @param {Object} o The item to add.
12863 * @return {Object} The item added.
12865 add : function(key, o){
12866 if(arguments.length == 1){
12868 key = this.getKey(o);
12870 if(typeof key == "undefined" || key === null){
12872 this.items.push(o);
12873 this.keys.push(null);
12875 var old = this.map[key];
12877 return this.replace(key, o);
12880 this.items.push(o);
12882 this.keys.push(key);
12884 this.fireEvent("add", this.length-1, o, key);
12889 * MixedCollection has a generic way to fetch keys if you implement getKey.
12892 var mc = new Roo.util.MixedCollection();
12893 mc.add(someEl.dom.id, someEl);
12894 mc.add(otherEl.dom.id, otherEl);
12898 var mc = new Roo.util.MixedCollection();
12899 mc.getKey = function(el){
12905 // or via the constructor
12906 var mc = new Roo.util.MixedCollection(false, function(el){
12912 * @param o {Object} The item for which to find the key.
12913 * @return {Object} The key for the passed item.
12915 getKey : function(o){
12920 * Replaces an item in the collection.
12921 * @param {String} key The key associated with the item to replace, or the item to replace.
12922 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12923 * @return {Object} The new item.
12925 replace : function(key, o){
12926 if(arguments.length == 1){
12928 key = this.getKey(o);
12930 var old = this.item(key);
12931 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12932 return this.add(key, o);
12934 var index = this.indexOfKey(key);
12935 this.items[index] = o;
12937 this.fireEvent("replace", key, old, o);
12942 * Adds all elements of an Array or an Object to the collection.
12943 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12944 * an Array of values, each of which are added to the collection.
12946 addAll : function(objs){
12947 if(arguments.length > 1 || objs instanceof Array){
12948 var args = arguments.length > 1 ? arguments : objs;
12949 for(var i = 0, len = args.length; i < len; i++){
12953 for(var key in objs){
12954 if(this.allowFunctions || typeof objs[key] != "function"){
12955 this.add(key, objs[key]);
12962 * Executes the specified function once for every item in the collection, passing each
12963 * item as the first and only parameter. returning false from the function will stop the iteration.
12964 * @param {Function} fn The function to execute for each item.
12965 * @param {Object} scope (optional) The scope in which to execute the function.
12967 each : function(fn, scope){
12968 var items = [].concat(this.items); // each safe for removal
12969 for(var i = 0, len = items.length; i < len; i++){
12970 if(fn.call(scope || items[i], items[i], i, len) === false){
12977 * Executes the specified function once for every key in the collection, passing each
12978 * key, and its associated item as the first two parameters.
12979 * @param {Function} fn The function to execute for each item.
12980 * @param {Object} scope (optional) The scope in which to execute the function.
12982 eachKey : function(fn, scope){
12983 for(var i = 0, len = this.keys.length; i < len; i++){
12984 fn.call(scope || window, this.keys[i], this.items[i], i, len);
12989 * Returns the first item in the collection which elicits a true return value from the
12990 * passed selection function.
12991 * @param {Function} fn The selection function to execute for each item.
12992 * @param {Object} scope (optional) The scope in which to execute the function.
12993 * @return {Object} The first item in the collection which returned true from the selection function.
12995 find : function(fn, scope){
12996 for(var i = 0, len = this.items.length; i < len; i++){
12997 if(fn.call(scope || window, this.items[i], this.keys[i])){
12998 return this.items[i];
13005 * Inserts an item at the specified index in the collection.
13006 * @param {Number} index The index to insert the item at.
13007 * @param {String} key The key to associate with the new item, or the item itself.
13008 * @param {Object} o (optional) If the second parameter was a key, the new item.
13009 * @return {Object} The item inserted.
13011 insert : function(index, key, o){
13012 if(arguments.length == 2){
13014 key = this.getKey(o);
13016 if(index >= this.length){
13017 return this.add(key, o);
13020 this.items.splice(index, 0, o);
13021 if(typeof key != "undefined" && key != null){
13024 this.keys.splice(index, 0, key);
13025 this.fireEvent("add", index, o, key);
13030 * Removed an item from the collection.
13031 * @param {Object} o The item to remove.
13032 * @return {Object} The item removed.
13034 remove : function(o){
13035 return this.removeAt(this.indexOf(o));
13039 * Remove an item from a specified index in the collection.
13040 * @param {Number} index The index within the collection of the item to remove.
13042 removeAt : function(index){
13043 if(index < this.length && index >= 0){
13045 var o = this.items[index];
13046 this.items.splice(index, 1);
13047 var key = this.keys[index];
13048 if(typeof key != "undefined"){
13049 delete this.map[key];
13051 this.keys.splice(index, 1);
13052 this.fireEvent("remove", o, key);
13057 * Removed an item associated with the passed key fom the collection.
13058 * @param {String} key The key of the item to remove.
13060 removeKey : function(key){
13061 return this.removeAt(this.indexOfKey(key));
13065 * Returns the number of items in the collection.
13066 * @return {Number} the number of items in the collection.
13068 getCount : function(){
13069 return this.length;
13073 * Returns index within the collection of the passed Object.
13074 * @param {Object} o The item to find the index of.
13075 * @return {Number} index of the item.
13077 indexOf : function(o){
13078 if(!this.items.indexOf){
13079 for(var i = 0, len = this.items.length; i < len; i++){
13080 if(this.items[i] == o) return i;
13084 return this.items.indexOf(o);
13089 * Returns index within the collection of the passed key.
13090 * @param {String} key The key to find the index of.
13091 * @return {Number} index of the key.
13093 indexOfKey : function(key){
13094 if(!this.keys.indexOf){
13095 for(var i = 0, len = this.keys.length; i < len; i++){
13096 if(this.keys[i] == key) return i;
13100 return this.keys.indexOf(key);
13105 * Returns the item associated with the passed key OR index. Key has priority over index.
13106 * @param {String/Number} key The key or index of the item.
13107 * @return {Object} The item associated with the passed key.
13109 item : function(key){
13110 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13111 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13115 * Returns the item at the specified index.
13116 * @param {Number} index The index of the item.
13119 itemAt : function(index){
13120 return this.items[index];
13124 * Returns the item associated with the passed key.
13125 * @param {String/Number} key The key of the item.
13126 * @return {Object} The item associated with the passed key.
13128 key : function(key){
13129 return this.map[key];
13133 * Returns true if the collection contains the passed Object as an item.
13134 * @param {Object} o The Object to look for in the collection.
13135 * @return {Boolean} True if the collection contains the Object as an item.
13137 contains : function(o){
13138 return this.indexOf(o) != -1;
13142 * Returns true if the collection contains the passed Object as a key.
13143 * @param {String} key The key to look for in the collection.
13144 * @return {Boolean} True if the collection contains the Object as a key.
13146 containsKey : function(key){
13147 return typeof this.map[key] != "undefined";
13151 * Removes all items from the collection.
13153 clear : function(){
13158 this.fireEvent("clear");
13162 * Returns the first item in the collection.
13163 * @return {Object} the first item in the collection..
13165 first : function(){
13166 return this.items[0];
13170 * Returns the last item in the collection.
13171 * @return {Object} the last item in the collection..
13174 return this.items[this.length-1];
13177 _sort : function(property, dir, fn){
13178 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13179 fn = fn || function(a, b){
13182 var c = [], k = this.keys, items = this.items;
13183 for(var i = 0, len = items.length; i < len; i++){
13184 c[c.length] = {key: k[i], value: items[i], index: i};
13186 c.sort(function(a, b){
13187 var v = fn(a[property], b[property]) * dsc;
13189 v = (a.index < b.index ? -1 : 1);
13193 for(var i = 0, len = c.length; i < len; i++){
13194 items[i] = c[i].value;
13197 this.fireEvent("sort", this);
13201 * Sorts this collection with the passed comparison function
13202 * @param {String} direction (optional) "ASC" or "DESC"
13203 * @param {Function} fn (optional) comparison function
13205 sort : function(dir, fn){
13206 this._sort("value", dir, fn);
13210 * Sorts this collection by keys
13211 * @param {String} direction (optional) "ASC" or "DESC"
13212 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13214 keySort : function(dir, fn){
13215 this._sort("key", dir, fn || function(a, b){
13216 return String(a).toUpperCase()-String(b).toUpperCase();
13221 * Returns a range of items in this collection
13222 * @param {Number} startIndex (optional) defaults to 0
13223 * @param {Number} endIndex (optional) default to the last item
13224 * @return {Array} An array of items
13226 getRange : function(start, end){
13227 var items = this.items;
13228 if(items.length < 1){
13231 start = start || 0;
13232 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13235 for(var i = start; i <= end; i++) {
13236 r[r.length] = items[i];
13239 for(var i = start; i >= end; i--) {
13240 r[r.length] = items[i];
13247 * Filter the <i>objects</i> in this collection by a specific property.
13248 * Returns a new collection that has been filtered.
13249 * @param {String} property A property on your objects
13250 * @param {String/RegExp} value Either string that the property values
13251 * should start with or a RegExp to test against the property
13252 * @return {MixedCollection} The new filtered collection
13254 filter : function(property, value){
13255 if(!value.exec){ // not a regex
13256 value = String(value);
13257 if(value.length == 0){
13258 return this.clone();
13260 value = new RegExp("^" + Roo.escapeRe(value), "i");
13262 return this.filterBy(function(o){
13263 return o && value.test(o[property]);
13268 * Filter by a function. * Returns a new collection that has been filtered.
13269 * The passed function will be called with each
13270 * object in the collection. If the function returns true, the value is included
13271 * otherwise it is filtered.
13272 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13273 * @param {Object} scope (optional) The scope of the function (defaults to this)
13274 * @return {MixedCollection} The new filtered collection
13276 filterBy : function(fn, scope){
13277 var r = new Roo.util.MixedCollection();
13278 r.getKey = this.getKey;
13279 var k = this.keys, it = this.items;
13280 for(var i = 0, len = it.length; i < len; i++){
13281 if(fn.call(scope||this, it[i], k[i])){
13282 r.add(k[i], it[i]);
13289 * Creates a duplicate of this collection
13290 * @return {MixedCollection}
13292 clone : function(){
13293 var r = new Roo.util.MixedCollection();
13294 var k = this.keys, it = this.items;
13295 for(var i = 0, len = it.length; i < len; i++){
13296 r.add(k[i], it[i]);
13298 r.getKey = this.getKey;
13303 * Returns the item associated with the passed key or index.
13305 * @param {String/Number} key The key or index of the item.
13306 * @return {Object} The item associated with the passed key.
13308 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13310 * Ext JS Library 1.1.1
13311 * Copyright(c) 2006-2007, Ext JS, LLC.
13313 * Originally Released Under LGPL - original licence link has changed is not relivant.
13316 * <script type="text/javascript">
13319 * @class Roo.util.JSON
13320 * Modified version of Douglas Crockford"s json.js that doesn"t
13321 * mess with the Object prototype
13322 * http://www.json.org/js.html
13325 Roo.util.JSON = new (function(){
13326 var useHasOwn = {}.hasOwnProperty ? true : false;
13328 // crashes Safari in some instances
13329 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13331 var pad = function(n) {
13332 return n < 10 ? "0" + n : n;
13345 var encodeString = function(s){
13346 if (/["\\\x00-\x1f]/.test(s)) {
13347 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13352 c = b.charCodeAt();
13354 Math.floor(c / 16).toString(16) +
13355 (c % 16).toString(16);
13358 return '"' + s + '"';
13361 var encodeArray = function(o){
13362 var a = ["["], b, i, l = o.length, v;
13363 for (i = 0; i < l; i += 1) {
13365 switch (typeof v) {
13374 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13382 var encodeDate = function(o){
13383 return '"' + o.getFullYear() + "-" +
13384 pad(o.getMonth() + 1) + "-" +
13385 pad(o.getDate()) + "T" +
13386 pad(o.getHours()) + ":" +
13387 pad(o.getMinutes()) + ":" +
13388 pad(o.getSeconds()) + '"';
13392 * Encodes an Object, Array or other value
13393 * @param {Mixed} o The variable to encode
13394 * @return {String} The JSON string
13396 this.encode = function(o)
13398 // should this be extended to fully wrap stringify..
13400 if(typeof o == "undefined" || o === null){
13402 }else if(o instanceof Array){
13403 return encodeArray(o);
13404 }else if(o instanceof Date){
13405 return encodeDate(o);
13406 }else if(typeof o == "string"){
13407 return encodeString(o);
13408 }else if(typeof o == "number"){
13409 return isFinite(o) ? String(o) : "null";
13410 }else if(typeof o == "boolean"){
13413 var a = ["{"], b, i, v;
13415 if(!useHasOwn || o.hasOwnProperty(i)) {
13417 switch (typeof v) {
13426 a.push(this.encode(i), ":",
13427 v === null ? "null" : this.encode(v));
13438 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13439 * @param {String} json The JSON string
13440 * @return {Object} The resulting object
13442 this.decode = function(json){
13444 return /** eval:var:json */ eval("(" + json + ')');
13448 * Shorthand for {@link Roo.util.JSON#encode}
13449 * @member Roo encode
13451 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13453 * Shorthand for {@link Roo.util.JSON#decode}
13454 * @member Roo decode
13456 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13459 * Ext JS Library 1.1.1
13460 * Copyright(c) 2006-2007, Ext JS, LLC.
13462 * Originally Released Under LGPL - original licence link has changed is not relivant.
13465 * <script type="text/javascript">
13469 * @class Roo.util.Format
13470 * Reusable data formatting functions
13473 Roo.util.Format = function(){
13474 var trimRe = /^\s+|\s+$/g;
13477 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13478 * @param {String} value The string to truncate
13479 * @param {Number} length The maximum length to allow before truncating
13480 * @return {String} The converted text
13482 ellipsis : function(value, len){
13483 if(value && value.length > len){
13484 return value.substr(0, len-3)+"...";
13490 * Checks a reference and converts it to empty string if it is undefined
13491 * @param {Mixed} value Reference to check
13492 * @return {Mixed} Empty string if converted, otherwise the original value
13494 undef : function(value){
13495 return typeof value != "undefined" ? value : "";
13499 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13500 * @param {String} value The string to encode
13501 * @return {String} The encoded text
13503 htmlEncode : function(value){
13504 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13508 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13509 * @param {String} value The string to decode
13510 * @return {String} The decoded text
13512 htmlDecode : function(value){
13513 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13517 * Trims any whitespace from either side of a string
13518 * @param {String} value The text to trim
13519 * @return {String} The trimmed text
13521 trim : function(value){
13522 return String(value).replace(trimRe, "");
13526 * Returns a substring from within an original string
13527 * @param {String} value The original text
13528 * @param {Number} start The start index of the substring
13529 * @param {Number} length The length of the substring
13530 * @return {String} The substring
13532 substr : function(value, start, length){
13533 return String(value).substr(start, length);
13537 * Converts a string to all lower case letters
13538 * @param {String} value The text to convert
13539 * @return {String} The converted text
13541 lowercase : function(value){
13542 return String(value).toLowerCase();
13546 * Converts a string to all upper case letters
13547 * @param {String} value The text to convert
13548 * @return {String} The converted text
13550 uppercase : function(value){
13551 return String(value).toUpperCase();
13555 * Converts the first character only of a string to upper case
13556 * @param {String} value The text to convert
13557 * @return {String} The converted text
13559 capitalize : function(value){
13560 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13564 call : function(value, fn){
13565 if(arguments.length > 2){
13566 var args = Array.prototype.slice.call(arguments, 2);
13567 args.unshift(value);
13569 return /** eval:var:value */ eval(fn).apply(window, args);
13571 /** eval:var:value */
13572 return /** eval:var:value */ eval(fn).call(window, value);
13578 * safer version of Math.toFixed..??/
13579 * @param {Number/String} value The numeric value to format
13580 * @param {Number/String} value Decimal places
13581 * @return {String} The formatted currency string
13583 toFixed : function(v, n)
13585 // why not use to fixed - precision is buggered???
13587 return Math.round(v-0);
13589 var fact = Math.pow(10,n+1);
13590 v = (Math.round((v-0)*fact))/fact;
13591 var z = (''+fact).substring(2);
13592 if (v == Math.floor(v)) {
13593 return Math.floor(v) + '.' + z;
13596 // now just padd decimals..
13597 var ps = String(v).split('.');
13598 var fd = (ps[1] + z);
13599 var r = fd.substring(0,n);
13600 var rm = fd.substring(n);
13602 return ps[0] + '.' + r;
13604 r*=1; // turn it into a number;
13606 if (String(r).length != n) {
13609 r = String(r).substring(1); // chop the end off.
13612 return ps[0] + '.' + r;
13617 * Format a number as US currency
13618 * @param {Number/String} value The numeric value to format
13619 * @return {String} The formatted currency string
13621 usMoney : function(v){
13622 return '$' + Roo.util.Format.number(v);
13627 * eventually this should probably emulate php's number_format
13628 * @param {Number/String} value The numeric value to format
13629 * @param {Number} decimals number of decimal places
13630 * @return {String} The formatted currency string
13632 number : function(v,decimals)
13634 // multiply and round.
13635 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13636 var mul = Math.pow(10, decimals);
13637 var zero = String(mul).substring(1);
13638 v = (Math.round((v-0)*mul))/mul;
13640 // if it's '0' number.. then
13642 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13644 var ps = v.split('.');
13648 var r = /(\d+)(\d{3})/;
13650 while (r.test(whole)) {
13651 whole = whole.replace(r, '$1' + ',' + '$2');
13657 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13658 // does not have decimals
13659 (decimals ? ('.' + zero) : '');
13662 return whole + sub ;
13666 * Parse a value into a formatted date using the specified format pattern.
13667 * @param {Mixed} value The value to format
13668 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13669 * @return {String} The formatted date string
13671 date : function(v, format){
13675 if(!(v instanceof Date)){
13676 v = new Date(Date.parse(v));
13678 return v.dateFormat(format || Roo.util.Format.defaults.date);
13682 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13683 * @param {String} format Any valid date format string
13684 * @return {Function} The date formatting function
13686 dateRenderer : function(format){
13687 return function(v){
13688 return Roo.util.Format.date(v, format);
13693 stripTagsRE : /<\/?[^>]+>/gi,
13696 * Strips all HTML tags
13697 * @param {Mixed} value The text from which to strip tags
13698 * @return {String} The stripped text
13700 stripTags : function(v){
13701 return !v ? v : String(v).replace(this.stripTagsRE, "");
13705 Roo.util.Format.defaults = {
13709 * Ext JS Library 1.1.1
13710 * Copyright(c) 2006-2007, Ext JS, LLC.
13712 * Originally Released Under LGPL - original licence link has changed is not relivant.
13715 * <script type="text/javascript">
13722 * @class Roo.MasterTemplate
13723 * @extends Roo.Template
13724 * Provides a template that can have child templates. The syntax is:
13726 var t = new Roo.MasterTemplate(
13727 '<select name="{name}">',
13728 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13731 t.add('options', {value: 'foo', text: 'bar'});
13732 // or you can add multiple child elements in one shot
13733 t.addAll('options', [
13734 {value: 'foo', text: 'bar'},
13735 {value: 'foo2', text: 'bar2'},
13736 {value: 'foo3', text: 'bar3'}
13738 // then append, applying the master template values
13739 t.append('my-form', {name: 'my-select'});
13741 * A name attribute for the child template is not required if you have only one child
13742 * template or you want to refer to them by index.
13744 Roo.MasterTemplate = function(){
13745 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13746 this.originalHtml = this.html;
13748 var m, re = this.subTemplateRe;
13751 while(m = re.exec(this.html)){
13752 var name = m[1], content = m[2];
13757 tpl : new Roo.Template(content)
13760 st[name] = st[subIndex];
13762 st[subIndex].tpl.compile();
13763 st[subIndex].tpl.call = this.call.createDelegate(this);
13766 this.subCount = subIndex;
13769 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13771 * The regular expression used to match sub templates
13775 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13778 * Applies the passed values to a child template.
13779 * @param {String/Number} name (optional) The name or index of the child template
13780 * @param {Array/Object} values The values to be applied to the template
13781 * @return {MasterTemplate} this
13783 add : function(name, values){
13784 if(arguments.length == 1){
13785 values = arguments[0];
13788 var s = this.subs[name];
13789 s.buffer[s.buffer.length] = s.tpl.apply(values);
13794 * Applies all the passed values to a child template.
13795 * @param {String/Number} name (optional) The name or index of the child template
13796 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13797 * @param {Boolean} reset (optional) True to reset the template first
13798 * @return {MasterTemplate} this
13800 fill : function(name, values, reset){
13802 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13810 for(var i = 0, len = values.length; i < len; i++){
13811 this.add(name, values[i]);
13817 * Resets the template for reuse
13818 * @return {MasterTemplate} this
13820 reset : function(){
13822 for(var i = 0; i < this.subCount; i++){
13828 applyTemplate : function(values){
13830 var replaceIndex = -1;
13831 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13832 return s[++replaceIndex].buffer.join("");
13834 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13837 apply : function(){
13838 return this.applyTemplate.apply(this, arguments);
13841 compile : function(){return this;}
13845 * Alias for fill().
13848 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13850 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13851 * var tpl = Roo.MasterTemplate.from('element-id');
13852 * @param {String/HTMLElement} el
13853 * @param {Object} config
13856 Roo.MasterTemplate.from = function(el, config){
13857 el = Roo.getDom(el);
13858 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13861 * Ext JS Library 1.1.1
13862 * Copyright(c) 2006-2007, Ext JS, LLC.
13864 * Originally Released Under LGPL - original licence link has changed is not relivant.
13867 * <script type="text/javascript">
13872 * @class Roo.util.CSS
13873 * Utility class for manipulating CSS rules
13876 Roo.util.CSS = function(){
13878 var doc = document;
13880 var camelRe = /(-[a-z])/gi;
13881 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13885 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
13886 * tag and appended to the HEAD of the document.
13887 * @param {String|Object} cssText The text containing the css rules
13888 * @param {String} id An id to add to the stylesheet for later removal
13889 * @return {StyleSheet}
13891 createStyleSheet : function(cssText, id){
13893 var head = doc.getElementsByTagName("head")[0];
13894 var nrules = doc.createElement("style");
13895 nrules.setAttribute("type", "text/css");
13897 nrules.setAttribute("id", id);
13899 if (typeof(cssText) != 'string') {
13900 // support object maps..
13901 // not sure if this a good idea..
13902 // perhaps it should be merged with the general css handling
13903 // and handle js style props.
13904 var cssTextNew = [];
13905 for(var n in cssText) {
13907 for(var k in cssText[n]) {
13908 citems.push( k + ' : ' +cssText[n][k] + ';' );
13910 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13913 cssText = cssTextNew.join("\n");
13919 head.appendChild(nrules);
13920 ss = nrules.styleSheet;
13921 ss.cssText = cssText;
13924 nrules.appendChild(doc.createTextNode(cssText));
13926 nrules.cssText = cssText;
13928 head.appendChild(nrules);
13929 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13931 this.cacheStyleSheet(ss);
13936 * Removes a style or link tag by id
13937 * @param {String} id The id of the tag
13939 removeStyleSheet : function(id){
13940 var existing = doc.getElementById(id);
13942 existing.parentNode.removeChild(existing);
13947 * Dynamically swaps an existing stylesheet reference for a new one
13948 * @param {String} id The id of an existing link tag to remove
13949 * @param {String} url The href of the new stylesheet to include
13951 swapStyleSheet : function(id, url){
13952 this.removeStyleSheet(id);
13953 var ss = doc.createElement("link");
13954 ss.setAttribute("rel", "stylesheet");
13955 ss.setAttribute("type", "text/css");
13956 ss.setAttribute("id", id);
13957 ss.setAttribute("href", url);
13958 doc.getElementsByTagName("head")[0].appendChild(ss);
13962 * Refresh the rule cache if you have dynamically added stylesheets
13963 * @return {Object} An object (hash) of rules indexed by selector
13965 refreshCache : function(){
13966 return this.getRules(true);
13970 cacheStyleSheet : function(stylesheet){
13974 try{// try catch for cross domain access issue
13975 var ssRules = stylesheet.cssRules || stylesheet.rules;
13976 for(var j = ssRules.length-1; j >= 0; --j){
13977 rules[ssRules[j].selectorText] = ssRules[j];
13983 * Gets all css rules for the document
13984 * @param {Boolean} refreshCache true to refresh the internal cache
13985 * @return {Object} An object (hash) of rules indexed by selector
13987 getRules : function(refreshCache){
13988 if(rules == null || refreshCache){
13990 var ds = doc.styleSheets;
13991 for(var i =0, len = ds.length; i < len; i++){
13993 this.cacheStyleSheet(ds[i]);
14001 * Gets an an individual CSS rule by selector(s)
14002 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14003 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14004 * @return {CSSRule} The CSS rule or null if one is not found
14006 getRule : function(selector, refreshCache){
14007 var rs = this.getRules(refreshCache);
14008 if(!(selector instanceof Array)){
14009 return rs[selector];
14011 for(var i = 0; i < selector.length; i++){
14012 if(rs[selector[i]]){
14013 return rs[selector[i]];
14021 * Updates a rule property
14022 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14023 * @param {String} property The css property
14024 * @param {String} value The new value for the property
14025 * @return {Boolean} true If a rule was found and updated
14027 updateRule : function(selector, property, value){
14028 if(!(selector instanceof Array)){
14029 var rule = this.getRule(selector);
14031 rule.style[property.replace(camelRe, camelFn)] = value;
14035 for(var i = 0; i < selector.length; i++){
14036 if(this.updateRule(selector[i], property, value)){
14046 * Ext JS Library 1.1.1
14047 * Copyright(c) 2006-2007, Ext JS, LLC.
14049 * Originally Released Under LGPL - original licence link has changed is not relivant.
14052 * <script type="text/javascript">
14058 * @class Roo.util.ClickRepeater
14059 * @extends Roo.util.Observable
14061 * A wrapper class which can be applied to any element. Fires a "click" event while the
14062 * mouse is pressed. The interval between firings may be specified in the config but
14063 * defaults to 10 milliseconds.
14065 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14067 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14068 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14069 * Similar to an autorepeat key delay.
14070 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14071 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14072 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14073 * "interval" and "delay" are ignored. "immediate" is honored.
14074 * @cfg {Boolean} preventDefault True to prevent the default click event
14075 * @cfg {Boolean} stopDefault True to stop the default click event
14078 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14079 * 2007-02-02 jvs Renamed to ClickRepeater
14080 * 2007-02-03 jvs Modifications for FF Mac and Safari
14083 * @param {String/HTMLElement/Element} el The element to listen on
14084 * @param {Object} config
14086 Roo.util.ClickRepeater = function(el, config)
14088 this.el = Roo.get(el);
14089 this.el.unselectable();
14091 Roo.apply(this, config);
14096 * Fires when the mouse button is depressed.
14097 * @param {Roo.util.ClickRepeater} this
14099 "mousedown" : true,
14102 * Fires on a specified interval during the time the element is pressed.
14103 * @param {Roo.util.ClickRepeater} this
14108 * Fires when the mouse key is released.
14109 * @param {Roo.util.ClickRepeater} this
14114 this.el.on("mousedown", this.handleMouseDown, this);
14115 if(this.preventDefault || this.stopDefault){
14116 this.el.on("click", function(e){
14117 if(this.preventDefault){
14118 e.preventDefault();
14120 if(this.stopDefault){
14126 // allow inline handler
14128 this.on("click", this.handler, this.scope || this);
14131 Roo.util.ClickRepeater.superclass.constructor.call(this);
14134 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14137 preventDefault : true,
14138 stopDefault : false,
14142 handleMouseDown : function(){
14143 clearTimeout(this.timer);
14145 if(this.pressClass){
14146 this.el.addClass(this.pressClass);
14148 this.mousedownTime = new Date();
14150 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14151 this.el.on("mouseout", this.handleMouseOut, this);
14153 this.fireEvent("mousedown", this);
14154 this.fireEvent("click", this);
14156 this.timer = this.click.defer(this.delay || this.interval, this);
14160 click : function(){
14161 this.fireEvent("click", this);
14162 this.timer = this.click.defer(this.getInterval(), this);
14166 getInterval: function(){
14167 if(!this.accelerate){
14168 return this.interval;
14170 var pressTime = this.mousedownTime.getElapsed();
14171 if(pressTime < 500){
14173 }else if(pressTime < 1700){
14175 }else if(pressTime < 2600){
14177 }else if(pressTime < 3500){
14179 }else if(pressTime < 4400){
14181 }else if(pressTime < 5300){
14183 }else if(pressTime < 6200){
14191 handleMouseOut : function(){
14192 clearTimeout(this.timer);
14193 if(this.pressClass){
14194 this.el.removeClass(this.pressClass);
14196 this.el.on("mouseover", this.handleMouseReturn, this);
14200 handleMouseReturn : function(){
14201 this.el.un("mouseover", this.handleMouseReturn);
14202 if(this.pressClass){
14203 this.el.addClass(this.pressClass);
14209 handleMouseUp : function(){
14210 clearTimeout(this.timer);
14211 this.el.un("mouseover", this.handleMouseReturn);
14212 this.el.un("mouseout", this.handleMouseOut);
14213 Roo.get(document).un("mouseup", this.handleMouseUp);
14214 this.el.removeClass(this.pressClass);
14215 this.fireEvent("mouseup", this);
14219 * Ext JS Library 1.1.1
14220 * Copyright(c) 2006-2007, Ext JS, LLC.
14222 * Originally Released Under LGPL - original licence link has changed is not relivant.
14225 * <script type="text/javascript">
14230 * @class Roo.KeyNav
14231 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14232 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14233 * way to implement custom navigation schemes for any UI component.</p>
14234 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14235 * pageUp, pageDown, del, home, end. Usage:</p>
14237 var nav = new Roo.KeyNav("my-element", {
14238 "left" : function(e){
14239 this.moveLeft(e.ctrlKey);
14241 "right" : function(e){
14242 this.moveRight(e.ctrlKey);
14244 "enter" : function(e){
14251 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14252 * @param {Object} config The config
14254 Roo.KeyNav = function(el, config){
14255 this.el = Roo.get(el);
14256 Roo.apply(this, config);
14257 if(!this.disabled){
14258 this.disabled = true;
14263 Roo.KeyNav.prototype = {
14265 * @cfg {Boolean} disabled
14266 * True to disable this KeyNav instance (defaults to false)
14270 * @cfg {String} defaultEventAction
14271 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14272 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14273 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14275 defaultEventAction: "stopEvent",
14277 * @cfg {Boolean} forceKeyDown
14278 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14279 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14280 * handle keydown instead of keypress.
14282 forceKeyDown : false,
14285 prepareEvent : function(e){
14286 var k = e.getKey();
14287 var h = this.keyToHandler[k];
14288 //if(h && this[h]){
14289 // e.stopPropagation();
14291 if(Roo.isSafari && h && k >= 37 && k <= 40){
14297 relay : function(e){
14298 var k = e.getKey();
14299 var h = this.keyToHandler[k];
14301 if(this.doRelay(e, this[h], h) !== true){
14302 e[this.defaultEventAction]();
14308 doRelay : function(e, h, hname){
14309 return h.call(this.scope || this, e);
14312 // possible handlers
14326 // quick lookup hash
14343 * Enable this KeyNav
14345 enable: function(){
14347 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14348 // the EventObject will normalize Safari automatically
14349 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14350 this.el.on("keydown", this.relay, this);
14352 this.el.on("keydown", this.prepareEvent, this);
14353 this.el.on("keypress", this.relay, this);
14355 this.disabled = false;
14360 * Disable this KeyNav
14362 disable: function(){
14363 if(!this.disabled){
14364 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14365 this.el.un("keydown", this.relay);
14367 this.el.un("keydown", this.prepareEvent);
14368 this.el.un("keypress", this.relay);
14370 this.disabled = true;
14375 * Ext JS Library 1.1.1
14376 * Copyright(c) 2006-2007, Ext JS, LLC.
14378 * Originally Released Under LGPL - original licence link has changed is not relivant.
14381 * <script type="text/javascript">
14386 * @class Roo.KeyMap
14387 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14388 * The constructor accepts the same config object as defined by {@link #addBinding}.
14389 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14390 * combination it will call the function with this signature (if the match is a multi-key
14391 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14392 * A KeyMap can also handle a string representation of keys.<br />
14395 // map one key by key code
14396 var map = new Roo.KeyMap("my-element", {
14397 key: 13, // or Roo.EventObject.ENTER
14402 // map multiple keys to one action by string
14403 var map = new Roo.KeyMap("my-element", {
14409 // map multiple keys to multiple actions by strings and array of codes
14410 var map = new Roo.KeyMap("my-element", [
14413 fn: function(){ alert("Return was pressed"); }
14416 fn: function(){ alert('a, b or c was pressed'); }
14421 fn: function(){ alert('Control + shift + tab was pressed.'); }
14425 * <b>Note: A KeyMap starts enabled</b>
14427 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14428 * @param {Object} config The config (see {@link #addBinding})
14429 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14431 Roo.KeyMap = function(el, config, eventName){
14432 this.el = Roo.get(el);
14433 this.eventName = eventName || "keydown";
14434 this.bindings = [];
14436 this.addBinding(config);
14441 Roo.KeyMap.prototype = {
14443 * True to stop the event from bubbling and prevent the default browser action if the
14444 * key was handled by the KeyMap (defaults to false)
14450 * Add a new binding to this KeyMap. The following config object properties are supported:
14452 Property Type Description
14453 ---------- --------------- ----------------------------------------------------------------------
14454 key String/Array A single keycode or an array of keycodes to handle
14455 shift Boolean True to handle key only when shift is pressed (defaults to false)
14456 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14457 alt Boolean True to handle key only when alt is pressed (defaults to false)
14458 fn Function The function to call when KeyMap finds the expected key combination
14459 scope Object The scope of the callback function
14465 var map = new Roo.KeyMap(document, {
14466 key: Roo.EventObject.ENTER,
14471 //Add a new binding to the existing KeyMap later
14479 * @param {Object/Array} config A single KeyMap config or an array of configs
14481 addBinding : function(config){
14482 if(config instanceof Array){
14483 for(var i = 0, len = config.length; i < len; i++){
14484 this.addBinding(config[i]);
14488 var keyCode = config.key,
14489 shift = config.shift,
14490 ctrl = config.ctrl,
14493 scope = config.scope;
14494 if(typeof keyCode == "string"){
14496 var keyString = keyCode.toUpperCase();
14497 for(var j = 0, len = keyString.length; j < len; j++){
14498 ks.push(keyString.charCodeAt(j));
14502 var keyArray = keyCode instanceof Array;
14503 var handler = function(e){
14504 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14505 var k = e.getKey();
14507 for(var i = 0, len = keyCode.length; i < len; i++){
14508 if(keyCode[i] == k){
14509 if(this.stopEvent){
14512 fn.call(scope || window, k, e);
14518 if(this.stopEvent){
14521 fn.call(scope || window, k, e);
14526 this.bindings.push(handler);
14530 * Shorthand for adding a single key listener
14531 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14532 * following options:
14533 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14534 * @param {Function} fn The function to call
14535 * @param {Object} scope (optional) The scope of the function
14537 on : function(key, fn, scope){
14538 var keyCode, shift, ctrl, alt;
14539 if(typeof key == "object" && !(key instanceof Array)){
14558 handleKeyDown : function(e){
14559 if(this.enabled){ //just in case
14560 var b = this.bindings;
14561 for(var i = 0, len = b.length; i < len; i++){
14562 b[i].call(this, e);
14568 * Returns true if this KeyMap is enabled
14569 * @return {Boolean}
14571 isEnabled : function(){
14572 return this.enabled;
14576 * Enables this KeyMap
14578 enable: function(){
14580 this.el.on(this.eventName, this.handleKeyDown, this);
14581 this.enabled = true;
14586 * Disable this KeyMap
14588 disable: function(){
14590 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14591 this.enabled = false;
14596 * Ext JS Library 1.1.1
14597 * Copyright(c) 2006-2007, Ext JS, LLC.
14599 * Originally Released Under LGPL - original licence link has changed is not relivant.
14602 * <script type="text/javascript">
14607 * @class Roo.util.TextMetrics
14608 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14609 * wide, in pixels, a given block of text will be.
14612 Roo.util.TextMetrics = function(){
14616 * Measures the size of the specified text
14617 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14618 * that can affect the size of the rendered text
14619 * @param {String} text The text to measure
14620 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14621 * in order to accurately measure the text height
14622 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14624 measure : function(el, text, fixedWidth){
14626 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14629 shared.setFixedWidth(fixedWidth || 'auto');
14630 return shared.getSize(text);
14634 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14635 * the overhead of multiple calls to initialize the style properties on each measurement.
14636 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14637 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14638 * in order to accurately measure the text height
14639 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14641 createInstance : function(el, fixedWidth){
14642 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14649 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14650 var ml = new Roo.Element(document.createElement('div'));
14651 document.body.appendChild(ml.dom);
14652 ml.position('absolute');
14653 ml.setLeftTop(-1000, -1000);
14657 ml.setWidth(fixedWidth);
14662 * Returns the size of the specified text based on the internal element's style and width properties
14663 * @memberOf Roo.util.TextMetrics.Instance#
14664 * @param {String} text The text to measure
14665 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14667 getSize : function(text){
14669 var s = ml.getSize();
14675 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14676 * that can affect the size of the rendered text
14677 * @memberOf Roo.util.TextMetrics.Instance#
14678 * @param {String/HTMLElement} el The element, dom node or id
14680 bind : function(el){
14682 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14687 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14688 * to set a fixed width in order to accurately measure the text height.
14689 * @memberOf Roo.util.TextMetrics.Instance#
14690 * @param {Number} width The width to set on the element
14692 setFixedWidth : function(width){
14693 ml.setWidth(width);
14697 * Returns the measured width of the specified text
14698 * @memberOf Roo.util.TextMetrics.Instance#
14699 * @param {String} text The text to measure
14700 * @return {Number} width The width in pixels
14702 getWidth : function(text){
14703 ml.dom.style.width = 'auto';
14704 return this.getSize(text).width;
14708 * Returns the measured height of the specified text. For multiline text, be sure to call
14709 * {@link #setFixedWidth} if necessary.
14710 * @memberOf Roo.util.TextMetrics.Instance#
14711 * @param {String} text The text to measure
14712 * @return {Number} height The height in pixels
14714 getHeight : function(text){
14715 return this.getSize(text).height;
14719 instance.bind(bindTo);
14724 // backwards compat
14725 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14727 * Ext JS Library 1.1.1
14728 * Copyright(c) 2006-2007, Ext JS, LLC.
14730 * Originally Released Under LGPL - original licence link has changed is not relivant.
14733 * <script type="text/javascript">
14737 * @class Roo.state.Provider
14738 * Abstract base class for state provider implementations. This class provides methods
14739 * for encoding and decoding <b>typed</b> variables including dates and defines the
14740 * Provider interface.
14742 Roo.state.Provider = function(){
14744 * @event statechange
14745 * Fires when a state change occurs.
14746 * @param {Provider} this This state provider
14747 * @param {String} key The state key which was changed
14748 * @param {String} value The encoded value for the state
14751 "statechange": true
14754 Roo.state.Provider.superclass.constructor.call(this);
14756 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14758 * Returns the current value for a key
14759 * @param {String} name The key name
14760 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14761 * @return {Mixed} The state data
14763 get : function(name, defaultValue){
14764 return typeof this.state[name] == "undefined" ?
14765 defaultValue : this.state[name];
14769 * Clears a value from the state
14770 * @param {String} name The key name
14772 clear : function(name){
14773 delete this.state[name];
14774 this.fireEvent("statechange", this, name, null);
14778 * Sets the value for a key
14779 * @param {String} name The key name
14780 * @param {Mixed} value The value to set
14782 set : function(name, value){
14783 this.state[name] = value;
14784 this.fireEvent("statechange", this, name, value);
14788 * Decodes a string previously encoded with {@link #encodeValue}.
14789 * @param {String} value The value to decode
14790 * @return {Mixed} The decoded value
14792 decodeValue : function(cookie){
14793 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14794 var matches = re.exec(unescape(cookie));
14795 if(!matches || !matches[1]) return; // non state cookie
14796 var type = matches[1];
14797 var v = matches[2];
14800 return parseFloat(v);
14802 return new Date(Date.parse(v));
14807 var values = v.split("^");
14808 for(var i = 0, len = values.length; i < len; i++){
14809 all.push(this.decodeValue(values[i]));
14814 var values = v.split("^");
14815 for(var i = 0, len = values.length; i < len; i++){
14816 var kv = values[i].split("=");
14817 all[kv[0]] = this.decodeValue(kv[1]);
14826 * Encodes a value including type information. Decode with {@link #decodeValue}.
14827 * @param {Mixed} value The value to encode
14828 * @return {String} The encoded value
14830 encodeValue : function(v){
14832 if(typeof v == "number"){
14834 }else if(typeof v == "boolean"){
14835 enc = "b:" + (v ? "1" : "0");
14836 }else if(v instanceof Date){
14837 enc = "d:" + v.toGMTString();
14838 }else if(v instanceof Array){
14840 for(var i = 0, len = v.length; i < len; i++){
14841 flat += this.encodeValue(v[i]);
14842 if(i != len-1) flat += "^";
14845 }else if(typeof v == "object"){
14848 if(typeof v[key] != "function"){
14849 flat += key + "=" + this.encodeValue(v[key]) + "^";
14852 enc = "o:" + flat.substring(0, flat.length-1);
14856 return escape(enc);
14862 * Ext JS Library 1.1.1
14863 * Copyright(c) 2006-2007, Ext JS, LLC.
14865 * Originally Released Under LGPL - original licence link has changed is not relivant.
14868 * <script type="text/javascript">
14871 * @class Roo.state.Manager
14872 * This is the global state manager. By default all components that are "state aware" check this class
14873 * for state information if you don't pass them a custom state provider. In order for this class
14874 * to be useful, it must be initialized with a provider when your application initializes.
14876 // in your initialization function
14878 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14880 // supposed you have a {@link Roo.BorderLayout}
14881 var layout = new Roo.BorderLayout(...);
14882 layout.restoreState();
14883 // or a {Roo.BasicDialog}
14884 var dialog = new Roo.BasicDialog(...);
14885 dialog.restoreState();
14889 Roo.state.Manager = function(){
14890 var provider = new Roo.state.Provider();
14894 * Configures the default state provider for your application
14895 * @param {Provider} stateProvider The state provider to set
14897 setProvider : function(stateProvider){
14898 provider = stateProvider;
14902 * Returns the current value for a key
14903 * @param {String} name The key name
14904 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14905 * @return {Mixed} The state data
14907 get : function(key, defaultValue){
14908 return provider.get(key, defaultValue);
14912 * Sets the value for a key
14913 * @param {String} name The key name
14914 * @param {Mixed} value The state data
14916 set : function(key, value){
14917 provider.set(key, value);
14921 * Clears a value from the state
14922 * @param {String} name The key name
14924 clear : function(key){
14925 provider.clear(key);
14929 * Gets the currently configured state provider
14930 * @return {Provider} The state provider
14932 getProvider : function(){
14939 * Ext JS Library 1.1.1
14940 * Copyright(c) 2006-2007, Ext JS, LLC.
14942 * Originally Released Under LGPL - original licence link has changed is not relivant.
14945 * <script type="text/javascript">
14948 * @class Roo.state.CookieProvider
14949 * @extends Roo.state.Provider
14950 * The default Provider implementation which saves state via cookies.
14953 var cp = new Roo.state.CookieProvider({
14955 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14956 domain: "roojs.com"
14958 Roo.state.Manager.setProvider(cp);
14960 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14961 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14962 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
14963 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14964 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14965 * domain the page is running on including the 'www' like 'www.roojs.com')
14966 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14968 * Create a new CookieProvider
14969 * @param {Object} config The configuration object
14971 Roo.state.CookieProvider = function(config){
14972 Roo.state.CookieProvider.superclass.constructor.call(this);
14974 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14975 this.domain = null;
14976 this.secure = false;
14977 Roo.apply(this, config);
14978 this.state = this.readCookies();
14981 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14983 set : function(name, value){
14984 if(typeof value == "undefined" || value === null){
14988 this.setCookie(name, value);
14989 Roo.state.CookieProvider.superclass.set.call(this, name, value);
14993 clear : function(name){
14994 this.clearCookie(name);
14995 Roo.state.CookieProvider.superclass.clear.call(this, name);
14999 readCookies : function(){
15001 var c = document.cookie + ";";
15002 var re = /\s?(.*?)=(.*?);/g;
15004 while((matches = re.exec(c)) != null){
15005 var name = matches[1];
15006 var value = matches[2];
15007 if(name && name.substring(0,3) == "ys-"){
15008 cookies[name.substr(3)] = this.decodeValue(value);
15015 setCookie : function(name, value){
15016 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15017 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15018 ((this.path == null) ? "" : ("; path=" + this.path)) +
15019 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15020 ((this.secure == true) ? "; secure" : "");
15024 clearCookie : function(name){
15025 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15026 ((this.path == null) ? "" : ("; path=" + this.path)) +
15027 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15028 ((this.secure == true) ? "; secure" : "");
15032 * Ext JS Library 1.1.1
15033 * Copyright(c) 2006-2007, Ext JS, LLC.
15035 * Originally Released Under LGPL - original licence link has changed is not relivant.
15038 * <script type="text/javascript">
15043 * @class Roo.ComponentMgr
15044 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15047 Roo.ComponentMgr = function(){
15048 var all = new Roo.util.MixedCollection();
15052 * Registers a component.
15053 * @param {Roo.Component} c The component
15055 register : function(c){
15060 * Unregisters a component.
15061 * @param {Roo.Component} c The component
15063 unregister : function(c){
15068 * Returns a component by id
15069 * @param {String} id The component id
15071 get : function(id){
15072 return all.get(id);
15076 * Registers a function that will be called when a specified component is added to ComponentMgr
15077 * @param {String} id The component id
15078 * @param {Funtction} fn The callback function
15079 * @param {Object} scope The scope of the callback
15081 onAvailable : function(id, fn, scope){
15082 all.on("add", function(index, o){
15084 fn.call(scope || o, o);
15085 all.un("add", fn, scope);
15092 * Ext JS Library 1.1.1
15093 * Copyright(c) 2006-2007, Ext JS, LLC.
15095 * Originally Released Under LGPL - original licence link has changed is not relivant.
15098 * <script type="text/javascript">
15102 * @class Roo.Component
15103 * @extends Roo.util.Observable
15104 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15105 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15106 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15107 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15108 * All visual components (widgets) that require rendering into a layout should subclass Component.
15110 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15111 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
15112 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15114 Roo.Component = function(config){
15115 config = config || {};
15116 if(config.tagName || config.dom || typeof config == "string"){ // element object
15117 config = {el: config, id: config.id || config};
15119 this.initialConfig = config;
15121 Roo.apply(this, config);
15125 * Fires after the component is disabled.
15126 * @param {Roo.Component} this
15131 * Fires after the component is enabled.
15132 * @param {Roo.Component} this
15136 * @event beforeshow
15137 * Fires before the component is shown. Return false to stop the show.
15138 * @param {Roo.Component} this
15143 * Fires after the component is shown.
15144 * @param {Roo.Component} this
15148 * @event beforehide
15149 * Fires before the component is hidden. Return false to stop the hide.
15150 * @param {Roo.Component} this
15155 * Fires after the component is hidden.
15156 * @param {Roo.Component} this
15160 * @event beforerender
15161 * Fires before the component is rendered. Return false to stop the render.
15162 * @param {Roo.Component} this
15164 beforerender : true,
15167 * Fires after the component is rendered.
15168 * @param {Roo.Component} this
15172 * @event beforedestroy
15173 * Fires before the component is destroyed. Return false to stop the destroy.
15174 * @param {Roo.Component} this
15176 beforedestroy : true,
15179 * Fires after the component is destroyed.
15180 * @param {Roo.Component} this
15185 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15187 Roo.ComponentMgr.register(this);
15188 Roo.Component.superclass.constructor.call(this);
15189 this.initComponent();
15190 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15191 this.render(this.renderTo);
15192 delete this.renderTo;
15197 Roo.Component.AUTO_ID = 1000;
15199 Roo.extend(Roo.Component, Roo.util.Observable, {
15201 * @scope Roo.Component.prototype
15203 * true if this component is hidden. Read-only.
15208 * true if this component is disabled. Read-only.
15213 * true if this component has been rendered. Read-only.
15217 /** @cfg {String} disableClass
15218 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15220 disabledClass : "x-item-disabled",
15221 /** @cfg {Boolean} allowDomMove
15222 * Whether the component can move the Dom node when rendering (defaults to true).
15224 allowDomMove : true,
15225 /** @cfg {String} hideMode (display|visibility)
15226 * How this component should hidden. Supported values are
15227 * "visibility" (css visibility), "offsets" (negative offset position) and
15228 * "display" (css display) - defaults to "display".
15230 hideMode: 'display',
15233 ctype : "Roo.Component",
15236 * @cfg {String} actionMode
15237 * which property holds the element that used for hide() / show() / disable() / enable()
15243 getActionEl : function(){
15244 return this[this.actionMode];
15247 initComponent : Roo.emptyFn,
15249 * If this is a lazy rendering component, render it to its container element.
15250 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
15252 render : function(container, position){
15253 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15254 if(!container && this.el){
15255 this.el = Roo.get(this.el);
15256 container = this.el.dom.parentNode;
15257 this.allowDomMove = false;
15259 this.container = Roo.get(container);
15260 this.rendered = true;
15261 if(position !== undefined){
15262 if(typeof position == 'number'){
15263 position = this.container.dom.childNodes[position];
15265 position = Roo.getDom(position);
15268 this.onRender(this.container, position || null);
15270 this.el.addClass(this.cls);
15274 this.el.applyStyles(this.style);
15277 this.fireEvent("render", this);
15278 this.afterRender(this.container);
15290 // default function is not really useful
15291 onRender : function(ct, position){
15293 this.el = Roo.get(this.el);
15294 if(this.allowDomMove !== false){
15295 ct.dom.insertBefore(this.el.dom, position);
15301 getAutoCreate : function(){
15302 var cfg = typeof this.autoCreate == "object" ?
15303 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15304 if(this.id && !cfg.id){
15311 afterRender : Roo.emptyFn,
15314 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15315 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15317 destroy : function(){
15318 if(this.fireEvent("beforedestroy", this) !== false){
15319 this.purgeListeners();
15320 this.beforeDestroy();
15322 this.el.removeAllListeners();
15324 if(this.actionMode == "container"){
15325 this.container.remove();
15329 Roo.ComponentMgr.unregister(this);
15330 this.fireEvent("destroy", this);
15335 beforeDestroy : function(){
15340 onDestroy : function(){
15345 * Returns the underlying {@link Roo.Element}.
15346 * @return {Roo.Element} The element
15348 getEl : function(){
15353 * Returns the id of this component.
15356 getId : function(){
15361 * Try to focus this component.
15362 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15363 * @return {Roo.Component} this
15365 focus : function(selectText){
15368 if(selectText === true){
15369 this.el.dom.select();
15384 * Disable this component.
15385 * @return {Roo.Component} this
15387 disable : function(){
15391 this.disabled = true;
15392 this.fireEvent("disable", this);
15397 onDisable : function(){
15398 this.getActionEl().addClass(this.disabledClass);
15399 this.el.dom.disabled = true;
15403 * Enable this component.
15404 * @return {Roo.Component} this
15406 enable : function(){
15410 this.disabled = false;
15411 this.fireEvent("enable", this);
15416 onEnable : function(){
15417 this.getActionEl().removeClass(this.disabledClass);
15418 this.el.dom.disabled = false;
15422 * Convenience function for setting disabled/enabled by boolean.
15423 * @param {Boolean} disabled
15425 setDisabled : function(disabled){
15426 this[disabled ? "disable" : "enable"]();
15430 * Show this component.
15431 * @return {Roo.Component} this
15434 if(this.fireEvent("beforeshow", this) !== false){
15435 this.hidden = false;
15439 this.fireEvent("show", this);
15445 onShow : function(){
15446 var ae = this.getActionEl();
15447 if(this.hideMode == 'visibility'){
15448 ae.dom.style.visibility = "visible";
15449 }else if(this.hideMode == 'offsets'){
15450 ae.removeClass('x-hidden');
15452 ae.dom.style.display = "";
15457 * Hide this component.
15458 * @return {Roo.Component} this
15461 if(this.fireEvent("beforehide", this) !== false){
15462 this.hidden = true;
15466 this.fireEvent("hide", this);
15472 onHide : function(){
15473 var ae = this.getActionEl();
15474 if(this.hideMode == 'visibility'){
15475 ae.dom.style.visibility = "hidden";
15476 }else if(this.hideMode == 'offsets'){
15477 ae.addClass('x-hidden');
15479 ae.dom.style.display = "none";
15484 * Convenience function to hide or show this component by boolean.
15485 * @param {Boolean} visible True to show, false to hide
15486 * @return {Roo.Component} this
15488 setVisible: function(visible){
15498 * Returns true if this component is visible.
15500 isVisible : function(){
15501 return this.getActionEl().isVisible();
15504 cloneConfig : function(overrides){
15505 overrides = overrides || {};
15506 var id = overrides.id || Roo.id();
15507 var cfg = Roo.applyIf(overrides, this.initialConfig);
15508 cfg.id = id; // prevent dup id
15509 return new this.constructor(cfg);
15513 * Ext JS Library 1.1.1
15514 * Copyright(c) 2006-2007, Ext JS, LLC.
15516 * Originally Released Under LGPL - original licence link has changed is not relivant.
15519 * <script type="text/javascript">
15523 * @class Roo.BoxComponent
15524 * @extends Roo.Component
15525 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15526 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15527 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15528 * layout containers.
15530 * @param {Roo.Element/String/Object} config The configuration options.
15532 Roo.BoxComponent = function(config){
15533 Roo.Component.call(this, config);
15537 * Fires after the component is resized.
15538 * @param {Roo.Component} this
15539 * @param {Number} adjWidth The box-adjusted width that was set
15540 * @param {Number} adjHeight The box-adjusted height that was set
15541 * @param {Number} rawWidth The width that was originally specified
15542 * @param {Number} rawHeight The height that was originally specified
15547 * Fires after the component is moved.
15548 * @param {Roo.Component} this
15549 * @param {Number} x The new x position
15550 * @param {Number} y The new y position
15556 Roo.extend(Roo.BoxComponent, Roo.Component, {
15557 // private, set in afterRender to signify that the component has been rendered
15559 // private, used to defer height settings to subclasses
15560 deferHeight: false,
15561 /** @cfg {Number} width
15562 * width (optional) size of component
15564 /** @cfg {Number} height
15565 * height (optional) size of component
15569 * Sets the width and height of the component. This method fires the resize event. This method can accept
15570 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15571 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15572 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15573 * @return {Roo.BoxComponent} this
15575 setSize : function(w, h){
15576 // support for standard size objects
15577 if(typeof w == 'object'){
15582 if(!this.boxReady){
15588 // prevent recalcs when not needed
15589 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15592 this.lastSize = {width: w, height: h};
15594 var adj = this.adjustSize(w, h);
15595 var aw = adj.width, ah = adj.height;
15596 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15597 var rz = this.getResizeEl();
15598 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15599 rz.setSize(aw, ah);
15600 }else if(!this.deferHeight && ah !== undefined){
15602 }else if(aw !== undefined){
15605 this.onResize(aw, ah, w, h);
15606 this.fireEvent('resize', this, aw, ah, w, h);
15612 * Gets the current size of the component's underlying element.
15613 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15615 getSize : function(){
15616 return this.el.getSize();
15620 * Gets the current XY position of the component's underlying element.
15621 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15622 * @return {Array} The XY position of the element (e.g., [100, 200])
15624 getPosition : function(local){
15625 if(local === true){
15626 return [this.el.getLeft(true), this.el.getTop(true)];
15628 return this.xy || this.el.getXY();
15632 * Gets the current box measurements of the component's underlying element.
15633 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15634 * @returns {Object} box An object in the format {x, y, width, height}
15636 getBox : function(local){
15637 var s = this.el.getSize();
15639 s.x = this.el.getLeft(true);
15640 s.y = this.el.getTop(true);
15642 var xy = this.xy || this.el.getXY();
15650 * Sets the current box measurements of the component's underlying element.
15651 * @param {Object} box An object in the format {x, y, width, height}
15652 * @returns {Roo.BoxComponent} this
15654 updateBox : function(box){
15655 this.setSize(box.width, box.height);
15656 this.setPagePosition(box.x, box.y);
15661 getResizeEl : function(){
15662 return this.resizeEl || this.el;
15666 getPositionEl : function(){
15667 return this.positionEl || this.el;
15671 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15672 * This method fires the move event.
15673 * @param {Number} left The new left
15674 * @param {Number} top The new top
15675 * @returns {Roo.BoxComponent} this
15677 setPosition : function(x, y){
15680 if(!this.boxReady){
15683 var adj = this.adjustPosition(x, y);
15684 var ax = adj.x, ay = adj.y;
15686 var el = this.getPositionEl();
15687 if(ax !== undefined || ay !== undefined){
15688 if(ax !== undefined && ay !== undefined){
15689 el.setLeftTop(ax, ay);
15690 }else if(ax !== undefined){
15692 }else if(ay !== undefined){
15695 this.onPosition(ax, ay);
15696 this.fireEvent('move', this, ax, ay);
15702 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15703 * This method fires the move event.
15704 * @param {Number} x The new x position
15705 * @param {Number} y The new y position
15706 * @returns {Roo.BoxComponent} this
15708 setPagePosition : function(x, y){
15711 if(!this.boxReady){
15714 if(x === undefined || y === undefined){ // cannot translate undefined points
15717 var p = this.el.translatePoints(x, y);
15718 this.setPosition(p.left, p.top);
15723 onRender : function(ct, position){
15724 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15726 this.resizeEl = Roo.get(this.resizeEl);
15728 if(this.positionEl){
15729 this.positionEl = Roo.get(this.positionEl);
15734 afterRender : function(){
15735 Roo.BoxComponent.superclass.afterRender.call(this);
15736 this.boxReady = true;
15737 this.setSize(this.width, this.height);
15738 if(this.x || this.y){
15739 this.setPosition(this.x, this.y);
15741 if(this.pageX || this.pageY){
15742 this.setPagePosition(this.pageX, this.pageY);
15747 * Force the component's size to recalculate based on the underlying element's current height and width.
15748 * @returns {Roo.BoxComponent} this
15750 syncSize : function(){
15751 delete this.lastSize;
15752 this.setSize(this.el.getWidth(), this.el.getHeight());
15757 * Called after the component is resized, this method is empty by default but can be implemented by any
15758 * subclass that needs to perform custom logic after a resize occurs.
15759 * @param {Number} adjWidth The box-adjusted width that was set
15760 * @param {Number} adjHeight The box-adjusted height that was set
15761 * @param {Number} rawWidth The width that was originally specified
15762 * @param {Number} rawHeight The height that was originally specified
15764 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15769 * Called after the component is moved, this method is empty by default but can be implemented by any
15770 * subclass that needs to perform custom logic after a move occurs.
15771 * @param {Number} x The new x position
15772 * @param {Number} y The new y position
15774 onPosition : function(x, y){
15779 adjustSize : function(w, h){
15780 if(this.autoWidth){
15783 if(this.autoHeight){
15786 return {width : w, height: h};
15790 adjustPosition : function(x, y){
15791 return {x : x, y: y};
15794 * Original code for Roojs - LGPL
15795 * <script type="text/javascript">
15799 * @class Roo.XComponent
15800 * A delayed Element creator...
15801 * Or a way to group chunks of interface together.
15802 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15803 * used in conjunction with XComponent.build() it will create an instance of each element,
15804 * then call addxtype() to build the User interface.
15806 * Mypart.xyx = new Roo.XComponent({
15808 parent : 'Mypart.xyz', // empty == document.element.!!
15812 disabled : function() {}
15814 tree : function() { // return an tree of xtype declared components
15818 xtype : 'NestedLayoutPanel',
15825 * It can be used to build a big heiracy, with parent etc.
15826 * or you can just use this to render a single compoent to a dom element
15827 * MYPART.render(Roo.Element | String(id) | dom_element )
15834 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15835 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15837 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15839 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15840 * - if mulitple topModules exist, the last one is defined as the top module.
15844 * When the top level or multiple modules are to embedded into a existing HTML page,
15845 * the parent element can container '#id' of the element where the module will be drawn.
15849 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15850 * it relies more on a include mechanism, where sub modules are included into an outer page.
15851 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15853 * Bootstrap Roo Included elements
15855 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15856 * hence confusing the component builder as it thinks there are multiple top level elements.
15860 * @extends Roo.util.Observable
15862 * @param cfg {Object} configuration of component
15865 Roo.XComponent = function(cfg) {
15866 Roo.apply(this, cfg);
15870 * Fires when this the componnt is built
15871 * @param {Roo.XComponent} c the component
15876 this.region = this.region || 'center'; // default..
15877 Roo.XComponent.register(this);
15878 this.modules = false;
15879 this.el = false; // where the layout goes..
15883 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15886 * The created element (with Roo.factory())
15887 * @type {Roo.Layout}
15893 * for BC - use el in new code
15894 * @type {Roo.Layout}
15900 * for BC - use el in new code
15901 * @type {Roo.Layout}
15906 * @cfg {Function|boolean} disabled
15907 * If this module is disabled by some rule, return true from the funtion
15912 * @cfg {String} parent
15913 * Name of parent element which it get xtype added to..
15918 * @cfg {String} order
15919 * Used to set the order in which elements are created (usefull for multiple tabs)
15924 * @cfg {String} name
15925 * String to display while loading.
15929 * @cfg {String} region
15930 * Region to render component to (defaults to center)
15935 * @cfg {Array} items
15936 * A single item array - the first element is the root of the tree..
15937 * It's done this way to stay compatible with the Xtype system...
15943 * The method that retuns the tree of parts that make up this compoennt
15950 * render element to dom or tree
15951 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15954 render : function(el)
15958 var hp = this.parent ? 1 : 0;
15959 Roo.debug && Roo.log(this);
15961 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15962 // if parent is a '#.....' string, then let's use that..
15963 var ename = this.parent.substr(1);
15964 this.parent = false;
15965 Roo.debug && Roo.log(ename);
15967 case 'bootstrap-body' :
15968 if (typeof(Roo.bootstrap.Body) != 'undefined') {
15969 this.parent = { el : new Roo.bootstrap.Body() };
15970 Roo.debug && Roo.log("setting el to doc body");
15973 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15977 this.parent = { el : true};
15980 el = Roo.get(ename);
15985 if (!el && !this.parent) {
15986 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15990 Roo.debug && Roo.log("EL:");
15991 Roo.debug && Roo.log(el);
15992 Roo.debug && Roo.log("this.parent.el:");
15993 Roo.debug && Roo.log(this.parent.el);
15995 var tree = this._tree ? this._tree() : this.tree();
15997 // altertive root elements ??? - we need a better way to indicate these.
15998 var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15999 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16001 if (!this.parent && is_alt) {
16002 //el = Roo.get(document.body);
16003 this.parent = { el : true };
16008 if (!this.parent) {
16010 Roo.debug && Roo.log("no parent - creating one");
16012 el = el ? Roo.get(el) : false;
16014 // it's a top level one..
16016 el : new Roo.BorderLayout(el || document.body, {
16022 tabPosition: 'top',
16023 //resizeTabs: true,
16024 alwaysShowTabs: el && hp? false : true,
16025 hideTabs: el || !hp ? true : false,
16032 if (!this.parent.el) {
16033 // probably an old style ctor, which has been disabled.
16037 // The 'tree' method is '_tree now'
16039 tree.region = tree.region || this.region;
16041 if (this.parent.el === true) {
16042 // bootstrap... - body..
16043 this.parent.el = Roo.factory(tree);
16046 this.el = this.parent.el.addxtype(tree);
16047 this.fireEvent('built', this);
16049 this.panel = this.el;
16050 this.layout = this.panel.layout;
16051 this.parentLayout = this.parent.layout || false;
16057 Roo.apply(Roo.XComponent, {
16059 * @property hideProgress
16060 * true to disable the building progress bar.. usefull on single page renders.
16063 hideProgress : false,
16065 * @property buildCompleted
16066 * True when the builder has completed building the interface.
16069 buildCompleted : false,
16072 * @property topModule
16073 * the upper most module - uses document.element as it's constructor.
16080 * @property modules
16081 * array of modules to be created by registration system.
16082 * @type {Array} of Roo.XComponent
16087 * @property elmodules
16088 * array of modules to be created by which use #ID
16089 * @type {Array} of Roo.XComponent
16095 * @property build_from_html
16096 * Build elements from html - used by bootstrap HTML stuff
16097 * - this is cleared after build is completed
16098 * @type {boolean} true (default false)
16101 build_from_html : false,
16104 * Register components to be built later.
16106 * This solves the following issues
16107 * - Building is not done on page load, but after an authentication process has occured.
16108 * - Interface elements are registered on page load
16109 * - Parent Interface elements may not be loaded before child, so this handles that..
16116 module : 'Pman.Tab.projectMgr',
16118 parent : 'Pman.layout',
16119 disabled : false, // or use a function..
16122 * * @param {Object} details about module
16124 register : function(obj) {
16126 Roo.XComponent.event.fireEvent('register', obj);
16127 switch(typeof(obj.disabled) ) {
16133 if ( obj.disabled() ) {
16139 if (obj.disabled) {
16145 this.modules.push(obj);
16149 * convert a string to an object..
16150 * eg. 'AAA.BBB' -> finds AAA.BBB
16154 toObject : function(str)
16156 if (!str || typeof(str) == 'object') {
16159 if (str.substring(0,1) == '#') {
16163 var ar = str.split('.');
16168 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16170 throw "Module not found : " + str;
16174 throw "Module not found : " + str;
16176 Roo.each(ar, function(e) {
16177 if (typeof(o[e]) == 'undefined') {
16178 throw "Module not found : " + str;
16189 * move modules into their correct place in the tree..
16192 preBuild : function ()
16195 Roo.each(this.modules , function (obj)
16197 Roo.XComponent.event.fireEvent('beforebuild', obj);
16199 var opar = obj.parent;
16201 obj.parent = this.toObject(opar);
16203 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16208 Roo.debug && Roo.log("GOT top level module");
16209 Roo.debug && Roo.log(obj);
16210 obj.modules = new Roo.util.MixedCollection(false,
16211 function(o) { return o.order + '' }
16213 this.topModule = obj;
16216 // parent is a string (usually a dom element name..)
16217 if (typeof(obj.parent) == 'string') {
16218 this.elmodules.push(obj);
16221 if (obj.parent.constructor != Roo.XComponent) {
16222 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16224 if (!obj.parent.modules) {
16225 obj.parent.modules = new Roo.util.MixedCollection(false,
16226 function(o) { return o.order + '' }
16229 if (obj.parent.disabled) {
16230 obj.disabled = true;
16232 obj.parent.modules.add(obj);
16237 * make a list of modules to build.
16238 * @return {Array} list of modules.
16241 buildOrder : function()
16244 var cmp = function(a,b) {
16245 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16247 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16248 throw "No top level modules to build";
16251 // make a flat list in order of modules to build.
16252 var mods = this.topModule ? [ this.topModule ] : [];
16255 // elmodules (is a list of DOM based modules )
16256 Roo.each(this.elmodules, function(e) {
16258 if (!this.topModule &&
16259 typeof(e.parent) == 'string' &&
16260 e.parent.substring(0,1) == '#' &&
16261 Roo.get(e.parent.substr(1))
16264 _this.topModule = e;
16270 // add modules to their parents..
16271 var addMod = function(m) {
16272 Roo.debug && Roo.log("build Order: add: " + m.name);
16275 if (m.modules && !m.disabled) {
16276 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16277 m.modules.keySort('ASC', cmp );
16278 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16280 m.modules.each(addMod);
16282 Roo.debug && Roo.log("build Order: no child modules");
16284 // not sure if this is used any more..
16286 m.finalize.name = m.name + " (clean up) ";
16287 mods.push(m.finalize);
16291 if (this.topModule && this.topModule.modules) {
16292 this.topModule.modules.keySort('ASC', cmp );
16293 this.topModule.modules.each(addMod);
16299 * Build the registered modules.
16300 * @param {Object} parent element.
16301 * @param {Function} optional method to call after module has been added.
16305 build : function(opts)
16308 if (typeof(opts) != 'undefined') {
16309 Roo.apply(this,opts);
16313 var mods = this.buildOrder();
16315 //this.allmods = mods;
16316 //Roo.debug && Roo.log(mods);
16318 if (!mods.length) { // should not happen
16319 throw "NO modules!!!";
16323 var msg = "Building Interface...";
16324 // flash it up as modal - so we store the mask!?
16325 if (!this.hideProgress && Roo.MessageBox) {
16326 Roo.MessageBox.show({ title: 'loading' });
16327 Roo.MessageBox.show({
16328 title: "Please wait...",
16337 var total = mods.length;
16340 var progressRun = function() {
16341 if (!mods.length) {
16342 Roo.debug && Roo.log('hide?');
16343 if (!this.hideProgress && Roo.MessageBox) {
16344 Roo.MessageBox.hide();
16346 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16348 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16354 var m = mods.shift();
16357 Roo.debug && Roo.log(m);
16358 // not sure if this is supported any more.. - modules that are are just function
16359 if (typeof(m) == 'function') {
16361 return progressRun.defer(10, _this);
16365 msg = "Building Interface " + (total - mods.length) +
16367 (m.name ? (' - ' + m.name) : '');
16368 Roo.debug && Roo.log(msg);
16369 if (!this.hideProgress && Roo.MessageBox) {
16370 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16374 // is the module disabled?
16375 var disabled = (typeof(m.disabled) == 'function') ?
16376 m.disabled.call(m.module.disabled) : m.disabled;
16380 return progressRun(); // we do not update the display!
16388 // it's 10 on top level, and 1 on others??? why...
16389 return progressRun.defer(10, _this);
16392 progressRun.defer(1, _this);
16406 * wrapper for event.on - aliased later..
16407 * Typically use to register a event handler for register:
16409 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16418 Roo.XComponent.event = new Roo.util.Observable({
16422 * Fires when an Component is registered,
16423 * set the disable property on the Component to stop registration.
16424 * @param {Roo.XComponent} c the component being registerd.
16429 * @event beforebuild
16430 * Fires before each Component is built
16431 * can be used to apply permissions.
16432 * @param {Roo.XComponent} c the component being registerd.
16435 'beforebuild' : true,
16437 * @event buildcomplete
16438 * Fires on the top level element when all elements have been built
16439 * @param {Roo.XComponent} the top level component.
16441 'buildcomplete' : true
16446 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16449 * Ext JS Library 1.1.1
16450 * Copyright(c) 2006-2007, Ext JS, LLC.
16452 * Originally Released Under LGPL - original licence link has changed is not relivant.
16455 * <script type="text/javascript">
16461 * These classes are derivatives of the similarly named classes in the YUI Library.
16462 * The original license:
16463 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
16464 * Code licensed under the BSD License:
16465 * http://developer.yahoo.net/yui/license.txt
16470 var Event=Roo.EventManager;
16471 var Dom=Roo.lib.Dom;
16474 * @class Roo.dd.DragDrop
16475 * @extends Roo.util.Observable
16476 * Defines the interface and base operation of items that that can be
16477 * dragged or can be drop targets. It was designed to be extended, overriding
16478 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
16479 * Up to three html elements can be associated with a DragDrop instance:
16481 * <li>linked element: the element that is passed into the constructor.
16482 * This is the element which defines the boundaries for interaction with
16483 * other DragDrop objects.</li>
16484 * <li>handle element(s): The drag operation only occurs if the element that
16485 * was clicked matches a handle element. By default this is the linked
16486 * element, but there are times that you will want only a portion of the
16487 * linked element to initiate the drag operation, and the setHandleElId()
16488 * method provides a way to define this.</li>
16489 * <li>drag element: this represents the element that would be moved along
16490 * with the cursor during a drag operation. By default, this is the linked
16491 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
16492 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
16495 * This class should not be instantiated until the onload event to ensure that
16496 * the associated elements are available.
16497 * The following would define a DragDrop obj that would interact with any
16498 * other DragDrop obj in the "group1" group:
16500 * dd = new Roo.dd.DragDrop("div1", "group1");
16502 * Since none of the event handlers have been implemented, nothing would
16503 * actually happen if you were to run the code above. Normally you would
16504 * override this class or one of the default implementations, but you can
16505 * also override the methods you want on an instance of the class...
16507 * dd.onDragDrop = function(e, id) {
16508 * alert("dd was dropped on " + id);
16512 * @param {String} id of the element that is linked to this instance
16513 * @param {String} sGroup the group of related DragDrop objects
16514 * @param {object} config an object containing configurable attributes
16515 * Valid properties for DragDrop:
16516 * padding, isTarget, maintainOffset, primaryButtonOnly
16518 Roo.dd.DragDrop = function(id, sGroup, config) {
16520 this.init(id, sGroup, config);
16525 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
16528 * The id of the element associated with this object. This is what we
16529 * refer to as the "linked element" because the size and position of
16530 * this element is used to determine when the drag and drop objects have
16538 * Configuration attributes passed into the constructor
16545 * The id of the element that will be dragged. By default this is same
16546 * as the linked element , but could be changed to another element. Ex:
16548 * @property dragElId
16555 * the id of the element that initiates the drag operation. By default
16556 * this is the linked element, but could be changed to be a child of this
16557 * element. This lets us do things like only starting the drag when the
16558 * header element within the linked html element is clicked.
16559 * @property handleElId
16566 * An associative array of HTML tags that will be ignored if clicked.
16567 * @property invalidHandleTypes
16568 * @type {string: string}
16570 invalidHandleTypes: null,
16573 * An associative array of ids for elements that will be ignored if clicked
16574 * @property invalidHandleIds
16575 * @type {string: string}
16577 invalidHandleIds: null,
16580 * An indexted array of css class names for elements that will be ignored
16582 * @property invalidHandleClasses
16585 invalidHandleClasses: null,
16588 * The linked element's absolute X position at the time the drag was
16590 * @property startPageX
16597 * The linked element's absolute X position at the time the drag was
16599 * @property startPageY
16606 * The group defines a logical collection of DragDrop objects that are
16607 * related. Instances only get events when interacting with other
16608 * DragDrop object in the same group. This lets us define multiple
16609 * groups using a single DragDrop subclass if we want.
16611 * @type {string: string}
16616 * Individual drag/drop instances can be locked. This will prevent
16617 * onmousedown start drag.
16625 * Lock this instance
16628 lock: function() { this.locked = true; },
16631 * Unlock this instace
16634 unlock: function() { this.locked = false; },
16637 * By default, all insances can be a drop target. This can be disabled by
16638 * setting isTarget to false.
16645 * The padding configured for this drag and drop object for calculating
16646 * the drop zone intersection with this object.
16653 * Cached reference to the linked element
16654 * @property _domRef
16660 * Internal typeof flag
16661 * @property __ygDragDrop
16664 __ygDragDrop: true,
16667 * Set to true when horizontal contraints are applied
16668 * @property constrainX
16675 * Set to true when vertical contraints are applied
16676 * @property constrainY
16683 * The left constraint
16691 * The right constraint
16699 * The up constraint
16708 * The down constraint
16716 * Maintain offsets when we resetconstraints. Set to true when you want
16717 * the position of the element relative to its parent to stay the same
16718 * when the page changes
16720 * @property maintainOffset
16723 maintainOffset: false,
16726 * Array of pixel locations the element will snap to if we specified a
16727 * horizontal graduation/interval. This array is generated automatically
16728 * when you define a tick interval.
16735 * Array of pixel locations the element will snap to if we specified a
16736 * vertical graduation/interval. This array is generated automatically
16737 * when you define a tick interval.
16744 * By default the drag and drop instance will only respond to the primary
16745 * button click (left button for a right-handed mouse). Set to true to
16746 * allow drag and drop to start with any mouse click that is propogated
16748 * @property primaryButtonOnly
16751 primaryButtonOnly: true,
16754 * The availabe property is false until the linked dom element is accessible.
16755 * @property available
16761 * By default, drags can only be initiated if the mousedown occurs in the
16762 * region the linked element is. This is done in part to work around a
16763 * bug in some browsers that mis-report the mousedown if the previous
16764 * mouseup happened outside of the window. This property is set to true
16765 * if outer handles are defined.
16767 * @property hasOuterHandles
16771 hasOuterHandles: false,
16774 * Code that executes immediately before the startDrag event
16775 * @method b4StartDrag
16778 b4StartDrag: function(x, y) { },
16781 * Abstract method called after a drag/drop object is clicked
16782 * and the drag or mousedown time thresholds have beeen met.
16783 * @method startDrag
16784 * @param {int} X click location
16785 * @param {int} Y click location
16787 startDrag: function(x, y) { /* override this */ },
16790 * Code that executes immediately before the onDrag event
16794 b4Drag: function(e) { },
16797 * Abstract method called during the onMouseMove event while dragging an
16800 * @param {Event} e the mousemove event
16802 onDrag: function(e) { /* override this */ },
16805 * Abstract method called when this element fist begins hovering over
16806 * another DragDrop obj
16807 * @method onDragEnter
16808 * @param {Event} e the mousemove event
16809 * @param {String|DragDrop[]} id In POINT mode, the element
16810 * id this is hovering over. In INTERSECT mode, an array of one or more
16811 * dragdrop items being hovered over.
16813 onDragEnter: function(e, id) { /* override this */ },
16816 * Code that executes immediately before the onDragOver event
16817 * @method b4DragOver
16820 b4DragOver: function(e) { },
16823 * Abstract method called when this element is hovering over another
16825 * @method onDragOver
16826 * @param {Event} e the mousemove event
16827 * @param {String|DragDrop[]} id In POINT mode, the element
16828 * id this is hovering over. In INTERSECT mode, an array of dd items
16829 * being hovered over.
16831 onDragOver: function(e, id) { /* override this */ },
16834 * Code that executes immediately before the onDragOut event
16835 * @method b4DragOut
16838 b4DragOut: function(e) { },
16841 * Abstract method called when we are no longer hovering over an element
16842 * @method onDragOut
16843 * @param {Event} e the mousemove event
16844 * @param {String|DragDrop[]} id In POINT mode, the element
16845 * id this was hovering over. In INTERSECT mode, an array of dd items
16846 * that the mouse is no longer over.
16848 onDragOut: function(e, id) { /* override this */ },
16851 * Code that executes immediately before the onDragDrop event
16852 * @method b4DragDrop
16855 b4DragDrop: function(e) { },
16858 * Abstract method called when this item is dropped on another DragDrop
16860 * @method onDragDrop
16861 * @param {Event} e the mouseup event
16862 * @param {String|DragDrop[]} id In POINT mode, the element
16863 * id this was dropped on. In INTERSECT mode, an array of dd items this
16866 onDragDrop: function(e, id) { /* override this */ },
16869 * Abstract method called when this item is dropped on an area with no
16871 * @method onInvalidDrop
16872 * @param {Event} e the mouseup event
16874 onInvalidDrop: function(e) { /* override this */ },
16877 * Code that executes immediately before the endDrag event
16878 * @method b4EndDrag
16881 b4EndDrag: function(e) { },
16884 * Fired when we are done dragging the object
16886 * @param {Event} e the mouseup event
16888 endDrag: function(e) { /* override this */ },
16891 * Code executed immediately before the onMouseDown event
16892 * @method b4MouseDown
16893 * @param {Event} e the mousedown event
16896 b4MouseDown: function(e) { },
16899 * Event handler that fires when a drag/drop obj gets a mousedown
16900 * @method onMouseDown
16901 * @param {Event} e the mousedown event
16903 onMouseDown: function(e) { /* override this */ },
16906 * Event handler that fires when a drag/drop obj gets a mouseup
16907 * @method onMouseUp
16908 * @param {Event} e the mouseup event
16910 onMouseUp: function(e) { /* override this */ },
16913 * Override the onAvailable method to do what is needed after the initial
16914 * position was determined.
16915 * @method onAvailable
16917 onAvailable: function () {
16921 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
16924 defaultPadding : {left:0, right:0, top:0, bottom:0},
16927 * Initializes the drag drop object's constraints to restrict movement to a certain element.
16931 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
16932 { dragElId: "existingProxyDiv" });
16933 dd.startDrag = function(){
16934 this.constrainTo("parent-id");
16937 * Or you can initalize it using the {@link Roo.Element} object:
16939 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
16940 startDrag : function(){
16941 this.constrainTo("parent-id");
16945 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
16946 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
16947 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
16948 * an object containing the sides to pad. For example: {right:10, bottom:10}
16949 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
16951 constrainTo : function(constrainTo, pad, inContent){
16952 if(typeof pad == "number"){
16953 pad = {left: pad, right:pad, top:pad, bottom:pad};
16955 pad = pad || this.defaultPadding;
16956 var b = Roo.get(this.getEl()).getBox();
16957 var ce = Roo.get(constrainTo);
16958 var s = ce.getScroll();
16959 var c, cd = ce.dom;
16960 if(cd == document.body){
16961 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
16964 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
16968 var topSpace = b.y - c.y;
16969 var leftSpace = b.x - c.x;
16971 this.resetConstraints();
16972 this.setXConstraint(leftSpace - (pad.left||0), // left
16973 c.width - leftSpace - b.width - (pad.right||0) //right
16975 this.setYConstraint(topSpace - (pad.top||0), //top
16976 c.height - topSpace - b.height - (pad.bottom||0) //bottom
16981 * Returns a reference to the linked element
16983 * @return {HTMLElement} the html element
16985 getEl: function() {
16986 if (!this._domRef) {
16987 this._domRef = Roo.getDom(this.id);
16990 return this._domRef;
16994 * Returns a reference to the actual element to drag. By default this is
16995 * the same as the html element, but it can be assigned to another
16996 * element. An example of this can be found in Roo.dd.DDProxy
16997 * @method getDragEl
16998 * @return {HTMLElement} the html element
17000 getDragEl: function() {
17001 return Roo.getDom(this.dragElId);
17005 * Sets up the DragDrop object. Must be called in the constructor of any
17006 * Roo.dd.DragDrop subclass
17008 * @param id the id of the linked element
17009 * @param {String} sGroup the group of related items
17010 * @param {object} config configuration attributes
17012 init: function(id, sGroup, config) {
17013 this.initTarget(id, sGroup, config);
17014 if (!Roo.isTouch) {
17015 Event.on(this.id, "mousedown", this.handleMouseDown, this);
17017 Event.on(this.id, "touchstart", this.handleMouseDown, this);
17018 // Event.on(this.id, "selectstart", Event.preventDefault);
17022 * Initializes Targeting functionality only... the object does not
17023 * get a mousedown handler.
17024 * @method initTarget
17025 * @param id the id of the linked element
17026 * @param {String} sGroup the group of related items
17027 * @param {object} config configuration attributes
17029 initTarget: function(id, sGroup, config) {
17031 // configuration attributes
17032 this.config = config || {};
17034 // create a local reference to the drag and drop manager
17035 this.DDM = Roo.dd.DDM;
17036 // initialize the groups array
17039 // assume that we have an element reference instead of an id if the
17040 // parameter is not a string
17041 if (typeof id !== "string") {
17048 // add to an interaction group
17049 this.addToGroup((sGroup) ? sGroup : "default");
17051 // We don't want to register this as the handle with the manager
17052 // so we just set the id rather than calling the setter.
17053 this.handleElId = id;
17055 // the linked element is the element that gets dragged by default
17056 this.setDragElId(id);
17058 // by default, clicked anchors will not start drag operations.
17059 this.invalidHandleTypes = { A: "A" };
17060 this.invalidHandleIds = {};
17061 this.invalidHandleClasses = [];
17063 this.applyConfig();
17065 this.handleOnAvailable();
17069 * Applies the configuration parameters that were passed into the constructor.
17070 * This is supposed to happen at each level through the inheritance chain. So
17071 * a DDProxy implentation will execute apply config on DDProxy, DD, and
17072 * DragDrop in order to get all of the parameters that are available in
17074 * @method applyConfig
17076 applyConfig: function() {
17078 // configurable properties:
17079 // padding, isTarget, maintainOffset, primaryButtonOnly
17080 this.padding = this.config.padding || [0, 0, 0, 0];
17081 this.isTarget = (this.config.isTarget !== false);
17082 this.maintainOffset = (this.config.maintainOffset);
17083 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
17088 * Executed when the linked element is available
17089 * @method handleOnAvailable
17092 handleOnAvailable: function() {
17093 this.available = true;
17094 this.resetConstraints();
17095 this.onAvailable();
17099 * Configures the padding for the target zone in px. Effectively expands
17100 * (or reduces) the virtual object size for targeting calculations.
17101 * Supports css-style shorthand; if only one parameter is passed, all sides
17102 * will have that padding, and if only two are passed, the top and bottom
17103 * will have the first param, the left and right the second.
17104 * @method setPadding
17105 * @param {int} iTop Top pad
17106 * @param {int} iRight Right pad
17107 * @param {int} iBot Bot pad
17108 * @param {int} iLeft Left pad
17110 setPadding: function(iTop, iRight, iBot, iLeft) {
17111 // this.padding = [iLeft, iRight, iTop, iBot];
17112 if (!iRight && 0 !== iRight) {
17113 this.padding = [iTop, iTop, iTop, iTop];
17114 } else if (!iBot && 0 !== iBot) {
17115 this.padding = [iTop, iRight, iTop, iRight];
17117 this.padding = [iTop, iRight, iBot, iLeft];
17122 * Stores the initial placement of the linked element.
17123 * @method setInitialPosition
17124 * @param {int} diffX the X offset, default 0
17125 * @param {int} diffY the Y offset, default 0
17127 setInitPosition: function(diffX, diffY) {
17128 var el = this.getEl();
17130 if (!this.DDM.verifyEl(el)) {
17134 var dx = diffX || 0;
17135 var dy = diffY || 0;
17137 var p = Dom.getXY( el );
17139 this.initPageX = p[0] - dx;
17140 this.initPageY = p[1] - dy;
17142 this.lastPageX = p[0];
17143 this.lastPageY = p[1];
17146 this.setStartPosition(p);
17150 * Sets the start position of the element. This is set when the obj
17151 * is initialized, the reset when a drag is started.
17152 * @method setStartPosition
17153 * @param pos current position (from previous lookup)
17156 setStartPosition: function(pos) {
17157 var p = pos || Dom.getXY( this.getEl() );
17158 this.deltaSetXY = null;
17160 this.startPageX = p[0];
17161 this.startPageY = p[1];
17165 * Add this instance to a group of related drag/drop objects. All
17166 * instances belong to at least one group, and can belong to as many
17167 * groups as needed.
17168 * @method addToGroup
17169 * @param sGroup {string} the name of the group
17171 addToGroup: function(sGroup) {
17172 this.groups[sGroup] = true;
17173 this.DDM.regDragDrop(this, sGroup);
17177 * Remove's this instance from the supplied interaction group
17178 * @method removeFromGroup
17179 * @param {string} sGroup The group to drop
17181 removeFromGroup: function(sGroup) {
17182 if (this.groups[sGroup]) {
17183 delete this.groups[sGroup];
17186 this.DDM.removeDDFromGroup(this, sGroup);
17190 * Allows you to specify that an element other than the linked element
17191 * will be moved with the cursor during a drag
17192 * @method setDragElId
17193 * @param id {string} the id of the element that will be used to initiate the drag
17195 setDragElId: function(id) {
17196 this.dragElId = id;
17200 * Allows you to specify a child of the linked element that should be
17201 * used to initiate the drag operation. An example of this would be if
17202 * you have a content div with text and links. Clicking anywhere in the
17203 * content area would normally start the drag operation. Use this method
17204 * to specify that an element inside of the content div is the element
17205 * that starts the drag operation.
17206 * @method setHandleElId
17207 * @param id {string} the id of the element that will be used to
17208 * initiate the drag.
17210 setHandleElId: function(id) {
17211 if (typeof id !== "string") {
17214 this.handleElId = id;
17215 this.DDM.regHandle(this.id, id);
17219 * Allows you to set an element outside of the linked element as a drag
17221 * @method setOuterHandleElId
17222 * @param id the id of the element that will be used to initiate the drag
17224 setOuterHandleElId: function(id) {
17225 if (typeof id !== "string") {
17228 Event.on(id, "mousedown",
17229 this.handleMouseDown, this);
17230 this.setHandleElId(id);
17232 this.hasOuterHandles = true;
17236 * Remove all drag and drop hooks for this element
17239 unreg: function() {
17240 Event.un(this.id, "mousedown",
17241 this.handleMouseDown);
17242 Event.un(this.id, "touchstart",
17243 this.handleMouseDown);
17244 this._domRef = null;
17245 this.DDM._remove(this);
17248 destroy : function(){
17253 * Returns true if this instance is locked, or the drag drop mgr is locked
17254 * (meaning that all drag/drop is disabled on the page.)
17256 * @return {boolean} true if this obj or all drag/drop is locked, else
17259 isLocked: function() {
17260 return (this.DDM.isLocked() || this.locked);
17264 * Fired when this object is clicked
17265 * @method handleMouseDown
17267 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
17270 handleMouseDown: function(e, oDD){
17272 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
17273 //Roo.log('not touch/ button !=0');
17276 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
17277 return; // double touch..
17281 if (this.isLocked()) {
17282 //Roo.log('locked');
17286 this.DDM.refreshCache(this.groups);
17287 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
17288 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
17289 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
17290 //Roo.log('no outer handes or not over target');
17293 // Roo.log('check validator');
17294 if (this.clickValidator(e)) {
17295 // Roo.log('validate success');
17296 // set the initial element position
17297 this.setStartPosition();
17300 this.b4MouseDown(e);
17301 this.onMouseDown(e);
17303 this.DDM.handleMouseDown(e, this);
17305 this.DDM.stopEvent(e);
17313 clickValidator: function(e) {
17314 var target = e.getTarget();
17315 return ( this.isValidHandleChild(target) &&
17316 (this.id == this.handleElId ||
17317 this.DDM.handleWasClicked(target, this.id)) );
17321 * Allows you to specify a tag name that should not start a drag operation
17322 * when clicked. This is designed to facilitate embedding links within a
17323 * drag handle that do something other than start the drag.
17324 * @method addInvalidHandleType
17325 * @param {string} tagName the type of element to exclude
17327 addInvalidHandleType: function(tagName) {
17328 var type = tagName.toUpperCase();
17329 this.invalidHandleTypes[type] = type;
17333 * Lets you to specify an element id for a child of a drag handle
17334 * that should not initiate a drag
17335 * @method addInvalidHandleId
17336 * @param {string} id the element id of the element you wish to ignore
17338 addInvalidHandleId: function(id) {
17339 if (typeof id !== "string") {
17342 this.invalidHandleIds[id] = id;
17346 * Lets you specify a css class of elements that will not initiate a drag
17347 * @method addInvalidHandleClass
17348 * @param {string} cssClass the class of the elements you wish to ignore
17350 addInvalidHandleClass: function(cssClass) {
17351 this.invalidHandleClasses.push(cssClass);
17355 * Unsets an excluded tag name set by addInvalidHandleType
17356 * @method removeInvalidHandleType
17357 * @param {string} tagName the type of element to unexclude
17359 removeInvalidHandleType: function(tagName) {
17360 var type = tagName.toUpperCase();
17361 // this.invalidHandleTypes[type] = null;
17362 delete this.invalidHandleTypes[type];
17366 * Unsets an invalid handle id
17367 * @method removeInvalidHandleId
17368 * @param {string} id the id of the element to re-enable
17370 removeInvalidHandleId: function(id) {
17371 if (typeof id !== "string") {
17374 delete this.invalidHandleIds[id];
17378 * Unsets an invalid css class
17379 * @method removeInvalidHandleClass
17380 * @param {string} cssClass the class of the element(s) you wish to
17383 removeInvalidHandleClass: function(cssClass) {
17384 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
17385 if (this.invalidHandleClasses[i] == cssClass) {
17386 delete this.invalidHandleClasses[i];
17392 * Checks the tag exclusion list to see if this click should be ignored
17393 * @method isValidHandleChild
17394 * @param {HTMLElement} node the HTMLElement to evaluate
17395 * @return {boolean} true if this is a valid tag type, false if not
17397 isValidHandleChild: function(node) {
17400 // var n = (node.nodeName == "#text") ? node.parentNode : node;
17403 nodeName = node.nodeName.toUpperCase();
17405 nodeName = node.nodeName;
17407 valid = valid && !this.invalidHandleTypes[nodeName];
17408 valid = valid && !this.invalidHandleIds[node.id];
17410 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
17411 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
17420 * Create the array of horizontal tick marks if an interval was specified
17421 * in setXConstraint().
17422 * @method setXTicks
17425 setXTicks: function(iStartX, iTickSize) {
17427 this.xTickSize = iTickSize;
17431 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
17433 this.xTicks[this.xTicks.length] = i;
17438 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
17440 this.xTicks[this.xTicks.length] = i;
17445 this.xTicks.sort(this.DDM.numericSort) ;
17449 * Create the array of vertical tick marks if an interval was specified in
17450 * setYConstraint().
17451 * @method setYTicks
17454 setYTicks: function(iStartY, iTickSize) {
17456 this.yTickSize = iTickSize;
17460 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
17462 this.yTicks[this.yTicks.length] = i;
17467 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
17469 this.yTicks[this.yTicks.length] = i;
17474 this.yTicks.sort(this.DDM.numericSort) ;
17478 * By default, the element can be dragged any place on the screen. Use
17479 * this method to limit the horizontal travel of the element. Pass in
17480 * 0,0 for the parameters if you want to lock the drag to the y axis.
17481 * @method setXConstraint
17482 * @param {int} iLeft the number of pixels the element can move to the left
17483 * @param {int} iRight the number of pixels the element can move to the
17485 * @param {int} iTickSize optional parameter for specifying that the
17487 * should move iTickSize pixels at a time.
17489 setXConstraint: function(iLeft, iRight, iTickSize) {
17490 this.leftConstraint = iLeft;
17491 this.rightConstraint = iRight;
17493 this.minX = this.initPageX - iLeft;
17494 this.maxX = this.initPageX + iRight;
17495 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
17497 this.constrainX = true;
17501 * Clears any constraints applied to this instance. Also clears ticks
17502 * since they can't exist independent of a constraint at this time.
17503 * @method clearConstraints
17505 clearConstraints: function() {
17506 this.constrainX = false;
17507 this.constrainY = false;
17512 * Clears any tick interval defined for this instance
17513 * @method clearTicks
17515 clearTicks: function() {
17516 this.xTicks = null;
17517 this.yTicks = null;
17518 this.xTickSize = 0;
17519 this.yTickSize = 0;
17523 * By default, the element can be dragged any place on the screen. Set
17524 * this to limit the vertical travel of the element. Pass in 0,0 for the
17525 * parameters if you want to lock the drag to the x axis.
17526 * @method setYConstraint
17527 * @param {int} iUp the number of pixels the element can move up
17528 * @param {int} iDown the number of pixels the element can move down
17529 * @param {int} iTickSize optional parameter for specifying that the
17530 * element should move iTickSize pixels at a time.
17532 setYConstraint: function(iUp, iDown, iTickSize) {
17533 this.topConstraint = iUp;
17534 this.bottomConstraint = iDown;
17536 this.minY = this.initPageY - iUp;
17537 this.maxY = this.initPageY + iDown;
17538 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
17540 this.constrainY = true;
17545 * resetConstraints must be called if you manually reposition a dd element.
17546 * @method resetConstraints
17547 * @param {boolean} maintainOffset
17549 resetConstraints: function() {
17552 // Maintain offsets if necessary
17553 if (this.initPageX || this.initPageX === 0) {
17554 // figure out how much this thing has moved
17555 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
17556 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
17558 this.setInitPosition(dx, dy);
17560 // This is the first time we have detected the element's position
17562 this.setInitPosition();
17565 if (this.constrainX) {
17566 this.setXConstraint( this.leftConstraint,
17567 this.rightConstraint,
17571 if (this.constrainY) {
17572 this.setYConstraint( this.topConstraint,
17573 this.bottomConstraint,
17579 * Normally the drag element is moved pixel by pixel, but we can specify
17580 * that it move a number of pixels at a time. This method resolves the
17581 * location when we have it set up like this.
17583 * @param {int} val where we want to place the object
17584 * @param {int[]} tickArray sorted array of valid points
17585 * @return {int} the closest tick
17588 getTick: function(val, tickArray) {
17591 // If tick interval is not defined, it is effectively 1 pixel,
17592 // so we return the value passed to us.
17594 } else if (tickArray[0] >= val) {
17595 // The value is lower than the first tick, so we return the first
17597 return tickArray[0];
17599 for (var i=0, len=tickArray.length; i<len; ++i) {
17601 if (tickArray[next] && tickArray[next] >= val) {
17602 var diff1 = val - tickArray[i];
17603 var diff2 = tickArray[next] - val;
17604 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
17608 // The value is larger than the last tick, so we return the last
17610 return tickArray[tickArray.length - 1];
17617 * @return {string} string representation of the dd obj
17619 toString: function() {
17620 return ("DragDrop " + this.id);
17628 * Ext JS Library 1.1.1
17629 * Copyright(c) 2006-2007, Ext JS, LLC.
17631 * Originally Released Under LGPL - original licence link has changed is not relivant.
17634 * <script type="text/javascript">
17639 * The drag and drop utility provides a framework for building drag and drop
17640 * applications. In addition to enabling drag and drop for specific elements,
17641 * the drag and drop elements are tracked by the manager class, and the
17642 * interactions between the various elements are tracked during the drag and
17643 * the implementing code is notified about these important moments.
17646 // Only load the library once. Rewriting the manager class would orphan
17647 // existing drag and drop instances.
17648 if (!Roo.dd.DragDropMgr) {
17651 * @class Roo.dd.DragDropMgr
17652 * DragDropMgr is a singleton that tracks the element interaction for
17653 * all DragDrop items in the window. Generally, you will not call
17654 * this class directly, but it does have helper methods that could
17655 * be useful in your DragDrop implementations.
17658 Roo.dd.DragDropMgr = function() {
17660 var Event = Roo.EventManager;
17665 * Two dimensional Array of registered DragDrop objects. The first
17666 * dimension is the DragDrop item group, the second the DragDrop
17669 * @type {string: string}
17676 * Array of element ids defined as drag handles. Used to determine
17677 * if the element that generated the mousedown event is actually the
17678 * handle and not the html element itself.
17679 * @property handleIds
17680 * @type {string: string}
17687 * the DragDrop object that is currently being dragged
17688 * @property dragCurrent
17696 * the DragDrop object(s) that are being hovered over
17697 * @property dragOvers
17705 * the X distance between the cursor and the object being dragged
17714 * the Y distance between the cursor and the object being dragged
17723 * Flag to determine if we should prevent the default behavior of the
17724 * events we define. By default this is true, but this can be set to
17725 * false if you need the default behavior (not recommended)
17726 * @property preventDefault
17730 preventDefault: true,
17733 * Flag to determine if we should stop the propagation of the events
17734 * we generate. This is true by default but you may want to set it to
17735 * false if the html element contains other features that require the
17737 * @property stopPropagation
17741 stopPropagation: true,
17744 * Internal flag that is set to true when drag and drop has been
17746 * @property initialized
17753 * All drag and drop can be disabled.
17761 * Called the first time an element is registered.
17767 this.initialized = true;
17771 * In point mode, drag and drop interaction is defined by the
17772 * location of the cursor during the drag/drop
17780 * In intersect mode, drag and drop interactio nis defined by the
17781 * overlap of two or more drag and drop objects.
17782 * @property INTERSECT
17789 * The current drag and drop mode. Default: POINT
17797 * Runs method on all drag and drop objects
17798 * @method _execOnAll
17802 _execOnAll: function(sMethod, args) {
17803 for (var i in this.ids) {
17804 for (var j in this.ids[i]) {
17805 var oDD = this.ids[i][j];
17806 if (! this.isTypeOfDD(oDD)) {
17809 oDD[sMethod].apply(oDD, args);
17815 * Drag and drop initialization. Sets up the global event handlers
17820 _onLoad: function() {
17824 if (!Roo.isTouch) {
17825 Event.on(document, "mouseup", this.handleMouseUp, this, true);
17826 Event.on(document, "mousemove", this.handleMouseMove, this, true);
17828 Event.on(document, "touchend", this.handleMouseUp, this, true);
17829 Event.on(document, "touchmove", this.handleMouseMove, this, true);
17831 Event.on(window, "unload", this._onUnload, this, true);
17832 Event.on(window, "resize", this._onResize, this, true);
17833 // Event.on(window, "mouseout", this._test);
17838 * Reset constraints on all drag and drop objs
17839 * @method _onResize
17843 _onResize: function(e) {
17844 this._execOnAll("resetConstraints", []);
17848 * Lock all drag and drop functionality
17852 lock: function() { this.locked = true; },
17855 * Unlock all drag and drop functionality
17859 unlock: function() { this.locked = false; },
17862 * Is drag and drop locked?
17864 * @return {boolean} True if drag and drop is locked, false otherwise.
17867 isLocked: function() { return this.locked; },
17870 * Location cache that is set for all drag drop objects when a drag is
17871 * initiated, cleared when the drag is finished.
17872 * @property locationCache
17879 * Set useCache to false if you want to force object the lookup of each
17880 * drag and drop linked element constantly during a drag.
17881 * @property useCache
17888 * The number of pixels that the mouse needs to move after the
17889 * mousedown before the drag is initiated. Default=3;
17890 * @property clickPixelThresh
17894 clickPixelThresh: 3,
17897 * The number of milliseconds after the mousedown event to initiate the
17898 * drag if we don't get a mouseup event. Default=1000
17899 * @property clickTimeThresh
17903 clickTimeThresh: 350,
17906 * Flag that indicates that either the drag pixel threshold or the
17907 * mousdown time threshold has been met
17908 * @property dragThreshMet
17913 dragThreshMet: false,
17916 * Timeout used for the click time threshold
17917 * @property clickTimeout
17922 clickTimeout: null,
17925 * The X position of the mousedown event stored for later use when a
17926 * drag threshold is met.
17935 * The Y position of the mousedown event stored for later use when a
17936 * drag threshold is met.
17945 * Each DragDrop instance must be registered with the DragDropMgr.
17946 * This is executed in DragDrop.init()
17947 * @method regDragDrop
17948 * @param {DragDrop} oDD the DragDrop object to register
17949 * @param {String} sGroup the name of the group this element belongs to
17952 regDragDrop: function(oDD, sGroup) {
17953 if (!this.initialized) { this.init(); }
17955 if (!this.ids[sGroup]) {
17956 this.ids[sGroup] = {};
17958 this.ids[sGroup][oDD.id] = oDD;
17962 * Removes the supplied dd instance from the supplied group. Executed
17963 * by DragDrop.removeFromGroup, so don't call this function directly.
17964 * @method removeDDFromGroup
17968 removeDDFromGroup: function(oDD, sGroup) {
17969 if (!this.ids[sGroup]) {
17970 this.ids[sGroup] = {};
17973 var obj = this.ids[sGroup];
17974 if (obj && obj[oDD.id]) {
17975 delete obj[oDD.id];
17980 * Unregisters a drag and drop item. This is executed in
17981 * DragDrop.unreg, use that method instead of calling this directly.
17986 _remove: function(oDD) {
17987 for (var g in oDD.groups) {
17988 if (g && this.ids[g][oDD.id]) {
17989 delete this.ids[g][oDD.id];
17992 delete this.handleIds[oDD.id];
17996 * Each DragDrop handle element must be registered. This is done
17997 * automatically when executing DragDrop.setHandleElId()
17998 * @method regHandle
17999 * @param {String} sDDId the DragDrop id this element is a handle for
18000 * @param {String} sHandleId the id of the element that is the drag
18004 regHandle: function(sDDId, sHandleId) {
18005 if (!this.handleIds[sDDId]) {
18006 this.handleIds[sDDId] = {};
18008 this.handleIds[sDDId][sHandleId] = sHandleId;
18012 * Utility function to determine if a given element has been
18013 * registered as a drag drop item.
18014 * @method isDragDrop
18015 * @param {String} id the element id to check
18016 * @return {boolean} true if this element is a DragDrop item,
18020 isDragDrop: function(id) {
18021 return ( this.getDDById(id) ) ? true : false;
18025 * Returns the drag and drop instances that are in all groups the
18026 * passed in instance belongs to.
18027 * @method getRelated
18028 * @param {DragDrop} p_oDD the obj to get related data for
18029 * @param {boolean} bTargetsOnly if true, only return targetable objs
18030 * @return {DragDrop[]} the related instances
18033 getRelated: function(p_oDD, bTargetsOnly) {
18035 for (var i in p_oDD.groups) {
18036 for (j in this.ids[i]) {
18037 var dd = this.ids[i][j];
18038 if (! this.isTypeOfDD(dd)) {
18041 if (!bTargetsOnly || dd.isTarget) {
18042 oDDs[oDDs.length] = dd;
18051 * Returns true if the specified dd target is a legal target for
18052 * the specifice drag obj
18053 * @method isLegalTarget
18054 * @param {DragDrop} the drag obj
18055 * @param {DragDrop} the target
18056 * @return {boolean} true if the target is a legal target for the
18060 isLegalTarget: function (oDD, oTargetDD) {
18061 var targets = this.getRelated(oDD, true);
18062 for (var i=0, len=targets.length;i<len;++i) {
18063 if (targets[i].id == oTargetDD.id) {
18072 * My goal is to be able to transparently determine if an object is
18073 * typeof DragDrop, and the exact subclass of DragDrop. typeof
18074 * returns "object", oDD.constructor.toString() always returns
18075 * "DragDrop" and not the name of the subclass. So for now it just
18076 * evaluates a well-known variable in DragDrop.
18077 * @method isTypeOfDD
18078 * @param {Object} the object to evaluate
18079 * @return {boolean} true if typeof oDD = DragDrop
18082 isTypeOfDD: function (oDD) {
18083 return (oDD && oDD.__ygDragDrop);
18087 * Utility function to determine if a given element has been
18088 * registered as a drag drop handle for the given Drag Drop object.
18090 * @param {String} id the element id to check
18091 * @return {boolean} true if this element is a DragDrop handle, false
18095 isHandle: function(sDDId, sHandleId) {
18096 return ( this.handleIds[sDDId] &&
18097 this.handleIds[sDDId][sHandleId] );
18101 * Returns the DragDrop instance for a given id
18102 * @method getDDById
18103 * @param {String} id the id of the DragDrop object
18104 * @return {DragDrop} the drag drop object, null if it is not found
18107 getDDById: function(id) {
18108 for (var i in this.ids) {
18109 if (this.ids[i][id]) {
18110 return this.ids[i][id];
18117 * Fired after a registered DragDrop object gets the mousedown event.
18118 * Sets up the events required to track the object being dragged
18119 * @method handleMouseDown
18120 * @param {Event} e the event
18121 * @param oDD the DragDrop object being dragged
18125 handleMouseDown: function(e, oDD) {
18127 Roo.QuickTips.disable();
18129 this.currentTarget = e.getTarget();
18131 this.dragCurrent = oDD;
18133 var el = oDD.getEl();
18135 // track start position
18136 this.startX = e.getPageX();
18137 this.startY = e.getPageY();
18139 this.deltaX = this.startX - el.offsetLeft;
18140 this.deltaY = this.startY - el.offsetTop;
18142 this.dragThreshMet = false;
18144 this.clickTimeout = setTimeout(
18146 var DDM = Roo.dd.DDM;
18147 DDM.startDrag(DDM.startX, DDM.startY);
18149 this.clickTimeThresh );
18153 * Fired when either the drag pixel threshol or the mousedown hold
18154 * time threshold has been met.
18155 * @method startDrag
18156 * @param x {int} the X position of the original mousedown
18157 * @param y {int} the Y position of the original mousedown
18160 startDrag: function(x, y) {
18161 clearTimeout(this.clickTimeout);
18162 if (this.dragCurrent) {
18163 this.dragCurrent.b4StartDrag(x, y);
18164 this.dragCurrent.startDrag(x, y);
18166 this.dragThreshMet = true;
18170 * Internal function to handle the mouseup event. Will be invoked
18171 * from the context of the document.
18172 * @method handleMouseUp
18173 * @param {Event} e the event
18177 handleMouseUp: function(e) {
18180 Roo.QuickTips.enable();
18182 if (! this.dragCurrent) {
18186 clearTimeout(this.clickTimeout);
18188 if (this.dragThreshMet) {
18189 this.fireEvents(e, true);
18199 * Utility to stop event propagation and event default, if these
18200 * features are turned on.
18201 * @method stopEvent
18202 * @param {Event} e the event as returned by this.getEvent()
18205 stopEvent: function(e){
18206 if(this.stopPropagation) {
18207 e.stopPropagation();
18210 if (this.preventDefault) {
18211 e.preventDefault();
18216 * Internal function to clean up event handlers after the drag
18217 * operation is complete
18219 * @param {Event} e the event
18223 stopDrag: function(e) {
18224 // Fire the drag end event for the item that was dragged
18225 if (this.dragCurrent) {
18226 if (this.dragThreshMet) {
18227 this.dragCurrent.b4EndDrag(e);
18228 this.dragCurrent.endDrag(e);
18231 this.dragCurrent.onMouseUp(e);
18234 this.dragCurrent = null;
18235 this.dragOvers = {};
18239 * Internal function to handle the mousemove event. Will be invoked
18240 * from the context of the html element.
18242 * @TODO figure out what we can do about mouse events lost when the
18243 * user drags objects beyond the window boundary. Currently we can
18244 * detect this in internet explorer by verifying that the mouse is
18245 * down during the mousemove event. Firefox doesn't give us the
18246 * button state on the mousemove event.
18247 * @method handleMouseMove
18248 * @param {Event} e the event
18252 handleMouseMove: function(e) {
18253 if (! this.dragCurrent) {
18257 // var button = e.which || e.button;
18259 // check for IE mouseup outside of page boundary
18260 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
18262 return this.handleMouseUp(e);
18265 if (!this.dragThreshMet) {
18266 var diffX = Math.abs(this.startX - e.getPageX());
18267 var diffY = Math.abs(this.startY - e.getPageY());
18268 if (diffX > this.clickPixelThresh ||
18269 diffY > this.clickPixelThresh) {
18270 this.startDrag(this.startX, this.startY);
18274 if (this.dragThreshMet) {
18275 this.dragCurrent.b4Drag(e);
18276 this.dragCurrent.onDrag(e);
18277 if(!this.dragCurrent.moveOnly){
18278 this.fireEvents(e, false);
18288 * Iterates over all of the DragDrop elements to find ones we are
18289 * hovering over or dropping on
18290 * @method fireEvents
18291 * @param {Event} e the event
18292 * @param {boolean} isDrop is this a drop op or a mouseover op?
18296 fireEvents: function(e, isDrop) {
18297 var dc = this.dragCurrent;
18299 // If the user did the mouse up outside of the window, we could
18300 // get here even though we have ended the drag.
18301 if (!dc || dc.isLocked()) {
18305 var pt = e.getPoint();
18307 // cache the previous dragOver array
18313 var enterEvts = [];
18315 // Check to see if the object(s) we were hovering over is no longer
18316 // being hovered over so we can fire the onDragOut event
18317 for (var i in this.dragOvers) {
18319 var ddo = this.dragOvers[i];
18321 if (! this.isTypeOfDD(ddo)) {
18325 if (! this.isOverTarget(pt, ddo, this.mode)) {
18326 outEvts.push( ddo );
18329 oldOvers[i] = true;
18330 delete this.dragOvers[i];
18333 for (var sGroup in dc.groups) {
18335 if ("string" != typeof sGroup) {
18339 for (i in this.ids[sGroup]) {
18340 var oDD = this.ids[sGroup][i];
18341 if (! this.isTypeOfDD(oDD)) {
18345 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
18346 if (this.isOverTarget(pt, oDD, this.mode)) {
18347 // look for drop interactions
18349 dropEvts.push( oDD );
18350 // look for drag enter and drag over interactions
18353 // initial drag over: dragEnter fires
18354 if (!oldOvers[oDD.id]) {
18355 enterEvts.push( oDD );
18356 // subsequent drag overs: dragOver fires
18358 overEvts.push( oDD );
18361 this.dragOvers[oDD.id] = oDD;
18369 if (outEvts.length) {
18370 dc.b4DragOut(e, outEvts);
18371 dc.onDragOut(e, outEvts);
18374 if (enterEvts.length) {
18375 dc.onDragEnter(e, enterEvts);
18378 if (overEvts.length) {
18379 dc.b4DragOver(e, overEvts);
18380 dc.onDragOver(e, overEvts);
18383 if (dropEvts.length) {
18384 dc.b4DragDrop(e, dropEvts);
18385 dc.onDragDrop(e, dropEvts);
18389 // fire dragout events
18391 for (i=0, len=outEvts.length; i<len; ++i) {
18392 dc.b4DragOut(e, outEvts[i].id);
18393 dc.onDragOut(e, outEvts[i].id);
18396 // fire enter events
18397 for (i=0,len=enterEvts.length; i<len; ++i) {
18398 // dc.b4DragEnter(e, oDD.id);
18399 dc.onDragEnter(e, enterEvts[i].id);
18402 // fire over events
18403 for (i=0,len=overEvts.length; i<len; ++i) {
18404 dc.b4DragOver(e, overEvts[i].id);
18405 dc.onDragOver(e, overEvts[i].id);
18408 // fire drop events
18409 for (i=0, len=dropEvts.length; i<len; ++i) {
18410 dc.b4DragDrop(e, dropEvts[i].id);
18411 dc.onDragDrop(e, dropEvts[i].id);
18416 // notify about a drop that did not find a target
18417 if (isDrop && !dropEvts.length) {
18418 dc.onInvalidDrop(e);
18424 * Helper function for getting the best match from the list of drag
18425 * and drop objects returned by the drag and drop events when we are
18426 * in INTERSECT mode. It returns either the first object that the
18427 * cursor is over, or the object that has the greatest overlap with
18428 * the dragged element.
18429 * @method getBestMatch
18430 * @param {DragDrop[]} dds The array of drag and drop objects
18432 * @return {DragDrop} The best single match
18435 getBestMatch: function(dds) {
18437 // Return null if the input is not what we expect
18438 //if (!dds || !dds.length || dds.length == 0) {
18440 // If there is only one item, it wins
18441 //} else if (dds.length == 1) {
18443 var len = dds.length;
18448 // Loop through the targeted items
18449 for (var i=0; i<len; ++i) {
18451 // If the cursor is over the object, it wins. If the
18452 // cursor is over multiple matches, the first one we come
18454 if (dd.cursorIsOver) {
18457 // Otherwise the object with the most overlap wins
18460 winner.overlap.getArea() < dd.overlap.getArea()) {
18471 * Refreshes the cache of the top-left and bottom-right points of the
18472 * drag and drop objects in the specified group(s). This is in the
18473 * format that is stored in the drag and drop instance, so typical
18476 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
18480 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
18482 * @TODO this really should be an indexed array. Alternatively this
18483 * method could accept both.
18484 * @method refreshCache
18485 * @param {Object} groups an associative array of groups to refresh
18488 refreshCache: function(groups) {
18489 for (var sGroup in groups) {
18490 if ("string" != typeof sGroup) {
18493 for (var i in this.ids[sGroup]) {
18494 var oDD = this.ids[sGroup][i];
18496 if (this.isTypeOfDD(oDD)) {
18497 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
18498 var loc = this.getLocation(oDD);
18500 this.locationCache[oDD.id] = loc;
18502 delete this.locationCache[oDD.id];
18503 // this will unregister the drag and drop object if
18504 // the element is not in a usable state
18513 * This checks to make sure an element exists and is in the DOM. The
18514 * main purpose is to handle cases where innerHTML is used to remove
18515 * drag and drop objects from the DOM. IE provides an 'unspecified
18516 * error' when trying to access the offsetParent of such an element
18518 * @param {HTMLElement} el the element to check
18519 * @return {boolean} true if the element looks usable
18522 verifyEl: function(el) {
18527 parent = el.offsetParent;
18530 parent = el.offsetParent;
18541 * Returns a Region object containing the drag and drop element's position
18542 * and size, including the padding configured for it
18543 * @method getLocation
18544 * @param {DragDrop} oDD the drag and drop object to get the
18546 * @return {Roo.lib.Region} a Region object representing the total area
18547 * the element occupies, including any padding
18548 * the instance is configured for.
18551 getLocation: function(oDD) {
18552 if (! this.isTypeOfDD(oDD)) {
18556 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
18559 pos= Roo.lib.Dom.getXY(el);
18567 x2 = x1 + el.offsetWidth;
18569 y2 = y1 + el.offsetHeight;
18571 t = y1 - oDD.padding[0];
18572 r = x2 + oDD.padding[1];
18573 b = y2 + oDD.padding[2];
18574 l = x1 - oDD.padding[3];
18576 return new Roo.lib.Region( t, r, b, l );
18580 * Checks the cursor location to see if it over the target
18581 * @method isOverTarget
18582 * @param {Roo.lib.Point} pt The point to evaluate
18583 * @param {DragDrop} oTarget the DragDrop object we are inspecting
18584 * @return {boolean} true if the mouse is over the target
18588 isOverTarget: function(pt, oTarget, intersect) {
18589 // use cache if available
18590 var loc = this.locationCache[oTarget.id];
18591 if (!loc || !this.useCache) {
18592 loc = this.getLocation(oTarget);
18593 this.locationCache[oTarget.id] = loc;
18601 oTarget.cursorIsOver = loc.contains( pt );
18603 // DragDrop is using this as a sanity check for the initial mousedown
18604 // in this case we are done. In POINT mode, if the drag obj has no
18605 // contraints, we are also done. Otherwise we need to evaluate the
18606 // location of the target as related to the actual location of the
18607 // dragged element.
18608 var dc = this.dragCurrent;
18609 if (!dc || !dc.getTargetCoord ||
18610 (!intersect && !dc.constrainX && !dc.constrainY)) {
18611 return oTarget.cursorIsOver;
18614 oTarget.overlap = null;
18616 // Get the current location of the drag element, this is the
18617 // location of the mouse event less the delta that represents
18618 // where the original mousedown happened on the element. We
18619 // need to consider constraints and ticks as well.
18620 var pos = dc.getTargetCoord(pt.x, pt.y);
18622 var el = dc.getDragEl();
18623 var curRegion = new Roo.lib.Region( pos.y,
18624 pos.x + el.offsetWidth,
18625 pos.y + el.offsetHeight,
18628 var overlap = curRegion.intersect(loc);
18631 oTarget.overlap = overlap;
18632 return (intersect) ? true : oTarget.cursorIsOver;
18639 * unload event handler
18640 * @method _onUnload
18644 _onUnload: function(e, me) {
18645 Roo.dd.DragDropMgr.unregAll();
18649 * Cleans up the drag and drop events and objects.
18654 unregAll: function() {
18656 if (this.dragCurrent) {
18658 this.dragCurrent = null;
18661 this._execOnAll("unreg", []);
18663 for (i in this.elementCache) {
18664 delete this.elementCache[i];
18667 this.elementCache = {};
18672 * A cache of DOM elements
18673 * @property elementCache
18680 * Get the wrapper for the DOM element specified
18681 * @method getElWrapper
18682 * @param {String} id the id of the element to get
18683 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
18685 * @deprecated This wrapper isn't that useful
18688 getElWrapper: function(id) {
18689 var oWrapper = this.elementCache[id];
18690 if (!oWrapper || !oWrapper.el) {
18691 oWrapper = this.elementCache[id] =
18692 new this.ElementWrapper(Roo.getDom(id));
18698 * Returns the actual DOM element
18699 * @method getElement
18700 * @param {String} id the id of the elment to get
18701 * @return {Object} The element
18702 * @deprecated use Roo.getDom instead
18705 getElement: function(id) {
18706 return Roo.getDom(id);
18710 * Returns the style property for the DOM element (i.e.,
18711 * document.getElById(id).style)
18713 * @param {String} id the id of the elment to get
18714 * @return {Object} The style property of the element
18715 * @deprecated use Roo.getDom instead
18718 getCss: function(id) {
18719 var el = Roo.getDom(id);
18720 return (el) ? el.style : null;
18724 * Inner class for cached elements
18725 * @class DragDropMgr.ElementWrapper
18730 ElementWrapper: function(el) {
18735 this.el = el || null;
18740 this.id = this.el && el.id;
18742 * A reference to the style property
18745 this.css = this.el && el.style;
18749 * Returns the X position of an html element
18751 * @param el the element for which to get the position
18752 * @return {int} the X coordinate
18754 * @deprecated use Roo.lib.Dom.getX instead
18757 getPosX: function(el) {
18758 return Roo.lib.Dom.getX(el);
18762 * Returns the Y position of an html element
18764 * @param el the element for which to get the position
18765 * @return {int} the Y coordinate
18766 * @deprecated use Roo.lib.Dom.getY instead
18769 getPosY: function(el) {
18770 return Roo.lib.Dom.getY(el);
18774 * Swap two nodes. In IE, we use the native method, for others we
18775 * emulate the IE behavior
18777 * @param n1 the first node to swap
18778 * @param n2 the other node to swap
18781 swapNode: function(n1, n2) {
18785 var p = n2.parentNode;
18786 var s = n2.nextSibling;
18789 p.insertBefore(n1, n2);
18790 } else if (n2 == n1.nextSibling) {
18791 p.insertBefore(n2, n1);
18793 n1.parentNode.replaceChild(n2, n1);
18794 p.insertBefore(n1, s);
18800 * Returns the current scroll position
18801 * @method getScroll
18805 getScroll: function () {
18806 var t, l, dde=document.documentElement, db=document.body;
18807 if (dde && (dde.scrollTop || dde.scrollLeft)) {
18809 l = dde.scrollLeft;
18816 return { top: t, left: l };
18820 * Returns the specified element style property
18822 * @param {HTMLElement} el the element
18823 * @param {string} styleProp the style property
18824 * @return {string} The value of the style property
18825 * @deprecated use Roo.lib.Dom.getStyle
18828 getStyle: function(el, styleProp) {
18829 return Roo.fly(el).getStyle(styleProp);
18833 * Gets the scrollTop
18834 * @method getScrollTop
18835 * @return {int} the document's scrollTop
18838 getScrollTop: function () { return this.getScroll().top; },
18841 * Gets the scrollLeft
18842 * @method getScrollLeft
18843 * @return {int} the document's scrollTop
18846 getScrollLeft: function () { return this.getScroll().left; },
18849 * Sets the x/y position of an element to the location of the
18852 * @param {HTMLElement} moveEl The element to move
18853 * @param {HTMLElement} targetEl The position reference element
18856 moveToEl: function (moveEl, targetEl) {
18857 var aCoord = Roo.lib.Dom.getXY(targetEl);
18858 Roo.lib.Dom.setXY(moveEl, aCoord);
18862 * Numeric array sort function
18863 * @method numericSort
18866 numericSort: function(a, b) { return (a - b); },
18870 * @property _timeoutCount
18877 * Trying to make the load order less important. Without this we get
18878 * an error if this file is loaded before the Event Utility.
18879 * @method _addListeners
18883 _addListeners: function() {
18884 var DDM = Roo.dd.DDM;
18885 if ( Roo.lib.Event && document ) {
18888 if (DDM._timeoutCount > 2000) {
18890 setTimeout(DDM._addListeners, 10);
18891 if (document && document.body) {
18892 DDM._timeoutCount += 1;
18899 * Recursively searches the immediate parent and all child nodes for
18900 * the handle element in order to determine wheter or not it was
18902 * @method handleWasClicked
18903 * @param node the html element to inspect
18906 handleWasClicked: function(node, id) {
18907 if (this.isHandle(id, node.id)) {
18910 // check to see if this is a text node child of the one we want
18911 var p = node.parentNode;
18914 if (this.isHandle(id, p.id)) {
18929 // shorter alias, save a few bytes
18930 Roo.dd.DDM = Roo.dd.DragDropMgr;
18931 Roo.dd.DDM._addListeners();
18935 * Ext JS Library 1.1.1
18936 * Copyright(c) 2006-2007, Ext JS, LLC.
18938 * Originally Released Under LGPL - original licence link has changed is not relivant.
18941 * <script type="text/javascript">
18946 * A DragDrop implementation where the linked element follows the
18947 * mouse cursor during a drag.
18948 * @extends Roo.dd.DragDrop
18950 * @param {String} id the id of the linked element
18951 * @param {String} sGroup the group of related DragDrop items
18952 * @param {object} config an object containing configurable attributes
18953 * Valid properties for DD:
18956 Roo.dd.DD = function(id, sGroup, config) {
18958 this.init(id, sGroup, config);
18962 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
18965 * When set to true, the utility automatically tries to scroll the browser
18966 * window wehn a drag and drop element is dragged near the viewport boundary.
18967 * Defaults to true.
18974 * Sets the pointer offset to the distance between the linked element's top
18975 * left corner and the location the element was clicked
18976 * @method autoOffset
18977 * @param {int} iPageX the X coordinate of the click
18978 * @param {int} iPageY the Y coordinate of the click
18980 autoOffset: function(iPageX, iPageY) {
18981 var x = iPageX - this.startPageX;
18982 var y = iPageY - this.startPageY;
18983 this.setDelta(x, y);
18987 * Sets the pointer offset. You can call this directly to force the
18988 * offset to be in a particular location (e.g., pass in 0,0 to set it
18989 * to the center of the object)
18991 * @param {int} iDeltaX the distance from the left
18992 * @param {int} iDeltaY the distance from the top
18994 setDelta: function(iDeltaX, iDeltaY) {
18995 this.deltaX = iDeltaX;
18996 this.deltaY = iDeltaY;
19000 * Sets the drag element to the location of the mousedown or click event,
19001 * maintaining the cursor location relative to the location on the element
19002 * that was clicked. Override this if you want to place the element in a
19003 * location other than where the cursor is.
19004 * @method setDragElPos
19005 * @param {int} iPageX the X coordinate of the mousedown or drag event
19006 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19008 setDragElPos: function(iPageX, iPageY) {
19009 // the first time we do this, we are going to check to make sure
19010 // the element has css positioning
19012 var el = this.getDragEl();
19013 this.alignElWithMouse(el, iPageX, iPageY);
19017 * Sets the element to the location of the mousedown or click event,
19018 * maintaining the cursor location relative to the location on the element
19019 * that was clicked. Override this if you want to place the element in a
19020 * location other than where the cursor is.
19021 * @method alignElWithMouse
19022 * @param {HTMLElement} el the element to move
19023 * @param {int} iPageX the X coordinate of the mousedown or drag event
19024 * @param {int} iPageY the Y coordinate of the mousedown or drag event
19026 alignElWithMouse: function(el, iPageX, iPageY) {
19027 var oCoord = this.getTargetCoord(iPageX, iPageY);
19028 var fly = el.dom ? el : Roo.fly(el);
19029 if (!this.deltaSetXY) {
19030 var aCoord = [oCoord.x, oCoord.y];
19032 var newLeft = fly.getLeft(true);
19033 var newTop = fly.getTop(true);
19034 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
19036 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
19039 this.cachePosition(oCoord.x, oCoord.y);
19040 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
19045 * Saves the most recent position so that we can reset the constraints and
19046 * tick marks on-demand. We need to know this so that we can calculate the
19047 * number of pixels the element is offset from its original position.
19048 * @method cachePosition
19049 * @param iPageX the current x position (optional, this just makes it so we
19050 * don't have to look it up again)
19051 * @param iPageY the current y position (optional, this just makes it so we
19052 * don't have to look it up again)
19054 cachePosition: function(iPageX, iPageY) {
19056 this.lastPageX = iPageX;
19057 this.lastPageY = iPageY;
19059 var aCoord = Roo.lib.Dom.getXY(this.getEl());
19060 this.lastPageX = aCoord[0];
19061 this.lastPageY = aCoord[1];
19066 * Auto-scroll the window if the dragged object has been moved beyond the
19067 * visible window boundary.
19068 * @method autoScroll
19069 * @param {int} x the drag element's x position
19070 * @param {int} y the drag element's y position
19071 * @param {int} h the height of the drag element
19072 * @param {int} w the width of the drag element
19075 autoScroll: function(x, y, h, w) {
19078 // The client height
19079 var clientH = Roo.lib.Dom.getViewWidth();
19081 // The client width
19082 var clientW = Roo.lib.Dom.getViewHeight();
19084 // The amt scrolled down
19085 var st = this.DDM.getScrollTop();
19087 // The amt scrolled right
19088 var sl = this.DDM.getScrollLeft();
19090 // Location of the bottom of the element
19093 // Location of the right of the element
19096 // The distance from the cursor to the bottom of the visible area,
19097 // adjusted so that we don't scroll if the cursor is beyond the
19098 // element drag constraints
19099 var toBot = (clientH + st - y - this.deltaY);
19101 // The distance from the cursor to the right of the visible area
19102 var toRight = (clientW + sl - x - this.deltaX);
19105 // How close to the edge the cursor must be before we scroll
19106 // var thresh = (document.all) ? 100 : 40;
19109 // How many pixels to scroll per autoscroll op. This helps to reduce
19110 // clunky scrolling. IE is more sensitive about this ... it needs this
19111 // value to be higher.
19112 var scrAmt = (document.all) ? 80 : 30;
19114 // Scroll down if we are near the bottom of the visible page and the
19115 // obj extends below the crease
19116 if ( bot > clientH && toBot < thresh ) {
19117 window.scrollTo(sl, st + scrAmt);
19120 // Scroll up if the window is scrolled down and the top of the object
19121 // goes above the top border
19122 if ( y < st && st > 0 && y - st < thresh ) {
19123 window.scrollTo(sl, st - scrAmt);
19126 // Scroll right if the obj is beyond the right border and the cursor is
19127 // near the border.
19128 if ( right > clientW && toRight < thresh ) {
19129 window.scrollTo(sl + scrAmt, st);
19132 // Scroll left if the window has been scrolled to the right and the obj
19133 // extends past the left border
19134 if ( x < sl && sl > 0 && x - sl < thresh ) {
19135 window.scrollTo(sl - scrAmt, st);
19141 * Finds the location the element should be placed if we want to move
19142 * it to where the mouse location less the click offset would place us.
19143 * @method getTargetCoord
19144 * @param {int} iPageX the X coordinate of the click
19145 * @param {int} iPageY the Y coordinate of the click
19146 * @return an object that contains the coordinates (Object.x and Object.y)
19149 getTargetCoord: function(iPageX, iPageY) {
19152 var x = iPageX - this.deltaX;
19153 var y = iPageY - this.deltaY;
19155 if (this.constrainX) {
19156 if (x < this.minX) { x = this.minX; }
19157 if (x > this.maxX) { x = this.maxX; }
19160 if (this.constrainY) {
19161 if (y < this.minY) { y = this.minY; }
19162 if (y > this.maxY) { y = this.maxY; }
19165 x = this.getTick(x, this.xTicks);
19166 y = this.getTick(y, this.yTicks);
19173 * Sets up config options specific to this class. Overrides
19174 * Roo.dd.DragDrop, but all versions of this method through the
19175 * inheritance chain are called
19177 applyConfig: function() {
19178 Roo.dd.DD.superclass.applyConfig.call(this);
19179 this.scroll = (this.config.scroll !== false);
19183 * Event that fires prior to the onMouseDown event. Overrides
19186 b4MouseDown: function(e) {
19187 // this.resetConstraints();
19188 this.autoOffset(e.getPageX(),
19193 * Event that fires prior to the onDrag event. Overrides
19196 b4Drag: function(e) {
19197 this.setDragElPos(e.getPageX(),
19201 toString: function() {
19202 return ("DD " + this.id);
19205 //////////////////////////////////////////////////////////////////////////
19206 // Debugging ygDragDrop events that can be overridden
19207 //////////////////////////////////////////////////////////////////////////
19209 startDrag: function(x, y) {
19212 onDrag: function(e) {
19215 onDragEnter: function(e, id) {
19218 onDragOver: function(e, id) {
19221 onDragOut: function(e, id) {
19224 onDragDrop: function(e, id) {
19227 endDrag: function(e) {
19234 * Ext JS Library 1.1.1
19235 * Copyright(c) 2006-2007, Ext JS, LLC.
19237 * Originally Released Under LGPL - original licence link has changed is not relivant.
19240 * <script type="text/javascript">
19244 * @class Roo.dd.DDProxy
19245 * A DragDrop implementation that inserts an empty, bordered div into
19246 * the document that follows the cursor during drag operations. At the time of
19247 * the click, the frame div is resized to the dimensions of the linked html
19248 * element, and moved to the exact location of the linked element.
19250 * References to the "frame" element refer to the single proxy element that
19251 * was created to be dragged in place of all DDProxy elements on the
19254 * @extends Roo.dd.DD
19256 * @param {String} id the id of the linked html element
19257 * @param {String} sGroup the group of related DragDrop objects
19258 * @param {object} config an object containing configurable attributes
19259 * Valid properties for DDProxy in addition to those in DragDrop:
19260 * resizeFrame, centerFrame, dragElId
19262 Roo.dd.DDProxy = function(id, sGroup, config) {
19264 this.init(id, sGroup, config);
19270 * The default drag frame div id
19271 * @property Roo.dd.DDProxy.dragElId
19275 Roo.dd.DDProxy.dragElId = "ygddfdiv";
19277 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
19280 * By default we resize the drag frame to be the same size as the element
19281 * we want to drag (this is to get the frame effect). We can turn it off
19282 * if we want a different behavior.
19283 * @property resizeFrame
19289 * By default the frame is positioned exactly where the drag element is, so
19290 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
19291 * you do not have constraints on the obj is to have the drag frame centered
19292 * around the cursor. Set centerFrame to true for this effect.
19293 * @property centerFrame
19296 centerFrame: false,
19299 * Creates the proxy element if it does not yet exist
19300 * @method createFrame
19302 createFrame: function() {
19304 var body = document.body;
19306 if (!body || !body.firstChild) {
19307 setTimeout( function() { self.createFrame(); }, 50 );
19311 var div = this.getDragEl();
19314 div = document.createElement("div");
19315 div.id = this.dragElId;
19318 s.position = "absolute";
19319 s.visibility = "hidden";
19321 s.border = "2px solid #aaa";
19324 // appendChild can blow up IE if invoked prior to the window load event
19325 // while rendering a table. It is possible there are other scenarios
19326 // that would cause this to happen as well.
19327 body.insertBefore(div, body.firstChild);
19332 * Initialization for the drag frame element. Must be called in the
19333 * constructor of all subclasses
19334 * @method initFrame
19336 initFrame: function() {
19337 this.createFrame();
19340 applyConfig: function() {
19341 Roo.dd.DDProxy.superclass.applyConfig.call(this);
19343 this.resizeFrame = (this.config.resizeFrame !== false);
19344 this.centerFrame = (this.config.centerFrame);
19345 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
19349 * Resizes the drag frame to the dimensions of the clicked object, positions
19350 * it over the object, and finally displays it
19351 * @method showFrame
19352 * @param {int} iPageX X click position
19353 * @param {int} iPageY Y click position
19356 showFrame: function(iPageX, iPageY) {
19357 var el = this.getEl();
19358 var dragEl = this.getDragEl();
19359 var s = dragEl.style;
19361 this._resizeProxy();
19363 if (this.centerFrame) {
19364 this.setDelta( Math.round(parseInt(s.width, 10)/2),
19365 Math.round(parseInt(s.height, 10)/2) );
19368 this.setDragElPos(iPageX, iPageY);
19370 Roo.fly(dragEl).show();
19374 * The proxy is automatically resized to the dimensions of the linked
19375 * element when a drag is initiated, unless resizeFrame is set to false
19376 * @method _resizeProxy
19379 _resizeProxy: function() {
19380 if (this.resizeFrame) {
19381 var el = this.getEl();
19382 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
19386 // overrides Roo.dd.DragDrop
19387 b4MouseDown: function(e) {
19388 var x = e.getPageX();
19389 var y = e.getPageY();
19390 this.autoOffset(x, y);
19391 this.setDragElPos(x, y);
19394 // overrides Roo.dd.DragDrop
19395 b4StartDrag: function(x, y) {
19396 // show the drag frame
19397 this.showFrame(x, y);
19400 // overrides Roo.dd.DragDrop
19401 b4EndDrag: function(e) {
19402 Roo.fly(this.getDragEl()).hide();
19405 // overrides Roo.dd.DragDrop
19406 // By default we try to move the element to the last location of the frame.
19407 // This is so that the default behavior mirrors that of Roo.dd.DD.
19408 endDrag: function(e) {
19410 var lel = this.getEl();
19411 var del = this.getDragEl();
19413 // Show the drag frame briefly so we can get its position
19414 del.style.visibility = "";
19417 // Hide the linked element before the move to get around a Safari
19419 lel.style.visibility = "hidden";
19420 Roo.dd.DDM.moveToEl(lel, del);
19421 del.style.visibility = "hidden";
19422 lel.style.visibility = "";
19427 beforeMove : function(){
19431 afterDrag : function(){
19435 toString: function() {
19436 return ("DDProxy " + this.id);
19442 * Ext JS Library 1.1.1
19443 * Copyright(c) 2006-2007, Ext JS, LLC.
19445 * Originally Released Under LGPL - original licence link has changed is not relivant.
19448 * <script type="text/javascript">
19452 * @class Roo.dd.DDTarget
19453 * A DragDrop implementation that does not move, but can be a drop
19454 * target. You would get the same result by simply omitting implementation
19455 * for the event callbacks, but this way we reduce the processing cost of the
19456 * event listener and the callbacks.
19457 * @extends Roo.dd.DragDrop
19459 * @param {String} id the id of the element that is a drop target
19460 * @param {String} sGroup the group of related DragDrop objects
19461 * @param {object} config an object containing configurable attributes
19462 * Valid properties for DDTarget in addition to those in
19466 Roo.dd.DDTarget = function(id, sGroup, config) {
19468 this.initTarget(id, sGroup, config);
19470 if (config.listeners || config.events) {
19471 Roo.dd.DragDrop.superclass.constructor.call(this, {
19472 listeners : config.listeners || {},
19473 events : config.events || {}
19478 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
19479 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
19480 toString: function() {
19481 return ("DDTarget " + this.id);
19486 * Ext JS Library 1.1.1
19487 * Copyright(c) 2006-2007, Ext JS, LLC.
19489 * Originally Released Under LGPL - original licence link has changed is not relivant.
19492 * <script type="text/javascript">
19497 * @class Roo.dd.ScrollManager
19498 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
19499 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
19502 Roo.dd.ScrollManager = function(){
19503 var ddm = Roo.dd.DragDropMgr;
19510 var onStop = function(e){
19515 var triggerRefresh = function(){
19516 if(ddm.dragCurrent){
19517 ddm.refreshCache(ddm.dragCurrent.groups);
19521 var doScroll = function(){
19522 if(ddm.dragCurrent){
19523 var dds = Roo.dd.ScrollManager;
19525 if(proc.el.scroll(proc.dir, dds.increment)){
19529 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
19534 var clearProc = function(){
19536 clearInterval(proc.id);
19543 var startProc = function(el, dir){
19544 Roo.log('scroll startproc');
19548 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
19551 var onFire = function(e, isDrop){
19553 if(isDrop || !ddm.dragCurrent){ return; }
19554 var dds = Roo.dd.ScrollManager;
19555 if(!dragEl || dragEl != ddm.dragCurrent){
19556 dragEl = ddm.dragCurrent;
19557 // refresh regions on drag start
19558 dds.refreshCache();
19561 var xy = Roo.lib.Event.getXY(e);
19562 var pt = new Roo.lib.Point(xy[0], xy[1]);
19563 for(var id in els){
19564 var el = els[id], r = el._region;
19565 if(r && r.contains(pt) && el.isScrollable()){
19566 if(r.bottom - pt.y <= dds.thresh){
19568 startProc(el, "down");
19571 }else if(r.right - pt.x <= dds.thresh){
19573 startProc(el, "left");
19576 }else if(pt.y - r.top <= dds.thresh){
19578 startProc(el, "up");
19581 }else if(pt.x - r.left <= dds.thresh){
19583 startProc(el, "right");
19592 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
19593 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
19597 * Registers new overflow element(s) to auto scroll
19598 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
19600 register : function(el){
19601 if(el instanceof Array){
19602 for(var i = 0, len = el.length; i < len; i++) {
19603 this.register(el[i]);
19609 Roo.dd.ScrollManager.els = els;
19613 * Unregisters overflow element(s) so they are no longer scrolled
19614 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
19616 unregister : function(el){
19617 if(el instanceof Array){
19618 for(var i = 0, len = el.length; i < len; i++) {
19619 this.unregister(el[i]);
19628 * The number of pixels from the edge of a container the pointer needs to be to
19629 * trigger scrolling (defaults to 25)
19635 * The number of pixels to scroll in each scroll increment (defaults to 50)
19641 * The frequency of scrolls in milliseconds (defaults to 500)
19647 * True to animate the scroll (defaults to true)
19653 * The animation duration in seconds -
19654 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
19660 * Manually trigger a cache refresh.
19662 refreshCache : function(){
19663 for(var id in els){
19664 if(typeof els[id] == 'object'){ // for people extending the object prototype
19665 els[id]._region = els[id].getRegion();
19672 * Ext JS Library 1.1.1
19673 * Copyright(c) 2006-2007, Ext JS, LLC.
19675 * Originally Released Under LGPL - original licence link has changed is not relivant.
19678 * <script type="text/javascript">
19683 * @class Roo.dd.Registry
19684 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
19685 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
19688 Roo.dd.Registry = function(){
19691 var autoIdSeed = 0;
19693 var getId = function(el, autogen){
19694 if(typeof el == "string"){
19698 if(!id && autogen !== false){
19699 id = "roodd-" + (++autoIdSeed);
19707 * Register a drag drop element
19708 * @param {String|HTMLElement} element The id or DOM node to register
19709 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
19710 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
19711 * knows how to interpret, plus there are some specific properties known to the Registry that should be
19712 * populated in the data object (if applicable):
19714 Value Description<br />
19715 --------- ------------------------------------------<br />
19716 handles Array of DOM nodes that trigger dragging<br />
19717 for the element being registered<br />
19718 isHandle True if the element passed in triggers<br />
19719 dragging itself, else false
19722 register : function(el, data){
19724 if(typeof el == "string"){
19725 el = document.getElementById(el);
19728 elements[getId(el)] = data;
19729 if(data.isHandle !== false){
19730 handles[data.ddel.id] = data;
19733 var hs = data.handles;
19734 for(var i = 0, len = hs.length; i < len; i++){
19735 handles[getId(hs[i])] = data;
19741 * Unregister a drag drop element
19742 * @param {String|HTMLElement} element The id or DOM node to unregister
19744 unregister : function(el){
19745 var id = getId(el, false);
19746 var data = elements[id];
19748 delete elements[id];
19750 var hs = data.handles;
19751 for(var i = 0, len = hs.length; i < len; i++){
19752 delete handles[getId(hs[i], false)];
19759 * Returns the handle registered for a DOM Node by id
19760 * @param {String|HTMLElement} id The DOM node or id to look up
19761 * @return {Object} handle The custom handle data
19763 getHandle : function(id){
19764 if(typeof id != "string"){ // must be element?
19767 return handles[id];
19771 * Returns the handle that is registered for the DOM node that is the target of the event
19772 * @param {Event} e The event
19773 * @return {Object} handle The custom handle data
19775 getHandleFromEvent : function(e){
19776 var t = Roo.lib.Event.getTarget(e);
19777 return t ? handles[t.id] : null;
19781 * Returns a custom data object that is registered for a DOM node by id
19782 * @param {String|HTMLElement} id The DOM node or id to look up
19783 * @return {Object} data The custom data
19785 getTarget : function(id){
19786 if(typeof id != "string"){ // must be element?
19789 return elements[id];
19793 * Returns a custom data object that is registered for the DOM node that is the target of the event
19794 * @param {Event} e The event
19795 * @return {Object} data The custom data
19797 getTargetFromEvent : function(e){
19798 var t = Roo.lib.Event.getTarget(e);
19799 return t ? elements[t.id] || handles[t.id] : null;
19804 * Ext JS Library 1.1.1
19805 * Copyright(c) 2006-2007, Ext JS, LLC.
19807 * Originally Released Under LGPL - original licence link has changed is not relivant.
19810 * <script type="text/javascript">
19815 * @class Roo.dd.StatusProxy
19816 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
19817 * default drag proxy used by all Roo.dd components.
19819 * @param {Object} config
19821 Roo.dd.StatusProxy = function(config){
19822 Roo.apply(this, config);
19823 this.id = this.id || Roo.id();
19824 this.el = new Roo.Layer({
19826 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
19827 {tag: "div", cls: "x-dd-drop-icon"},
19828 {tag: "div", cls: "x-dd-drag-ghost"}
19831 shadow: !config || config.shadow !== false
19833 this.ghost = Roo.get(this.el.dom.childNodes[1]);
19834 this.dropStatus = this.dropNotAllowed;
19837 Roo.dd.StatusProxy.prototype = {
19839 * @cfg {String} dropAllowed
19840 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
19842 dropAllowed : "x-dd-drop-ok",
19844 * @cfg {String} dropNotAllowed
19845 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
19847 dropNotAllowed : "x-dd-drop-nodrop",
19850 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
19851 * over the current target element.
19852 * @param {String} cssClass The css class for the new drop status indicator image
19854 setStatus : function(cssClass){
19855 cssClass = cssClass || this.dropNotAllowed;
19856 if(this.dropStatus != cssClass){
19857 this.el.replaceClass(this.dropStatus, cssClass);
19858 this.dropStatus = cssClass;
19863 * Resets the status indicator to the default dropNotAllowed value
19864 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
19866 reset : function(clearGhost){
19867 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
19868 this.dropStatus = this.dropNotAllowed;
19870 this.ghost.update("");
19875 * Updates the contents of the ghost element
19876 * @param {String} html The html that will replace the current innerHTML of the ghost element
19878 update : function(html){
19879 if(typeof html == "string"){
19880 this.ghost.update(html);
19882 this.ghost.update("");
19883 html.style.margin = "0";
19884 this.ghost.dom.appendChild(html);
19886 // ensure float = none set?? cant remember why though.
19887 var el = this.ghost.dom.firstChild;
19889 Roo.fly(el).setStyle('float', 'none');
19894 * Returns the underlying proxy {@link Roo.Layer}
19895 * @return {Roo.Layer} el
19897 getEl : function(){
19902 * Returns the ghost element
19903 * @return {Roo.Element} el
19905 getGhost : function(){
19911 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
19913 hide : function(clear){
19921 * Stops the repair animation if it's currently running
19924 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
19930 * Displays this proxy
19937 * Force the Layer to sync its shadow and shim positions to the element
19944 * Causes the proxy to return to its position of origin via an animation. Should be called after an
19945 * invalid drop operation by the item being dragged.
19946 * @param {Array} xy The XY position of the element ([x, y])
19947 * @param {Function} callback The function to call after the repair is complete
19948 * @param {Object} scope The scope in which to execute the callback
19950 repair : function(xy, callback, scope){
19951 this.callback = callback;
19952 this.scope = scope;
19953 if(xy && this.animRepair !== false){
19954 this.el.addClass("x-dd-drag-repair");
19955 this.el.hideUnders(true);
19956 this.anim = this.el.shift({
19957 duration: this.repairDuration || .5,
19961 callback: this.afterRepair,
19965 this.afterRepair();
19970 afterRepair : function(){
19972 if(typeof this.callback == "function"){
19973 this.callback.call(this.scope || this);
19975 this.callback = null;
19980 * Ext JS Library 1.1.1
19981 * Copyright(c) 2006-2007, Ext JS, LLC.
19983 * Originally Released Under LGPL - original licence link has changed is not relivant.
19986 * <script type="text/javascript">
19990 * @class Roo.dd.DragSource
19991 * @extends Roo.dd.DDProxy
19992 * A simple class that provides the basic implementation needed to make any element draggable.
19994 * @param {String/HTMLElement/Element} el The container element
19995 * @param {Object} config
19997 Roo.dd.DragSource = function(el, config){
19998 this.el = Roo.get(el);
19999 this.dragData = {};
20001 Roo.apply(this, config);
20004 this.proxy = new Roo.dd.StatusProxy();
20007 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
20008 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
20010 this.dragging = false;
20013 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
20015 * @cfg {String} dropAllowed
20016 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20018 dropAllowed : "x-dd-drop-ok",
20020 * @cfg {String} dropNotAllowed
20021 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20023 dropNotAllowed : "x-dd-drop-nodrop",
20026 * Returns the data object associated with this drag source
20027 * @return {Object} data An object containing arbitrary data
20029 getDragData : function(e){
20030 return this.dragData;
20034 onDragEnter : function(e, id){
20035 var target = Roo.dd.DragDropMgr.getDDById(id);
20036 this.cachedTarget = target;
20037 if(this.beforeDragEnter(target, e, id) !== false){
20038 if(target.isNotifyTarget){
20039 var status = target.notifyEnter(this, e, this.dragData);
20040 this.proxy.setStatus(status);
20042 this.proxy.setStatus(this.dropAllowed);
20045 if(this.afterDragEnter){
20047 * An empty function by default, but provided so that you can perform a custom action
20048 * when the dragged item enters the drop target by providing an implementation.
20049 * @param {Roo.dd.DragDrop} target The drop target
20050 * @param {Event} e The event object
20051 * @param {String} id The id of the dragged element
20052 * @method afterDragEnter
20054 this.afterDragEnter(target, e, id);
20060 * An empty function by default, but provided so that you can perform a custom action
20061 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
20062 * @param {Roo.dd.DragDrop} target The drop target
20063 * @param {Event} e The event object
20064 * @param {String} id The id of the dragged element
20065 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20067 beforeDragEnter : function(target, e, id){
20072 alignElWithMouse: function() {
20073 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
20078 onDragOver : function(e, id){
20079 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20080 if(this.beforeDragOver(target, e, id) !== false){
20081 if(target.isNotifyTarget){
20082 var status = target.notifyOver(this, e, this.dragData);
20083 this.proxy.setStatus(status);
20086 if(this.afterDragOver){
20088 * An empty function by default, but provided so that you can perform a custom action
20089 * while the dragged item is over the drop target by providing an implementation.
20090 * @param {Roo.dd.DragDrop} target The drop target
20091 * @param {Event} e The event object
20092 * @param {String} id The id of the dragged element
20093 * @method afterDragOver
20095 this.afterDragOver(target, e, id);
20101 * An empty function by default, but provided so that you can perform a custom action
20102 * while the dragged item is over the drop target and optionally cancel the onDragOver.
20103 * @param {Roo.dd.DragDrop} target The drop target
20104 * @param {Event} e The event object
20105 * @param {String} id The id of the dragged element
20106 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20108 beforeDragOver : function(target, e, id){
20113 onDragOut : function(e, id){
20114 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20115 if(this.beforeDragOut(target, e, id) !== false){
20116 if(target.isNotifyTarget){
20117 target.notifyOut(this, e, this.dragData);
20119 this.proxy.reset();
20120 if(this.afterDragOut){
20122 * An empty function by default, but provided so that you can perform a custom action
20123 * after the dragged item is dragged out of the target without dropping.
20124 * @param {Roo.dd.DragDrop} target The drop target
20125 * @param {Event} e The event object
20126 * @param {String} id The id of the dragged element
20127 * @method afterDragOut
20129 this.afterDragOut(target, e, id);
20132 this.cachedTarget = null;
20136 * An empty function by default, but provided so that you can perform a custom action before the dragged
20137 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
20138 * @param {Roo.dd.DragDrop} target The drop target
20139 * @param {Event} e The event object
20140 * @param {String} id The id of the dragged element
20141 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20143 beforeDragOut : function(target, e, id){
20148 onDragDrop : function(e, id){
20149 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
20150 if(this.beforeDragDrop(target, e, id) !== false){
20151 if(target.isNotifyTarget){
20152 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
20153 this.onValidDrop(target, e, id);
20155 this.onInvalidDrop(target, e, id);
20158 this.onValidDrop(target, e, id);
20161 if(this.afterDragDrop){
20163 * An empty function by default, but provided so that you can perform a custom action
20164 * after a valid drag drop has occurred by providing an implementation.
20165 * @param {Roo.dd.DragDrop} target The drop target
20166 * @param {Event} e The event object
20167 * @param {String} id The id of the dropped element
20168 * @method afterDragDrop
20170 this.afterDragDrop(target, e, id);
20173 delete this.cachedTarget;
20177 * An empty function by default, but provided so that you can perform a custom action before the dragged
20178 * item is dropped onto the target and optionally cancel the onDragDrop.
20179 * @param {Roo.dd.DragDrop} target The drop target
20180 * @param {Event} e The event object
20181 * @param {String} id The id of the dragged element
20182 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
20184 beforeDragDrop : function(target, e, id){
20189 onValidDrop : function(target, e, id){
20191 if(this.afterValidDrop){
20193 * An empty function by default, but provided so that you can perform a custom action
20194 * after a valid drop has occurred by providing an implementation.
20195 * @param {Object} target The target DD
20196 * @param {Event} e The event object
20197 * @param {String} id The id of the dropped element
20198 * @method afterInvalidDrop
20200 this.afterValidDrop(target, e, id);
20205 getRepairXY : function(e, data){
20206 return this.el.getXY();
20210 onInvalidDrop : function(target, e, id){
20211 this.beforeInvalidDrop(target, e, id);
20212 if(this.cachedTarget){
20213 if(this.cachedTarget.isNotifyTarget){
20214 this.cachedTarget.notifyOut(this, e, this.dragData);
20216 this.cacheTarget = null;
20218 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
20220 if(this.afterInvalidDrop){
20222 * An empty function by default, but provided so that you can perform a custom action
20223 * after an invalid drop has occurred by providing an implementation.
20224 * @param {Event} e The event object
20225 * @param {String} id The id of the dropped element
20226 * @method afterInvalidDrop
20228 this.afterInvalidDrop(e, id);
20233 afterRepair : function(){
20235 this.el.highlight(this.hlColor || "c3daf9");
20237 this.dragging = false;
20241 * An empty function by default, but provided so that you can perform a custom action after an invalid
20242 * drop has occurred.
20243 * @param {Roo.dd.DragDrop} target The drop target
20244 * @param {Event} e The event object
20245 * @param {String} id The id of the dragged element
20246 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
20248 beforeInvalidDrop : function(target, e, id){
20253 handleMouseDown : function(e){
20254 if(this.dragging) {
20257 var data = this.getDragData(e);
20258 if(data && this.onBeforeDrag(data, e) !== false){
20259 this.dragData = data;
20261 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
20266 * An empty function by default, but provided so that you can perform a custom action before the initial
20267 * drag event begins and optionally cancel it.
20268 * @param {Object} data An object containing arbitrary data to be shared with drop targets
20269 * @param {Event} e The event object
20270 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
20272 onBeforeDrag : function(data, e){
20277 * An empty function by default, but provided so that you can perform a custom action once the initial
20278 * drag event has begun. The drag cannot be canceled from this function.
20279 * @param {Number} x The x position of the click on the dragged object
20280 * @param {Number} y The y position of the click on the dragged object
20282 onStartDrag : Roo.emptyFn,
20284 // private - YUI override
20285 startDrag : function(x, y){
20286 this.proxy.reset();
20287 this.dragging = true;
20288 this.proxy.update("");
20289 this.onInitDrag(x, y);
20294 onInitDrag : function(x, y){
20295 var clone = this.el.dom.cloneNode(true);
20296 clone.id = Roo.id(); // prevent duplicate ids
20297 this.proxy.update(clone);
20298 this.onStartDrag(x, y);
20303 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
20304 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
20306 getProxy : function(){
20311 * Hides the drag source's {@link Roo.dd.StatusProxy}
20313 hideProxy : function(){
20315 this.proxy.reset(true);
20316 this.dragging = false;
20320 triggerCacheRefresh : function(){
20321 Roo.dd.DDM.refreshCache(this.groups);
20324 // private - override to prevent hiding
20325 b4EndDrag: function(e) {
20328 // private - override to prevent moving
20329 endDrag : function(e){
20330 this.onEndDrag(this.dragData, e);
20334 onEndDrag : function(data, e){
20337 // private - pin to cursor
20338 autoOffset : function(x, y) {
20339 this.setDelta(-12, -20);
20343 * Ext JS Library 1.1.1
20344 * Copyright(c) 2006-2007, Ext JS, LLC.
20346 * Originally Released Under LGPL - original licence link has changed is not relivant.
20349 * <script type="text/javascript">
20354 * @class Roo.dd.DropTarget
20355 * @extends Roo.dd.DDTarget
20356 * A simple class that provides the basic implementation needed to make any element a drop target that can have
20357 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
20359 * @param {String/HTMLElement/Element} el The container element
20360 * @param {Object} config
20362 Roo.dd.DropTarget = function(el, config){
20363 this.el = Roo.get(el);
20365 var listeners = false; ;
20366 if (config && config.listeners) {
20367 listeners= config.listeners;
20368 delete config.listeners;
20370 Roo.apply(this, config);
20372 if(this.containerScroll){
20373 Roo.dd.ScrollManager.register(this.el);
20377 * @scope Roo.dd.DropTarget
20382 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
20383 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
20384 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
20386 * IMPORTANT : it should set this.overClass and this.dropAllowed
20388 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20389 * @param {Event} e The event
20390 * @param {Object} data An object containing arbitrary data supplied by the drag source
20396 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
20397 * This method will be called on every mouse movement while the drag source is over the drop target.
20398 * This default implementation simply returns the dropAllowed config value.
20400 * IMPORTANT : it should set this.dropAllowed
20402 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20403 * @param {Event} e The event
20404 * @param {Object} data An object containing arbitrary data supplied by the drag source
20410 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
20411 * out of the target without dropping. This default implementation simply removes the CSS class specified by
20412 * overClass (if any) from the drop element.
20414 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20415 * @param {Event} e The event
20416 * @param {Object} data An object containing arbitrary data supplied by the drag source
20422 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
20423 * been dropped on it. This method has no default implementation and returns false, so you must provide an
20424 * implementation that does something to process the drop event and returns true so that the drag source's
20425 * repair action does not run.
20427 * IMPORTANT : it should set this.success
20429 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20430 * @param {Event} e The event
20431 * @param {Object} data An object containing arbitrary data supplied by the drag source
20437 Roo.dd.DropTarget.superclass.constructor.call( this,
20439 this.ddGroup || this.group,
20442 listeners : listeners || {}
20450 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
20452 * @cfg {String} overClass
20453 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
20456 * @cfg {String} ddGroup
20457 * The drag drop group to handle drop events for
20461 * @cfg {String} dropAllowed
20462 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
20464 dropAllowed : "x-dd-drop-ok",
20466 * @cfg {String} dropNotAllowed
20467 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
20469 dropNotAllowed : "x-dd-drop-nodrop",
20471 * @cfg {boolean} success
20472 * set this after drop listener..
20476 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
20477 * if the drop point is valid for over/enter..
20484 isNotifyTarget : true,
20489 notifyEnter : function(dd, e, data)
20492 this.fireEvent('enter', dd, e, data);
20493 if(this.overClass){
20494 this.el.addClass(this.overClass);
20496 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20497 this.valid ? this.dropAllowed : this.dropNotAllowed
20504 notifyOver : function(dd, e, data)
20507 this.fireEvent('over', dd, e, data);
20508 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
20509 this.valid ? this.dropAllowed : this.dropNotAllowed
20516 notifyOut : function(dd, e, data)
20518 this.fireEvent('out', dd, e, data);
20519 if(this.overClass){
20520 this.el.removeClass(this.overClass);
20527 notifyDrop : function(dd, e, data)
20529 this.success = false;
20530 this.fireEvent('drop', dd, e, data);
20531 return this.success;
20535 * Ext JS Library 1.1.1
20536 * Copyright(c) 2006-2007, Ext JS, LLC.
20538 * Originally Released Under LGPL - original licence link has changed is not relivant.
20541 * <script type="text/javascript">
20546 * @class Roo.dd.DragZone
20547 * @extends Roo.dd.DragSource
20548 * This class provides a container DD instance that proxies for multiple child node sources.<br />
20549 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
20551 * @param {String/HTMLElement/Element} el The container element
20552 * @param {Object} config
20554 Roo.dd.DragZone = function(el, config){
20555 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
20556 if(this.containerScroll){
20557 Roo.dd.ScrollManager.register(this.el);
20561 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
20563 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
20564 * for auto scrolling during drag operations.
20567 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
20568 * method after a failed drop (defaults to "c3daf9" - light blue)
20572 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
20573 * for a valid target to drag based on the mouse down. Override this method
20574 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
20575 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
20576 * @param {EventObject} e The mouse down event
20577 * @return {Object} The dragData
20579 getDragData : function(e){
20580 return Roo.dd.Registry.getHandleFromEvent(e);
20584 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
20585 * this.dragData.ddel
20586 * @param {Number} x The x position of the click on the dragged object
20587 * @param {Number} y The y position of the click on the dragged object
20588 * @return {Boolean} true to continue the drag, false to cancel
20590 onInitDrag : function(x, y){
20591 this.proxy.update(this.dragData.ddel.cloneNode(true));
20592 this.onStartDrag(x, y);
20597 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
20599 afterRepair : function(){
20601 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
20603 this.dragging = false;
20607 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
20608 * the XY of this.dragData.ddel
20609 * @param {EventObject} e The mouse up event
20610 * @return {Array} The xy location (e.g. [100, 200])
20612 getRepairXY : function(e){
20613 return Roo.Element.fly(this.dragData.ddel).getXY();
20617 * Ext JS Library 1.1.1
20618 * Copyright(c) 2006-2007, Ext JS, LLC.
20620 * Originally Released Under LGPL - original licence link has changed is not relivant.
20623 * <script type="text/javascript">
20626 * @class Roo.dd.DropZone
20627 * @extends Roo.dd.DropTarget
20628 * This class provides a container DD instance that proxies for multiple child node targets.<br />
20629 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
20631 * @param {String/HTMLElement/Element} el The container element
20632 * @param {Object} config
20634 Roo.dd.DropZone = function(el, config){
20635 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
20638 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
20640 * Returns a custom data object associated with the DOM node that is the target of the event. By default
20641 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
20642 * provide your own custom lookup.
20643 * @param {Event} e The event
20644 * @return {Object} data The custom data
20646 getTargetFromEvent : function(e){
20647 return Roo.dd.Registry.getTargetFromEvent(e);
20651 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
20652 * that it has registered. This method has no default implementation and should be overridden to provide
20653 * node-specific processing if necessary.
20654 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20655 * {@link #getTargetFromEvent} for this node)
20656 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20657 * @param {Event} e The event
20658 * @param {Object} data An object containing arbitrary data supplied by the drag source
20660 onNodeEnter : function(n, dd, e, data){
20665 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
20666 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
20667 * overridden to provide the proper feedback.
20668 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20669 * {@link #getTargetFromEvent} for this node)
20670 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20671 * @param {Event} e The event
20672 * @param {Object} data An object containing arbitrary data supplied by the drag source
20673 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20674 * underlying {@link Roo.dd.StatusProxy} can be updated
20676 onNodeOver : function(n, dd, e, data){
20677 return this.dropAllowed;
20681 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
20682 * the drop node without dropping. This method has no default implementation and should be overridden to provide
20683 * node-specific processing if necessary.
20684 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20685 * {@link #getTargetFromEvent} for this node)
20686 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20687 * @param {Event} e The event
20688 * @param {Object} data An object containing arbitrary data supplied by the drag source
20690 onNodeOut : function(n, dd, e, data){
20695 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
20696 * the drop node. The default implementation returns false, so it should be overridden to provide the
20697 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
20698 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
20699 * {@link #getTargetFromEvent} for this node)
20700 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20701 * @param {Event} e The event
20702 * @param {Object} data An object containing arbitrary data supplied by the drag source
20703 * @return {Boolean} True if the drop was valid, else false
20705 onNodeDrop : function(n, dd, e, data){
20710 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
20711 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
20712 * it should be overridden to provide the proper feedback if necessary.
20713 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20714 * @param {Event} e The event
20715 * @param {Object} data An object containing arbitrary data supplied by the drag source
20716 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20717 * underlying {@link Roo.dd.StatusProxy} can be updated
20719 onContainerOver : function(dd, e, data){
20720 return this.dropNotAllowed;
20724 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
20725 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
20726 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
20727 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
20728 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20729 * @param {Event} e The event
20730 * @param {Object} data An object containing arbitrary data supplied by the drag source
20731 * @return {Boolean} True if the drop was valid, else false
20733 onContainerDrop : function(dd, e, data){
20738 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
20739 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
20740 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
20741 * you should override this method and provide a custom implementation.
20742 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20743 * @param {Event} e The event
20744 * @param {Object} data An object containing arbitrary data supplied by the drag source
20745 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20746 * underlying {@link Roo.dd.StatusProxy} can be updated
20748 notifyEnter : function(dd, e, data){
20749 return this.dropNotAllowed;
20753 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
20754 * This method will be called on every mouse movement while the drag source is over the drop zone.
20755 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
20756 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
20757 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
20758 * registered node, it will call {@link #onContainerOver}.
20759 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20760 * @param {Event} e The event
20761 * @param {Object} data An object containing arbitrary data supplied by the drag source
20762 * @return {String} status The CSS class that communicates the drop status back to the source so that the
20763 * underlying {@link Roo.dd.StatusProxy} can be updated
20765 notifyOver : function(dd, e, data){
20766 var n = this.getTargetFromEvent(e);
20767 if(!n){ // not over valid drop target
20768 if(this.lastOverNode){
20769 this.onNodeOut(this.lastOverNode, dd, e, data);
20770 this.lastOverNode = null;
20772 return this.onContainerOver(dd, e, data);
20774 if(this.lastOverNode != n){
20775 if(this.lastOverNode){
20776 this.onNodeOut(this.lastOverNode, dd, e, data);
20778 this.onNodeEnter(n, dd, e, data);
20779 this.lastOverNode = n;
20781 return this.onNodeOver(n, dd, e, data);
20785 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
20786 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
20787 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
20788 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
20789 * @param {Event} e The event
20790 * @param {Object} data An object containing arbitrary data supplied by the drag zone
20792 notifyOut : function(dd, e, data){
20793 if(this.lastOverNode){
20794 this.onNodeOut(this.lastOverNode, dd, e, data);
20795 this.lastOverNode = null;
20800 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
20801 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
20802 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
20803 * otherwise it will call {@link #onContainerDrop}.
20804 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
20805 * @param {Event} e The event
20806 * @param {Object} data An object containing arbitrary data supplied by the drag source
20807 * @return {Boolean} True if the drop was valid, else false
20809 notifyDrop : function(dd, e, data){
20810 if(this.lastOverNode){
20811 this.onNodeOut(this.lastOverNode, dd, e, data);
20812 this.lastOverNode = null;
20814 var n = this.getTargetFromEvent(e);
20816 this.onNodeDrop(n, dd, e, data) :
20817 this.onContainerDrop(dd, e, data);
20821 triggerCacheRefresh : function(){
20822 Roo.dd.DDM.refreshCache(this.groups);
20826 * Ext JS Library 1.1.1
20827 * Copyright(c) 2006-2007, Ext JS, LLC.
20829 * Originally Released Under LGPL - original licence link has changed is not relivant.
20832 * <script type="text/javascript">
20837 * @class Roo.data.SortTypes
20839 * Defines the default sorting (casting?) comparison functions used when sorting data.
20841 Roo.data.SortTypes = {
20843 * Default sort that does nothing
20844 * @param {Mixed} s The value being converted
20845 * @return {Mixed} The comparison value
20847 none : function(s){
20852 * The regular expression used to strip tags
20856 stripTagsRE : /<\/?[^>]+>/gi,
20859 * Strips all HTML tags to sort on text only
20860 * @param {Mixed} s The value being converted
20861 * @return {String} The comparison value
20863 asText : function(s){
20864 return String(s).replace(this.stripTagsRE, "");
20868 * Strips all HTML tags to sort on text only - Case insensitive
20869 * @param {Mixed} s The value being converted
20870 * @return {String} The comparison value
20872 asUCText : function(s){
20873 return String(s).toUpperCase().replace(this.stripTagsRE, "");
20877 * Case insensitive string
20878 * @param {Mixed} s The value being converted
20879 * @return {String} The comparison value
20881 asUCString : function(s) {
20882 return String(s).toUpperCase();
20887 * @param {Mixed} s The value being converted
20888 * @return {Number} The comparison value
20890 asDate : function(s) {
20894 if(s instanceof Date){
20895 return s.getTime();
20897 return Date.parse(String(s));
20902 * @param {Mixed} s The value being converted
20903 * @return {Float} The comparison value
20905 asFloat : function(s) {
20906 var val = parseFloat(String(s).replace(/,/g, ""));
20907 if(isNaN(val)) val = 0;
20913 * @param {Mixed} s The value being converted
20914 * @return {Number} The comparison value
20916 asInt : function(s) {
20917 var val = parseInt(String(s).replace(/,/g, ""));
20918 if(isNaN(val)) val = 0;
20923 * Ext JS Library 1.1.1
20924 * Copyright(c) 2006-2007, Ext JS, LLC.
20926 * Originally Released Under LGPL - original licence link has changed is not relivant.
20929 * <script type="text/javascript">
20933 * @class Roo.data.Record
20934 * Instances of this class encapsulate both record <em>definition</em> information, and record
20935 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
20936 * to access Records cached in an {@link Roo.data.Store} object.<br>
20938 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
20939 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
20942 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
20944 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
20945 * {@link #create}. The parameters are the same.
20946 * @param {Array} data An associative Array of data values keyed by the field name.
20947 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
20948 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
20949 * not specified an integer id is generated.
20951 Roo.data.Record = function(data, id){
20952 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
20957 * Generate a constructor for a specific record layout.
20958 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
20959 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
20960 * Each field definition object may contain the following properties: <ul>
20961 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
20962 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
20963 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
20964 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
20965 * is being used, then this is a string containing the javascript expression to reference the data relative to
20966 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
20967 * to the data item relative to the record element. If the mapping expression is the same as the field name,
20968 * this may be omitted.</p></li>
20969 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
20970 * <ul><li>auto (Default, implies no conversion)</li>
20975 * <li>date</li></ul></p></li>
20976 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
20977 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
20978 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
20979 * by the Reader into an object that will be stored in the Record. It is passed the
20980 * following parameters:<ul>
20981 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
20983 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
20985 * <br>usage:<br><pre><code>
20986 var TopicRecord = Roo.data.Record.create(
20987 {name: 'title', mapping: 'topic_title'},
20988 {name: 'author', mapping: 'username'},
20989 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
20990 {name: 'lastPost', mapping: 'post_time', type: 'date'},
20991 {name: 'lastPoster', mapping: 'user2'},
20992 {name: 'excerpt', mapping: 'post_text'}
20995 var myNewRecord = new TopicRecord({
20996 title: 'Do my job please',
20999 lastPost: new Date(),
21000 lastPoster: 'Animal',
21001 excerpt: 'No way dude!'
21003 myStore.add(myNewRecord);
21008 Roo.data.Record.create = function(o){
21009 var f = function(){
21010 f.superclass.constructor.apply(this, arguments);
21012 Roo.extend(f, Roo.data.Record);
21013 var p = f.prototype;
21014 p.fields = new Roo.util.MixedCollection(false, function(field){
21017 for(var i = 0, len = o.length; i < len; i++){
21018 p.fields.add(new Roo.data.Field(o[i]));
21020 f.getField = function(name){
21021 return p.fields.get(name);
21026 Roo.data.Record.AUTO_ID = 1000;
21027 Roo.data.Record.EDIT = 'edit';
21028 Roo.data.Record.REJECT = 'reject';
21029 Roo.data.Record.COMMIT = 'commit';
21031 Roo.data.Record.prototype = {
21033 * Readonly flag - true if this record has been modified.
21042 join : function(store){
21043 this.store = store;
21047 * Set the named field to the specified value.
21048 * @param {String} name The name of the field to set.
21049 * @param {Object} value The value to set the field to.
21051 set : function(name, value){
21052 if(this.data[name] == value){
21056 if(!this.modified){
21057 this.modified = {};
21059 if(typeof this.modified[name] == 'undefined'){
21060 this.modified[name] = this.data[name];
21062 this.data[name] = value;
21063 if(!this.editing && this.store){
21064 this.store.afterEdit(this);
21069 * Get the value of the named field.
21070 * @param {String} name The name of the field to get the value of.
21071 * @return {Object} The value of the field.
21073 get : function(name){
21074 return this.data[name];
21078 beginEdit : function(){
21079 this.editing = true;
21080 this.modified = {};
21084 cancelEdit : function(){
21085 this.editing = false;
21086 delete this.modified;
21090 endEdit : function(){
21091 this.editing = false;
21092 if(this.dirty && this.store){
21093 this.store.afterEdit(this);
21098 * Usually called by the {@link Roo.data.Store} which owns the Record.
21099 * Rejects all changes made to the Record since either creation, or the last commit operation.
21100 * Modified fields are reverted to their original values.
21102 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21103 * of reject operations.
21105 reject : function(){
21106 var m = this.modified;
21108 if(typeof m[n] != "function"){
21109 this.data[n] = m[n];
21112 this.dirty = false;
21113 delete this.modified;
21114 this.editing = false;
21116 this.store.afterReject(this);
21121 * Usually called by the {@link Roo.data.Store} which owns the Record.
21122 * Commits all changes made to the Record since either creation, or the last commit operation.
21124 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
21125 * of commit operations.
21127 commit : function(){
21128 this.dirty = false;
21129 delete this.modified;
21130 this.editing = false;
21132 this.store.afterCommit(this);
21137 hasError : function(){
21138 return this.error != null;
21142 clearError : function(){
21147 * Creates a copy of this record.
21148 * @param {String} id (optional) A new record id if you don't want to use this record's id
21151 copy : function(newId) {
21152 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
21156 * Ext JS Library 1.1.1
21157 * Copyright(c) 2006-2007, Ext JS, LLC.
21159 * Originally Released Under LGPL - original licence link has changed is not relivant.
21162 * <script type="text/javascript">
21168 * @class Roo.data.Store
21169 * @extends Roo.util.Observable
21170 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
21171 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
21173 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
21174 * has no knowledge of the format of the data returned by the Proxy.<br>
21176 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
21177 * instances from the data object. These records are cached and made available through accessor functions.
21179 * Creates a new Store.
21180 * @param {Object} config A config object containing the objects needed for the Store to access data,
21181 * and read the data into Records.
21183 Roo.data.Store = function(config){
21184 this.data = new Roo.util.MixedCollection(false);
21185 this.data.getKey = function(o){
21188 this.baseParams = {};
21190 this.paramNames = {
21195 "multisort" : "_multisort"
21198 if(config && config.data){
21199 this.inlineData = config.data;
21200 delete config.data;
21203 Roo.apply(this, config);
21205 if(this.reader){ // reader passed
21206 this.reader = Roo.factory(this.reader, Roo.data);
21207 this.reader.xmodule = this.xmodule || false;
21208 if(!this.recordType){
21209 this.recordType = this.reader.recordType;
21211 if(this.reader.onMetaChange){
21212 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
21216 if(this.recordType){
21217 this.fields = this.recordType.prototype.fields;
21219 this.modified = [];
21223 * @event datachanged
21224 * Fires when the data cache has changed, and a widget which is using this Store
21225 * as a Record cache should refresh its view.
21226 * @param {Store} this
21228 datachanged : true,
21230 * @event metachange
21231 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
21232 * @param {Store} this
21233 * @param {Object} meta The JSON metadata
21238 * Fires when Records have been added to the Store
21239 * @param {Store} this
21240 * @param {Roo.data.Record[]} records The array of Records added
21241 * @param {Number} index The index at which the record(s) were added
21246 * Fires when a Record has been removed from the Store
21247 * @param {Store} this
21248 * @param {Roo.data.Record} record The Record that was removed
21249 * @param {Number} index The index at which the record was removed
21254 * Fires when a Record has been updated
21255 * @param {Store} this
21256 * @param {Roo.data.Record} record The Record that was updated
21257 * @param {String} operation The update operation being performed. Value may be one of:
21259 Roo.data.Record.EDIT
21260 Roo.data.Record.REJECT
21261 Roo.data.Record.COMMIT
21267 * Fires when the data cache has been cleared.
21268 * @param {Store} this
21272 * @event beforeload
21273 * Fires before a request is made for a new data object. If the beforeload handler returns false
21274 * the load action will be canceled.
21275 * @param {Store} this
21276 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21280 * @event beforeloadadd
21281 * Fires after a new set of Records has been loaded.
21282 * @param {Store} this
21283 * @param {Roo.data.Record[]} records The Records that were loaded
21284 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21286 beforeloadadd : true,
21289 * Fires after a new set of Records has been loaded, before they are added to the store.
21290 * @param {Store} this
21291 * @param {Roo.data.Record[]} records The Records that were loaded
21292 * @param {Object} options The loading options that were specified (see {@link #load} for details)
21293 * @params {Object} return from reader
21297 * @event loadexception
21298 * Fires if an exception occurs in the Proxy during loading.
21299 * Called with the signature of the Proxy's "loadexception" event.
21300 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
21303 * @param {Object} return from JsonData.reader() - success, totalRecords, records
21304 * @param {Object} load options
21305 * @param {Object} jsonData from your request (normally this contains the Exception)
21307 loadexception : true
21311 this.proxy = Roo.factory(this.proxy, Roo.data);
21312 this.proxy.xmodule = this.xmodule || false;
21313 this.relayEvents(this.proxy, ["loadexception"]);
21315 this.sortToggle = {};
21316 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
21318 Roo.data.Store.superclass.constructor.call(this);
21320 if(this.inlineData){
21321 this.loadData(this.inlineData);
21322 delete this.inlineData;
21326 Roo.extend(Roo.data.Store, Roo.util.Observable, {
21328 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
21329 * without a remote query - used by combo/forms at present.
21333 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
21336 * @cfg {Array} data Inline data to be loaded when the store is initialized.
21339 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
21340 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
21343 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
21344 * on any HTTP request
21347 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
21350 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
21354 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
21355 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
21357 remoteSort : false,
21360 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
21361 * loaded or when a record is removed. (defaults to false).
21363 pruneModifiedRecords : false,
21366 lastOptions : null,
21369 * Add Records to the Store and fires the add event.
21370 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21372 add : function(records){
21373 records = [].concat(records);
21374 for(var i = 0, len = records.length; i < len; i++){
21375 records[i].join(this);
21377 var index = this.data.length;
21378 this.data.addAll(records);
21379 this.fireEvent("add", this, records, index);
21383 * Remove a Record from the Store and fires the remove event.
21384 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
21386 remove : function(record){
21387 var index = this.data.indexOf(record);
21388 this.data.removeAt(index);
21389 if(this.pruneModifiedRecords){
21390 this.modified.remove(record);
21392 this.fireEvent("remove", this, record, index);
21396 * Remove all Records from the Store and fires the clear event.
21398 removeAll : function(){
21400 if(this.pruneModifiedRecords){
21401 this.modified = [];
21403 this.fireEvent("clear", this);
21407 * Inserts Records to the Store at the given index and fires the add event.
21408 * @param {Number} index The start index at which to insert the passed Records.
21409 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
21411 insert : function(index, records){
21412 records = [].concat(records);
21413 for(var i = 0, len = records.length; i < len; i++){
21414 this.data.insert(index, records[i]);
21415 records[i].join(this);
21417 this.fireEvent("add", this, records, index);
21421 * Get the index within the cache of the passed Record.
21422 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
21423 * @return {Number} The index of the passed Record. Returns -1 if not found.
21425 indexOf : function(record){
21426 return this.data.indexOf(record);
21430 * Get the index within the cache of the Record with the passed id.
21431 * @param {String} id The id of the Record to find.
21432 * @return {Number} The index of the Record. Returns -1 if not found.
21434 indexOfId : function(id){
21435 return this.data.indexOfKey(id);
21439 * Get the Record with the specified id.
21440 * @param {String} id The id of the Record to find.
21441 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
21443 getById : function(id){
21444 return this.data.key(id);
21448 * Get the Record at the specified index.
21449 * @param {Number} index The index of the Record to find.
21450 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
21452 getAt : function(index){
21453 return this.data.itemAt(index);
21457 * Returns a range of Records between specified indices.
21458 * @param {Number} startIndex (optional) The starting index (defaults to 0)
21459 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
21460 * @return {Roo.data.Record[]} An array of Records
21462 getRange : function(start, end){
21463 return this.data.getRange(start, end);
21467 storeOptions : function(o){
21468 o = Roo.apply({}, o);
21471 this.lastOptions = o;
21475 * Loads the Record cache from the configured Proxy using the configured Reader.
21477 * If using remote paging, then the first load call must specify the <em>start</em>
21478 * and <em>limit</em> properties in the options.params property to establish the initial
21479 * position within the dataset, and the number of Records to cache on each read from the Proxy.
21481 * <strong>It is important to note that for remote data sources, loading is asynchronous,
21482 * and this call will return before the new data has been loaded. Perform any post-processing
21483 * in a callback function, or in a "load" event handler.</strong>
21485 * @param {Object} options An object containing properties which control loading options:<ul>
21486 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
21487 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
21488 * passed the following arguments:<ul>
21489 * <li>r : Roo.data.Record[]</li>
21490 * <li>options: Options object from the load call</li>
21491 * <li>success: Boolean success indicator</li></ul></li>
21492 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
21493 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
21496 load : function(options){
21497 options = options || {};
21498 if(this.fireEvent("beforeload", this, options) !== false){
21499 this.storeOptions(options);
21500 var p = Roo.apply(options.params || {}, this.baseParams);
21501 // if meta was not loaded from remote source.. try requesting it.
21502 if (!this.reader.metaFromRemote) {
21503 p._requestMeta = 1;
21505 if(this.sortInfo && this.remoteSort){
21506 var pn = this.paramNames;
21507 p[pn["sort"]] = this.sortInfo.field;
21508 p[pn["dir"]] = this.sortInfo.direction;
21510 if (this.multiSort) {
21511 var pn = this.paramNames;
21512 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
21515 this.proxy.load(p, this.reader, this.loadRecords, this, options);
21520 * Reloads the Record cache from the configured Proxy using the configured Reader and
21521 * the options from the last load operation performed.
21522 * @param {Object} options (optional) An object containing properties which may override the options
21523 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
21524 * the most recently used options are reused).
21526 reload : function(options){
21527 this.load(Roo.applyIf(options||{}, this.lastOptions));
21531 // Called as a callback by the Reader during a load operation.
21532 loadRecords : function(o, options, success){
21533 if(!o || success === false){
21534 if(success !== false){
21535 this.fireEvent("load", this, [], options, o);
21537 if(options.callback){
21538 options.callback.call(options.scope || this, [], options, false);
21542 // if data returned failure - throw an exception.
21543 if (o.success === false) {
21544 // show a message if no listener is registered.
21545 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
21546 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
21548 // loadmask wil be hooked into this..
21549 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
21552 var r = o.records, t = o.totalRecords || r.length;
21554 this.fireEvent("beforeloadadd", this, r, options, o);
21556 if(!options || options.add !== true){
21557 if(this.pruneModifiedRecords){
21558 this.modified = [];
21560 for(var i = 0, len = r.length; i < len; i++){
21564 this.data = this.snapshot;
21565 delete this.snapshot;
21568 this.data.addAll(r);
21569 this.totalLength = t;
21571 this.fireEvent("datachanged", this);
21573 this.totalLength = Math.max(t, this.data.length+r.length);
21576 this.fireEvent("load", this, r, options, o);
21577 if(options.callback){
21578 options.callback.call(options.scope || this, r, options, true);
21584 * Loads data from a passed data block. A Reader which understands the format of the data
21585 * must have been configured in the constructor.
21586 * @param {Object} data The data block from which to read the Records. The format of the data expected
21587 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
21588 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
21590 loadData : function(o, append){
21591 var r = this.reader.readRecords(o);
21592 this.loadRecords(r, {add: append}, true);
21596 * Gets the number of cached records.
21598 * <em>If using paging, this may not be the total size of the dataset. If the data object
21599 * used by the Reader contains the dataset size, then the getTotalCount() function returns
21600 * the data set size</em>
21602 getCount : function(){
21603 return this.data.length || 0;
21607 * Gets the total number of records in the dataset as returned by the server.
21609 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
21610 * the dataset size</em>
21612 getTotalCount : function(){
21613 return this.totalLength || 0;
21617 * Returns the sort state of the Store as an object with two properties:
21619 field {String} The name of the field by which the Records are sorted
21620 direction {String} The sort order, "ASC" or "DESC"
21623 getSortState : function(){
21624 return this.sortInfo;
21628 applySort : function(){
21629 if(this.sortInfo && !this.remoteSort){
21630 var s = this.sortInfo, f = s.field;
21631 var st = this.fields.get(f).sortType;
21632 var fn = function(r1, r2){
21633 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
21634 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
21636 this.data.sort(s.direction, fn);
21637 if(this.snapshot && this.snapshot != this.data){
21638 this.snapshot.sort(s.direction, fn);
21644 * Sets the default sort column and order to be used by the next load operation.
21645 * @param {String} fieldName The name of the field to sort by.
21646 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21648 setDefaultSort : function(field, dir){
21649 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
21653 * Sort the Records.
21654 * If remote sorting is used, the sort is performed on the server, and the cache is
21655 * reloaded. If local sorting is used, the cache is sorted internally.
21656 * @param {String} fieldName The name of the field to sort by.
21657 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
21659 sort : function(fieldName, dir){
21660 var f = this.fields.get(fieldName);
21662 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
21664 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
21665 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
21670 this.sortToggle[f.name] = dir;
21671 this.sortInfo = {field: f.name, direction: dir};
21672 if(!this.remoteSort){
21674 this.fireEvent("datachanged", this);
21676 this.load(this.lastOptions);
21681 * Calls the specified function for each of the Records in the cache.
21682 * @param {Function} fn The function to call. The Record is passed as the first parameter.
21683 * Returning <em>false</em> aborts and exits the iteration.
21684 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
21686 each : function(fn, scope){
21687 this.data.each(fn, scope);
21691 * Gets all records modified since the last commit. Modified records are persisted across load operations
21692 * (e.g., during paging).
21693 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
21695 getModifiedRecords : function(){
21696 return this.modified;
21700 createFilterFn : function(property, value, anyMatch){
21701 if(!value.exec){ // not a regex
21702 value = String(value);
21703 if(value.length == 0){
21706 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
21708 return function(r){
21709 return value.test(r.data[property]);
21714 * Sums the value of <i>property</i> for each record between start and end and returns the result.
21715 * @param {String} property A field on your records
21716 * @param {Number} start The record index to start at (defaults to 0)
21717 * @param {Number} end The last record index to include (defaults to length - 1)
21718 * @return {Number} The sum
21720 sum : function(property, start, end){
21721 var rs = this.data.items, v = 0;
21722 start = start || 0;
21723 end = (end || end === 0) ? end : rs.length-1;
21725 for(var i = start; i <= end; i++){
21726 v += (rs[i].data[property] || 0);
21732 * Filter the records by a specified property.
21733 * @param {String} field A field on your records
21734 * @param {String/RegExp} value Either a string that the field
21735 * should start with or a RegExp to test against the field
21736 * @param {Boolean} anyMatch True to match any part not just the beginning
21738 filter : function(property, value, anyMatch){
21739 var fn = this.createFilterFn(property, value, anyMatch);
21740 return fn ? this.filterBy(fn) : this.clearFilter();
21744 * Filter by a function. The specified function will be called with each
21745 * record in this data source. If the function returns true the record is included,
21746 * otherwise it is filtered.
21747 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21748 * @param {Object} scope (optional) The scope of the function (defaults to this)
21750 filterBy : function(fn, scope){
21751 this.snapshot = this.snapshot || this.data;
21752 this.data = this.queryBy(fn, scope||this);
21753 this.fireEvent("datachanged", this);
21757 * Query the records by a specified property.
21758 * @param {String} field A field on your records
21759 * @param {String/RegExp} value Either a string that the field
21760 * should start with or a RegExp to test against the field
21761 * @param {Boolean} anyMatch True to match any part not just the beginning
21762 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21764 query : function(property, value, anyMatch){
21765 var fn = this.createFilterFn(property, value, anyMatch);
21766 return fn ? this.queryBy(fn) : this.data.clone();
21770 * Query by a function. The specified function will be called with each
21771 * record in this data source. If the function returns true the record is included
21773 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
21774 * @param {Object} scope (optional) The scope of the function (defaults to this)
21775 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
21777 queryBy : function(fn, scope){
21778 var data = this.snapshot || this.data;
21779 return data.filterBy(fn, scope||this);
21783 * Collects unique values for a particular dataIndex from this store.
21784 * @param {String} dataIndex The property to collect
21785 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
21786 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
21787 * @return {Array} An array of the unique values
21789 collect : function(dataIndex, allowNull, bypassFilter){
21790 var d = (bypassFilter === true && this.snapshot) ?
21791 this.snapshot.items : this.data.items;
21792 var v, sv, r = [], l = {};
21793 for(var i = 0, len = d.length; i < len; i++){
21794 v = d[i].data[dataIndex];
21796 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
21805 * Revert to a view of the Record cache with no filtering applied.
21806 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
21808 clearFilter : function(suppressEvent){
21809 if(this.snapshot && this.snapshot != this.data){
21810 this.data = this.snapshot;
21811 delete this.snapshot;
21812 if(suppressEvent !== true){
21813 this.fireEvent("datachanged", this);
21819 afterEdit : function(record){
21820 if(this.modified.indexOf(record) == -1){
21821 this.modified.push(record);
21823 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
21827 afterReject : function(record){
21828 this.modified.remove(record);
21829 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
21833 afterCommit : function(record){
21834 this.modified.remove(record);
21835 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
21839 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
21840 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
21842 commitChanges : function(){
21843 var m = this.modified.slice(0);
21844 this.modified = [];
21845 for(var i = 0, len = m.length; i < len; i++){
21851 * Cancel outstanding changes on all changed records.
21853 rejectChanges : function(){
21854 var m = this.modified.slice(0);
21855 this.modified = [];
21856 for(var i = 0, len = m.length; i < len; i++){
21861 onMetaChange : function(meta, rtype, o){
21862 this.recordType = rtype;
21863 this.fields = rtype.prototype.fields;
21864 delete this.snapshot;
21865 this.sortInfo = meta.sortInfo || this.sortInfo;
21866 this.modified = [];
21867 this.fireEvent('metachange', this, this.reader.meta);
21870 moveIndex : function(data, type)
21872 var index = this.indexOf(data);
21874 var newIndex = index + type;
21878 this.insert(newIndex, data);
21883 * Ext JS Library 1.1.1
21884 * Copyright(c) 2006-2007, Ext JS, LLC.
21886 * Originally Released Under LGPL - original licence link has changed is not relivant.
21889 * <script type="text/javascript">
21893 * @class Roo.data.SimpleStore
21894 * @extends Roo.data.Store
21895 * Small helper class to make creating Stores from Array data easier.
21896 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
21897 * @cfg {Array} fields An array of field definition objects, or field name strings.
21898 * @cfg {Array} data The multi-dimensional array of data
21900 * @param {Object} config
21902 Roo.data.SimpleStore = function(config){
21903 Roo.data.SimpleStore.superclass.constructor.call(this, {
21905 reader: new Roo.data.ArrayReader({
21908 Roo.data.Record.create(config.fields)
21910 proxy : new Roo.data.MemoryProxy(config.data)
21914 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
21916 * Ext JS Library 1.1.1
21917 * Copyright(c) 2006-2007, Ext JS, LLC.
21919 * Originally Released Under LGPL - original licence link has changed is not relivant.
21922 * <script type="text/javascript">
21927 * @extends Roo.data.Store
21928 * @class Roo.data.JsonStore
21929 * Small helper class to make creating Stores for JSON data easier. <br/>
21931 var store = new Roo.data.JsonStore({
21932 url: 'get-images.php',
21934 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
21937 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
21938 * JsonReader and HttpProxy (unless inline data is provided).</b>
21939 * @cfg {Array} fields An array of field definition objects, or field name strings.
21941 * @param {Object} config
21943 Roo.data.JsonStore = function(c){
21944 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
21945 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
21946 reader: new Roo.data.JsonReader(c, c.fields)
21949 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
21951 * Ext JS Library 1.1.1
21952 * Copyright(c) 2006-2007, Ext JS, LLC.
21954 * Originally Released Under LGPL - original licence link has changed is not relivant.
21957 * <script type="text/javascript">
21961 Roo.data.Field = function(config){
21962 if(typeof config == "string"){
21963 config = {name: config};
21965 Roo.apply(this, config);
21968 this.type = "auto";
21971 var st = Roo.data.SortTypes;
21972 // named sortTypes are supported, here we look them up
21973 if(typeof this.sortType == "string"){
21974 this.sortType = st[this.sortType];
21977 // set default sortType for strings and dates
21978 if(!this.sortType){
21981 this.sortType = st.asUCString;
21984 this.sortType = st.asDate;
21987 this.sortType = st.none;
21992 var stripRe = /[\$,%]/g;
21994 // prebuilt conversion function for this field, instead of
21995 // switching every time we're reading a value
21997 var cv, dateFormat = this.dateFormat;
22002 cv = function(v){ return v; };
22005 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
22009 return v !== undefined && v !== null && v !== '' ?
22010 parseInt(String(v).replace(stripRe, ""), 10) : '';
22015 return v !== undefined && v !== null && v !== '' ?
22016 parseFloat(String(v).replace(stripRe, ""), 10) : '';
22021 cv = function(v){ return v === true || v === "true" || v == 1; };
22028 if(v instanceof Date){
22032 if(dateFormat == "timestamp"){
22033 return new Date(v*1000);
22035 return Date.parseDate(v, dateFormat);
22037 var parsed = Date.parse(v);
22038 return parsed ? new Date(parsed) : null;
22047 Roo.data.Field.prototype = {
22055 * Ext JS Library 1.1.1
22056 * Copyright(c) 2006-2007, Ext JS, LLC.
22058 * Originally Released Under LGPL - original licence link has changed is not relivant.
22061 * <script type="text/javascript">
22064 // Base class for reading structured data from a data source. This class is intended to be
22065 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
22068 * @class Roo.data.DataReader
22069 * Base class for reading structured data from a data source. This class is intended to be
22070 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
22073 Roo.data.DataReader = function(meta, recordType){
22077 this.recordType = recordType instanceof Array ?
22078 Roo.data.Record.create(recordType) : recordType;
22081 Roo.data.DataReader.prototype = {
22083 * Create an empty record
22084 * @param {Object} data (optional) - overlay some values
22085 * @return {Roo.data.Record} record created.
22087 newRow : function(d) {
22089 this.recordType.prototype.fields.each(function(c) {
22091 case 'int' : da[c.name] = 0; break;
22092 case 'date' : da[c.name] = new Date(); break;
22093 case 'float' : da[c.name] = 0.0; break;
22094 case 'boolean' : da[c.name] = false; break;
22095 default : da[c.name] = ""; break;
22099 return new this.recordType(Roo.apply(da, d));
22104 * Ext JS Library 1.1.1
22105 * Copyright(c) 2006-2007, Ext JS, LLC.
22107 * Originally Released Under LGPL - original licence link has changed is not relivant.
22110 * <script type="text/javascript">
22114 * @class Roo.data.DataProxy
22115 * @extends Roo.data.Observable
22116 * This class is an abstract base class for implementations which provide retrieval of
22117 * unformatted data objects.<br>
22119 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
22120 * (of the appropriate type which knows how to parse the data object) to provide a block of
22121 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
22123 * Custom implementations must implement the load method as described in
22124 * {@link Roo.data.HttpProxy#load}.
22126 Roo.data.DataProxy = function(){
22129 * @event beforeload
22130 * Fires before a network request is made to retrieve a data object.
22131 * @param {Object} This DataProxy object.
22132 * @param {Object} params The params parameter to the load function.
22137 * Fires before the load method's callback is called.
22138 * @param {Object} This DataProxy object.
22139 * @param {Object} o The data object.
22140 * @param {Object} arg The callback argument object passed to the load function.
22144 * @event loadexception
22145 * Fires if an Exception occurs during data retrieval.
22146 * @param {Object} This DataProxy object.
22147 * @param {Object} o The data object.
22148 * @param {Object} arg The callback argument object passed to the load function.
22149 * @param {Object} e The Exception.
22151 loadexception : true
22153 Roo.data.DataProxy.superclass.constructor.call(this);
22156 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
22159 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
22163 * Ext JS Library 1.1.1
22164 * Copyright(c) 2006-2007, Ext JS, LLC.
22166 * Originally Released Under LGPL - original licence link has changed is not relivant.
22169 * <script type="text/javascript">
22172 * @class Roo.data.MemoryProxy
22173 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
22174 * to the Reader when its load method is called.
22176 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
22178 Roo.data.MemoryProxy = function(data){
22182 Roo.data.MemoryProxy.superclass.constructor.call(this);
22186 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
22188 * Load data from the requested source (in this case an in-memory
22189 * data object passed to the constructor), read the data object into
22190 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22191 * process that block using the passed callback.
22192 * @param {Object} params This parameter is not used by the MemoryProxy class.
22193 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22194 * object into a block of Roo.data.Records.
22195 * @param {Function} callback The function into which to pass the block of Roo.data.records.
22196 * The function must be passed <ul>
22197 * <li>The Record block object</li>
22198 * <li>The "arg" argument from the load function</li>
22199 * <li>A boolean success indicator</li>
22201 * @param {Object} scope The scope in which to call the callback
22202 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22204 load : function(params, reader, callback, scope, arg){
22205 params = params || {};
22208 result = reader.readRecords(this.data);
22210 this.fireEvent("loadexception", this, arg, null, e);
22211 callback.call(scope, null, arg, false);
22214 callback.call(scope, result, arg, true);
22218 update : function(params, records){
22223 * Ext JS Library 1.1.1
22224 * Copyright(c) 2006-2007, Ext JS, LLC.
22226 * Originally Released Under LGPL - original licence link has changed is not relivant.
22229 * <script type="text/javascript">
22232 * @class Roo.data.HttpProxy
22233 * @extends Roo.data.DataProxy
22234 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
22235 * configured to reference a certain URL.<br><br>
22237 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
22238 * from which the running page was served.<br><br>
22240 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
22242 * Be aware that to enable the browser to parse an XML document, the server must set
22243 * the Content-Type header in the HTTP response to "text/xml".
22245 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
22246 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
22247 * will be used to make the request.
22249 Roo.data.HttpProxy = function(conn){
22250 Roo.data.HttpProxy.superclass.constructor.call(this);
22251 // is conn a conn config or a real conn?
22253 this.useAjax = !conn || !conn.events;
22257 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
22258 // thse are take from connection...
22261 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
22264 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
22265 * extra parameters to each request made by this object. (defaults to undefined)
22268 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
22269 * to each request made by this object. (defaults to undefined)
22272 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
22275 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
22278 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
22284 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
22288 * Return the {@link Roo.data.Connection} object being used by this Proxy.
22289 * @return {Connection} The Connection object. This object may be used to subscribe to events on
22290 * a finer-grained basis than the DataProxy events.
22292 getConnection : function(){
22293 return this.useAjax ? Roo.Ajax : this.conn;
22297 * Load data from the configured {@link Roo.data.Connection}, read the data object into
22298 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
22299 * process that block using the passed callback.
22300 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22301 * for the request to the remote server.
22302 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22303 * object into a block of Roo.data.Records.
22304 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22305 * The function must be passed <ul>
22306 * <li>The Record block object</li>
22307 * <li>The "arg" argument from the load function</li>
22308 * <li>A boolean success indicator</li>
22310 * @param {Object} scope The scope in which to call the callback
22311 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22313 load : function(params, reader, callback, scope, arg){
22314 if(this.fireEvent("beforeload", this, params) !== false){
22316 params : params || {},
22318 callback : callback,
22323 callback : this.loadResponse,
22327 Roo.applyIf(o, this.conn);
22328 if(this.activeRequest){
22329 Roo.Ajax.abort(this.activeRequest);
22331 this.activeRequest = Roo.Ajax.request(o);
22333 this.conn.request(o);
22336 callback.call(scope||this, null, arg, false);
22341 loadResponse : function(o, success, response){
22342 delete this.activeRequest;
22344 this.fireEvent("loadexception", this, o, response);
22345 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22350 result = o.reader.read(response);
22352 this.fireEvent("loadexception", this, o, response, e);
22353 o.request.callback.call(o.request.scope, null, o.request.arg, false);
22357 this.fireEvent("load", this, o, o.request.arg);
22358 o.request.callback.call(o.request.scope, result, o.request.arg, true);
22362 update : function(dataSet){
22367 updateResponse : function(dataSet){
22372 * Ext JS Library 1.1.1
22373 * Copyright(c) 2006-2007, Ext JS, LLC.
22375 * Originally Released Under LGPL - original licence link has changed is not relivant.
22378 * <script type="text/javascript">
22382 * @class Roo.data.ScriptTagProxy
22383 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
22384 * other than the originating domain of the running page.<br><br>
22386 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
22387 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
22389 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
22390 * source code that is used as the source inside a <script> tag.<br><br>
22392 * In order for the browser to process the returned data, the server must wrap the data object
22393 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
22394 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
22395 * depending on whether the callback name was passed:
22398 boolean scriptTag = false;
22399 String cb = request.getParameter("callback");
22402 response.setContentType("text/javascript");
22404 response.setContentType("application/x-json");
22406 Writer out = response.getWriter();
22408 out.write(cb + "(");
22410 out.print(dataBlock.toJsonString());
22417 * @param {Object} config A configuration object.
22419 Roo.data.ScriptTagProxy = function(config){
22420 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
22421 Roo.apply(this, config);
22422 this.head = document.getElementsByTagName("head")[0];
22425 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
22427 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
22429 * @cfg {String} url The URL from which to request the data object.
22432 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
22436 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
22437 * the server the name of the callback function set up by the load call to process the returned data object.
22438 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
22439 * javascript output which calls this named function passing the data object as its only parameter.
22441 callbackParam : "callback",
22443 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
22444 * name to the request.
22449 * Load data from the configured URL, read the data object into
22450 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
22451 * process that block using the passed callback.
22452 * @param {Object} params An object containing properties which are to be used as HTTP parameters
22453 * for the request to the remote server.
22454 * @param {Roo.data.DataReader} reader The Reader object which converts the data
22455 * object into a block of Roo.data.Records.
22456 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
22457 * The function must be passed <ul>
22458 * <li>The Record block object</li>
22459 * <li>The "arg" argument from the load function</li>
22460 * <li>A boolean success indicator</li>
22462 * @param {Object} scope The scope in which to call the callback
22463 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
22465 load : function(params, reader, callback, scope, arg){
22466 if(this.fireEvent("beforeload", this, params) !== false){
22468 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
22470 var url = this.url;
22471 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
22473 url += "&_dc=" + (new Date().getTime());
22475 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
22478 cb : "stcCallback"+transId,
22479 scriptId : "stcScript"+transId,
22483 callback : callback,
22489 window[trans.cb] = function(o){
22490 conn.handleResponse(o, trans);
22493 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
22495 if(this.autoAbort !== false){
22499 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
22501 var script = document.createElement("script");
22502 script.setAttribute("src", url);
22503 script.setAttribute("type", "text/javascript");
22504 script.setAttribute("id", trans.scriptId);
22505 this.head.appendChild(script);
22507 this.trans = trans;
22509 callback.call(scope||this, null, arg, false);
22514 isLoading : function(){
22515 return this.trans ? true : false;
22519 * Abort the current server request.
22521 abort : function(){
22522 if(this.isLoading()){
22523 this.destroyTrans(this.trans);
22528 destroyTrans : function(trans, isLoaded){
22529 this.head.removeChild(document.getElementById(trans.scriptId));
22530 clearTimeout(trans.timeoutId);
22532 window[trans.cb] = undefined;
22534 delete window[trans.cb];
22537 // if hasn't been loaded, wait for load to remove it to prevent script error
22538 window[trans.cb] = function(){
22539 window[trans.cb] = undefined;
22541 delete window[trans.cb];
22548 handleResponse : function(o, trans){
22549 this.trans = false;
22550 this.destroyTrans(trans, true);
22553 result = trans.reader.readRecords(o);
22555 this.fireEvent("loadexception", this, o, trans.arg, e);
22556 trans.callback.call(trans.scope||window, null, trans.arg, false);
22559 this.fireEvent("load", this, o, trans.arg);
22560 trans.callback.call(trans.scope||window, result, trans.arg, true);
22564 handleFailure : function(trans){
22565 this.trans = false;
22566 this.destroyTrans(trans, false);
22567 this.fireEvent("loadexception", this, null, trans.arg);
22568 trans.callback.call(trans.scope||window, null, trans.arg, false);
22572 * Ext JS Library 1.1.1
22573 * Copyright(c) 2006-2007, Ext JS, LLC.
22575 * Originally Released Under LGPL - original licence link has changed is not relivant.
22578 * <script type="text/javascript">
22582 * @class Roo.data.JsonReader
22583 * @extends Roo.data.DataReader
22584 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
22585 * based on mappings in a provided Roo.data.Record constructor.
22587 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
22588 * in the reply previously.
22593 var RecordDef = Roo.data.Record.create([
22594 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22595 {name: 'occupation'} // This field will use "occupation" as the mapping.
22597 var myReader = new Roo.data.JsonReader({
22598 totalProperty: "results", // The property which contains the total dataset size (optional)
22599 root: "rows", // The property which contains an Array of row objects
22600 id: "id" // The property within each row object that provides an ID for the record (optional)
22604 * This would consume a JSON file like this:
22606 { 'results': 2, 'rows': [
22607 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
22608 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
22611 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
22612 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22613 * paged from the remote server.
22614 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
22615 * @cfg {String} root name of the property which contains the Array of row objects.
22616 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
22618 * Create a new JsonReader
22619 * @param {Object} meta Metadata configuration options
22620 * @param {Object} recordType Either an Array of field definition objects,
22621 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
22623 Roo.data.JsonReader = function(meta, recordType){
22626 // set some defaults:
22627 Roo.applyIf(meta, {
22628 totalProperty: 'total',
22629 successProperty : 'success',
22634 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22636 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
22639 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
22640 * Used by Store query builder to append _requestMeta to params.
22643 metaFromRemote : false,
22645 * This method is only used by a DataProxy which has retrieved data from a remote server.
22646 * @param {Object} response The XHR object which contains the JSON data in its responseText.
22647 * @return {Object} data A data block which is used by an Roo.data.Store object as
22648 * a cache of Roo.data.Records.
22650 read : function(response){
22651 var json = response.responseText;
22653 var o = /* eval:var:o */ eval("("+json+")");
22655 throw {message: "JsonReader.read: Json object not found"};
22661 this.metaFromRemote = true;
22662 this.meta = o.metaData;
22663 this.recordType = Roo.data.Record.create(o.metaData.fields);
22664 this.onMetaChange(this.meta, this.recordType, o);
22666 return this.readRecords(o);
22669 // private function a store will implement
22670 onMetaChange : function(meta, recordType, o){
22677 simpleAccess: function(obj, subsc) {
22684 getJsonAccessor: function(){
22686 return function(expr) {
22688 return(re.test(expr))
22689 ? new Function("obj", "return obj." + expr)
22694 return Roo.emptyFn;
22699 * Create a data block containing Roo.data.Records from an XML document.
22700 * @param {Object} o An object which contains an Array of row objects in the property specified
22701 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
22702 * which contains the total size of the dataset.
22703 * @return {Object} data A data block which is used by an Roo.data.Store object as
22704 * a cache of Roo.data.Records.
22706 readRecords : function(o){
22708 * After any data loads, the raw JSON data is available for further custom processing.
22712 var s = this.meta, Record = this.recordType,
22713 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
22715 // Generate extraction functions for the totalProperty, the root, the id, and for each field
22717 if(s.totalProperty) {
22718 this.getTotal = this.getJsonAccessor(s.totalProperty);
22720 if(s.successProperty) {
22721 this.getSuccess = this.getJsonAccessor(s.successProperty);
22723 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
22725 var g = this.getJsonAccessor(s.id);
22726 this.getId = function(rec) {
22728 return (r === undefined || r === "") ? null : r;
22731 this.getId = function(){return null;};
22734 for(var jj = 0; jj < fl; jj++){
22736 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
22737 this.ef[jj] = this.getJsonAccessor(map);
22741 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
22742 if(s.totalProperty){
22743 var vt = parseInt(this.getTotal(o), 10);
22748 if(s.successProperty){
22749 var vs = this.getSuccess(o);
22750 if(vs === false || vs === 'false'){
22755 for(var i = 0; i < c; i++){
22758 var id = this.getId(n);
22759 for(var j = 0; j < fl; j++){
22761 var v = this.ef[j](n);
22763 Roo.log('missing convert for ' + f.name);
22767 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
22769 var record = new Record(values, id);
22771 records[i] = record;
22777 totalRecords : totalRecords
22782 * Ext JS Library 1.1.1
22783 * Copyright(c) 2006-2007, Ext JS, LLC.
22785 * Originally Released Under LGPL - original licence link has changed is not relivant.
22788 * <script type="text/javascript">
22792 * @class Roo.data.XmlReader
22793 * @extends Roo.data.DataReader
22794 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
22795 * based on mappings in a provided Roo.data.Record constructor.<br><br>
22797 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
22798 * header in the HTTP response must be set to "text/xml".</em>
22802 var RecordDef = Roo.data.Record.create([
22803 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
22804 {name: 'occupation'} // This field will use "occupation" as the mapping.
22806 var myReader = new Roo.data.XmlReader({
22807 totalRecords: "results", // The element which contains the total dataset size (optional)
22808 record: "row", // The repeated element which contains row information
22809 id: "id" // The element within the row that provides an ID for the record (optional)
22813 * This would consume an XML file like this:
22817 <results>2</results>
22820 <name>Bill</name>
22821 <occupation>Gardener</occupation>
22825 <name>Ben</name>
22826 <occupation>Horticulturalist</occupation>
22830 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
22831 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
22832 * paged from the remote server.
22833 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
22834 * @cfg {String} success The DomQuery path to the success attribute used by forms.
22835 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
22836 * a record identifier value.
22838 * Create a new XmlReader
22839 * @param {Object} meta Metadata configuration options
22840 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
22841 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
22842 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
22844 Roo.data.XmlReader = function(meta, recordType){
22846 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
22848 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
22850 * This method is only used by a DataProxy which has retrieved data from a remote server.
22851 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
22852 * to contain a method called 'responseXML' that returns an XML document object.
22853 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22854 * a cache of Roo.data.Records.
22856 read : function(response){
22857 var doc = response.responseXML;
22859 throw {message: "XmlReader.read: XML Document not available"};
22861 return this.readRecords(doc);
22865 * Create a data block containing Roo.data.Records from an XML document.
22866 * @param {Object} doc A parsed XML document.
22867 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
22868 * a cache of Roo.data.Records.
22870 readRecords : function(doc){
22872 * After any data loads/reads, the raw XML Document is available for further custom processing.
22873 * @type XMLDocument
22875 this.xmlData = doc;
22876 var root = doc.documentElement || doc;
22877 var q = Roo.DomQuery;
22878 var recordType = this.recordType, fields = recordType.prototype.fields;
22879 var sid = this.meta.id;
22880 var totalRecords = 0, success = true;
22881 if(this.meta.totalRecords){
22882 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
22885 if(this.meta.success){
22886 var sv = q.selectValue(this.meta.success, root, true);
22887 success = sv !== false && sv !== 'false';
22890 var ns = q.select(this.meta.record, root);
22891 for(var i = 0, len = ns.length; i < len; i++) {
22894 var id = sid ? q.selectValue(sid, n) : undefined;
22895 for(var j = 0, jlen = fields.length; j < jlen; j++){
22896 var f = fields.items[j];
22897 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
22899 values[f.name] = v;
22901 var record = new recordType(values, id);
22903 records[records.length] = record;
22909 totalRecords : totalRecords || records.length
22914 * Ext JS Library 1.1.1
22915 * Copyright(c) 2006-2007, Ext JS, LLC.
22917 * Originally Released Under LGPL - original licence link has changed is not relivant.
22920 * <script type="text/javascript">
22924 * @class Roo.data.ArrayReader
22925 * @extends Roo.data.DataReader
22926 * Data reader class to create an Array of Roo.data.Record objects from an Array.
22927 * Each element of that Array represents a row of data fields. The
22928 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
22929 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
22933 var RecordDef = Roo.data.Record.create([
22934 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
22935 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
22937 var myReader = new Roo.data.ArrayReader({
22938 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
22942 * This would consume an Array like this:
22944 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
22946 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
22948 * Create a new JsonReader
22949 * @param {Object} meta Metadata configuration options.
22950 * @param {Object} recordType Either an Array of field definition objects
22951 * as specified to {@link Roo.data.Record#create},
22952 * or an {@link Roo.data.Record} object
22953 * created using {@link Roo.data.Record#create}.
22955 Roo.data.ArrayReader = function(meta, recordType){
22956 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
22959 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
22961 * Create a data block containing Roo.data.Records from an XML document.
22962 * @param {Object} o An Array of row objects which represents the dataset.
22963 * @return {Object} data A data block which is used by an Roo.data.Store object as
22964 * a cache of Roo.data.Records.
22966 readRecords : function(o){
22967 var sid = this.meta ? this.meta.id : null;
22968 var recordType = this.recordType, fields = recordType.prototype.fields;
22971 for(var i = 0; i < root.length; i++){
22974 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
22975 for(var j = 0, jlen = fields.length; j < jlen; j++){
22976 var f = fields.items[j];
22977 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
22978 var v = n[k] !== undefined ? n[k] : f.defaultValue;
22980 values[f.name] = v;
22982 var record = new recordType(values, id);
22984 records[records.length] = record;
22988 totalRecords : records.length
22993 * Ext JS Library 1.1.1
22994 * Copyright(c) 2006-2007, Ext JS, LLC.
22996 * Originally Released Under LGPL - original licence link has changed is not relivant.
22999 * <script type="text/javascript">
23004 * @class Roo.data.Tree
23005 * @extends Roo.util.Observable
23006 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
23007 * in the tree have most standard DOM functionality.
23009 * @param {Node} root (optional) The root node
23011 Roo.data.Tree = function(root){
23012 this.nodeHash = {};
23014 * The root node for this tree
23019 this.setRootNode(root);
23024 * Fires when a new child node is appended to a node in this tree.
23025 * @param {Tree} tree The owner tree
23026 * @param {Node} parent The parent node
23027 * @param {Node} node The newly appended node
23028 * @param {Number} index The index of the newly appended node
23033 * Fires when a child node is removed from a node in this tree.
23034 * @param {Tree} tree The owner tree
23035 * @param {Node} parent The parent node
23036 * @param {Node} node The child node removed
23041 * Fires when a node is moved to a new location in the tree
23042 * @param {Tree} tree The owner tree
23043 * @param {Node} node The node moved
23044 * @param {Node} oldParent The old parent of this node
23045 * @param {Node} newParent The new parent of this node
23046 * @param {Number} index The index it was moved to
23051 * Fires when a new child node is inserted in a node in this tree.
23052 * @param {Tree} tree The owner tree
23053 * @param {Node} parent The parent node
23054 * @param {Node} node The child node inserted
23055 * @param {Node} refNode The child node the node was inserted before
23059 * @event beforeappend
23060 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
23061 * @param {Tree} tree The owner tree
23062 * @param {Node} parent The parent node
23063 * @param {Node} node The child node to be appended
23065 "beforeappend" : true,
23067 * @event beforeremove
23068 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
23069 * @param {Tree} tree The owner tree
23070 * @param {Node} parent The parent node
23071 * @param {Node} node The child node to be removed
23073 "beforeremove" : true,
23075 * @event beforemove
23076 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
23077 * @param {Tree} tree The owner tree
23078 * @param {Node} node The node being moved
23079 * @param {Node} oldParent The parent of the node
23080 * @param {Node} newParent The new parent the node is moving to
23081 * @param {Number} index The index it is being moved to
23083 "beforemove" : true,
23085 * @event beforeinsert
23086 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
23087 * @param {Tree} tree The owner tree
23088 * @param {Node} parent The parent node
23089 * @param {Node} node The child node to be inserted
23090 * @param {Node} refNode The child node the node is being inserted before
23092 "beforeinsert" : true
23095 Roo.data.Tree.superclass.constructor.call(this);
23098 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
23099 pathSeparator: "/",
23101 proxyNodeEvent : function(){
23102 return this.fireEvent.apply(this, arguments);
23106 * Returns the root node for this tree.
23109 getRootNode : function(){
23114 * Sets the root node for this tree.
23115 * @param {Node} node
23118 setRootNode : function(node){
23120 node.ownerTree = this;
23121 node.isRoot = true;
23122 this.registerNode(node);
23127 * Gets a node in this tree by its id.
23128 * @param {String} id
23131 getNodeById : function(id){
23132 return this.nodeHash[id];
23135 registerNode : function(node){
23136 this.nodeHash[node.id] = node;
23139 unregisterNode : function(node){
23140 delete this.nodeHash[node.id];
23143 toString : function(){
23144 return "[Tree"+(this.id?" "+this.id:"")+"]";
23149 * @class Roo.data.Node
23150 * @extends Roo.util.Observable
23151 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
23152 * @cfg {String} id The id for this node. If one is not specified, one is generated.
23154 * @param {Object} attributes The attributes/config for the node
23156 Roo.data.Node = function(attributes){
23158 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
23161 this.attributes = attributes || {};
23162 this.leaf = this.attributes.leaf;
23164 * The node id. @type String
23166 this.id = this.attributes.id;
23168 this.id = Roo.id(null, "ynode-");
23169 this.attributes.id = this.id;
23174 * All child nodes of this node. @type Array
23176 this.childNodes = [];
23177 if(!this.childNodes.indexOf){ // indexOf is a must
23178 this.childNodes.indexOf = function(o){
23179 for(var i = 0, len = this.length; i < len; i++){
23188 * The parent node for this node. @type Node
23190 this.parentNode = null;
23192 * The first direct child node of this node, or null if this node has no child nodes. @type Node
23194 this.firstChild = null;
23196 * The last direct child node of this node, or null if this node has no child nodes. @type Node
23198 this.lastChild = null;
23200 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
23202 this.previousSibling = null;
23204 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
23206 this.nextSibling = null;
23211 * Fires when a new child node is appended
23212 * @param {Tree} tree The owner tree
23213 * @param {Node} this This node
23214 * @param {Node} node The newly appended node
23215 * @param {Number} index The index of the newly appended node
23220 * Fires when a child node is removed
23221 * @param {Tree} tree The owner tree
23222 * @param {Node} this This node
23223 * @param {Node} node The removed node
23228 * Fires when this node is moved to a new location in the tree
23229 * @param {Tree} tree The owner tree
23230 * @param {Node} this This node
23231 * @param {Node} oldParent The old parent of this node
23232 * @param {Node} newParent The new parent of this node
23233 * @param {Number} index The index it was moved to
23238 * Fires when a new child node is inserted.
23239 * @param {Tree} tree The owner tree
23240 * @param {Node} this This node
23241 * @param {Node} node The child node inserted
23242 * @param {Node} refNode The child node the node was inserted before
23246 * @event beforeappend
23247 * Fires before a new child is appended, return false to cancel the append.
23248 * @param {Tree} tree The owner tree
23249 * @param {Node} this This node
23250 * @param {Node} node The child node to be appended
23252 "beforeappend" : true,
23254 * @event beforeremove
23255 * Fires before a child is removed, return false to cancel the remove.
23256 * @param {Tree} tree The owner tree
23257 * @param {Node} this This node
23258 * @param {Node} node The child node to be removed
23260 "beforeremove" : true,
23262 * @event beforemove
23263 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
23264 * @param {Tree} tree The owner tree
23265 * @param {Node} this This node
23266 * @param {Node} oldParent The parent of this node
23267 * @param {Node} newParent The new parent this node is moving to
23268 * @param {Number} index The index it is being moved to
23270 "beforemove" : true,
23272 * @event beforeinsert
23273 * Fires before a new child is inserted, return false to cancel the insert.
23274 * @param {Tree} tree The owner tree
23275 * @param {Node} this This node
23276 * @param {Node} node The child node to be inserted
23277 * @param {Node} refNode The child node the node is being inserted before
23279 "beforeinsert" : true
23281 this.listeners = this.attributes.listeners;
23282 Roo.data.Node.superclass.constructor.call(this);
23285 Roo.extend(Roo.data.Node, Roo.util.Observable, {
23286 fireEvent : function(evtName){
23287 // first do standard event for this node
23288 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
23291 // then bubble it up to the tree if the event wasn't cancelled
23292 var ot = this.getOwnerTree();
23294 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
23302 * Returns true if this node is a leaf
23303 * @return {Boolean}
23305 isLeaf : function(){
23306 return this.leaf === true;
23310 setFirstChild : function(node){
23311 this.firstChild = node;
23315 setLastChild : function(node){
23316 this.lastChild = node;
23321 * Returns true if this node is the last child of its parent
23322 * @return {Boolean}
23324 isLast : function(){
23325 return (!this.parentNode ? true : this.parentNode.lastChild == this);
23329 * Returns true if this node is the first child of its parent
23330 * @return {Boolean}
23332 isFirst : function(){
23333 return (!this.parentNode ? true : this.parentNode.firstChild == this);
23336 hasChildNodes : function(){
23337 return !this.isLeaf() && this.childNodes.length > 0;
23341 * Insert node(s) as the last child node of this node.
23342 * @param {Node/Array} node The node or Array of nodes to append
23343 * @return {Node} The appended node if single append, or null if an array was passed
23345 appendChild : function(node){
23347 if(node instanceof Array){
23349 }else if(arguments.length > 1){
23352 // if passed an array or multiple args do them one by one
23354 for(var i = 0, len = multi.length; i < len; i++) {
23355 this.appendChild(multi[i]);
23358 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
23361 var index = this.childNodes.length;
23362 var oldParent = node.parentNode;
23363 // it's a move, make sure we move it cleanly
23365 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
23368 oldParent.removeChild(node);
23370 index = this.childNodes.length;
23372 this.setFirstChild(node);
23374 this.childNodes.push(node);
23375 node.parentNode = this;
23376 var ps = this.childNodes[index-1];
23378 node.previousSibling = ps;
23379 ps.nextSibling = node;
23381 node.previousSibling = null;
23383 node.nextSibling = null;
23384 this.setLastChild(node);
23385 node.setOwnerTree(this.getOwnerTree());
23386 this.fireEvent("append", this.ownerTree, this, node, index);
23388 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
23395 * Removes a child node from this node.
23396 * @param {Node} node The node to remove
23397 * @return {Node} The removed node
23399 removeChild : function(node){
23400 var index = this.childNodes.indexOf(node);
23404 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
23408 // remove it from childNodes collection
23409 this.childNodes.splice(index, 1);
23412 if(node.previousSibling){
23413 node.previousSibling.nextSibling = node.nextSibling;
23415 if(node.nextSibling){
23416 node.nextSibling.previousSibling = node.previousSibling;
23419 // update child refs
23420 if(this.firstChild == node){
23421 this.setFirstChild(node.nextSibling);
23423 if(this.lastChild == node){
23424 this.setLastChild(node.previousSibling);
23427 node.setOwnerTree(null);
23428 // clear any references from the node
23429 node.parentNode = null;
23430 node.previousSibling = null;
23431 node.nextSibling = null;
23432 this.fireEvent("remove", this.ownerTree, this, node);
23437 * Inserts the first node before the second node in this nodes childNodes collection.
23438 * @param {Node} node The node to insert
23439 * @param {Node} refNode The node to insert before (if null the node is appended)
23440 * @return {Node} The inserted node
23442 insertBefore : function(node, refNode){
23443 if(!refNode){ // like standard Dom, refNode can be null for append
23444 return this.appendChild(node);
23447 if(node == refNode){
23451 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
23454 var index = this.childNodes.indexOf(refNode);
23455 var oldParent = node.parentNode;
23456 var refIndex = index;
23458 // when moving internally, indexes will change after remove
23459 if(oldParent == this && this.childNodes.indexOf(node) < index){
23463 // it's a move, make sure we move it cleanly
23465 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
23468 oldParent.removeChild(node);
23471 this.setFirstChild(node);
23473 this.childNodes.splice(refIndex, 0, node);
23474 node.parentNode = this;
23475 var ps = this.childNodes[refIndex-1];
23477 node.previousSibling = ps;
23478 ps.nextSibling = node;
23480 node.previousSibling = null;
23482 node.nextSibling = refNode;
23483 refNode.previousSibling = node;
23484 node.setOwnerTree(this.getOwnerTree());
23485 this.fireEvent("insert", this.ownerTree, this, node, refNode);
23487 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
23493 * Returns the child node at the specified index.
23494 * @param {Number} index
23497 item : function(index){
23498 return this.childNodes[index];
23502 * Replaces one child node in this node with another.
23503 * @param {Node} newChild The replacement node
23504 * @param {Node} oldChild The node to replace
23505 * @return {Node} The replaced node
23507 replaceChild : function(newChild, oldChild){
23508 this.insertBefore(newChild, oldChild);
23509 this.removeChild(oldChild);
23514 * Returns the index of a child node
23515 * @param {Node} node
23516 * @return {Number} The index of the node or -1 if it was not found
23518 indexOf : function(child){
23519 return this.childNodes.indexOf(child);
23523 * Returns the tree this node is in.
23526 getOwnerTree : function(){
23527 // if it doesn't have one, look for one
23528 if(!this.ownerTree){
23532 this.ownerTree = p.ownerTree;
23538 return this.ownerTree;
23542 * Returns depth of this node (the root node has a depth of 0)
23545 getDepth : function(){
23548 while(p.parentNode){
23556 setOwnerTree : function(tree){
23557 // if it's move, we need to update everyone
23558 if(tree != this.ownerTree){
23559 if(this.ownerTree){
23560 this.ownerTree.unregisterNode(this);
23562 this.ownerTree = tree;
23563 var cs = this.childNodes;
23564 for(var i = 0, len = cs.length; i < len; i++) {
23565 cs[i].setOwnerTree(tree);
23568 tree.registerNode(this);
23574 * Returns the path for this node. The path can be used to expand or select this node programmatically.
23575 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
23576 * @return {String} The path
23578 getPath : function(attr){
23579 attr = attr || "id";
23580 var p = this.parentNode;
23581 var b = [this.attributes[attr]];
23583 b.unshift(p.attributes[attr]);
23586 var sep = this.getOwnerTree().pathSeparator;
23587 return sep + b.join(sep);
23591 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23592 * function call will be the scope provided or the current node. The arguments to the function
23593 * will be the args provided or the current node. If the function returns false at any point,
23594 * the bubble is stopped.
23595 * @param {Function} fn The function to call
23596 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23597 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23599 bubble : function(fn, scope, args){
23602 if(fn.call(scope || p, args || p) === false){
23610 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
23611 * function call will be the scope provided or the current node. The arguments to the function
23612 * will be the args provided or the current node. If the function returns false at any point,
23613 * the cascade is stopped on that branch.
23614 * @param {Function} fn The function to call
23615 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23616 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23618 cascade : function(fn, scope, args){
23619 if(fn.call(scope || this, args || this) !== false){
23620 var cs = this.childNodes;
23621 for(var i = 0, len = cs.length; i < len; i++) {
23622 cs[i].cascade(fn, scope, args);
23628 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
23629 * function call will be the scope provided or the current node. The arguments to the function
23630 * will be the args provided or the current node. If the function returns false at any point,
23631 * the iteration stops.
23632 * @param {Function} fn The function to call
23633 * @param {Object} scope (optional) The scope of the function (defaults to current node)
23634 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
23636 eachChild : function(fn, scope, args){
23637 var cs = this.childNodes;
23638 for(var i = 0, len = cs.length; i < len; i++) {
23639 if(fn.call(scope || this, args || cs[i]) === false){
23646 * Finds the first child that has the attribute with the specified value.
23647 * @param {String} attribute The attribute name
23648 * @param {Mixed} value The value to search for
23649 * @return {Node} The found child or null if none was found
23651 findChild : function(attribute, value){
23652 var cs = this.childNodes;
23653 for(var i = 0, len = cs.length; i < len; i++) {
23654 if(cs[i].attributes[attribute] == value){
23662 * Finds the first child by a custom function. The child matches if the function passed
23664 * @param {Function} fn
23665 * @param {Object} scope (optional)
23666 * @return {Node} The found child or null if none was found
23668 findChildBy : function(fn, scope){
23669 var cs = this.childNodes;
23670 for(var i = 0, len = cs.length; i < len; i++) {
23671 if(fn.call(scope||cs[i], cs[i]) === true){
23679 * Sorts this nodes children using the supplied sort function
23680 * @param {Function} fn
23681 * @param {Object} scope (optional)
23683 sort : function(fn, scope){
23684 var cs = this.childNodes;
23685 var len = cs.length;
23687 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
23689 for(var i = 0; i < len; i++){
23691 n.previousSibling = cs[i-1];
23692 n.nextSibling = cs[i+1];
23694 this.setFirstChild(n);
23697 this.setLastChild(n);
23704 * Returns true if this node is an ancestor (at any point) of the passed node.
23705 * @param {Node} node
23706 * @return {Boolean}
23708 contains : function(node){
23709 return node.isAncestor(this);
23713 * Returns true if the passed node is an ancestor (at any point) of this node.
23714 * @param {Node} node
23715 * @return {Boolean}
23717 isAncestor : function(node){
23718 var p = this.parentNode;
23728 toString : function(){
23729 return "[Node"+(this.id?" "+this.id:"")+"]";
23733 * Ext JS Library 1.1.1
23734 * Copyright(c) 2006-2007, Ext JS, LLC.
23736 * Originally Released Under LGPL - original licence link has changed is not relivant.
23739 * <script type="text/javascript">
23744 * @extends Roo.Element
23745 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
23746 * automatic maintaining of shadow/shim positions.
23747 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
23748 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
23749 * you can pass a string with a CSS class name. False turns off the shadow.
23750 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
23751 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
23752 * @cfg {String} cls CSS class to add to the element
23753 * @cfg {Number} zindex Starting z-index (defaults to 11000)
23754 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
23756 * @param {Object} config An object with config options.
23757 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
23760 Roo.Layer = function(config, existingEl){
23761 config = config || {};
23762 var dh = Roo.DomHelper;
23763 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
23765 this.dom = Roo.getDom(existingEl);
23768 var o = config.dh || {tag: "div", cls: "x-layer"};
23769 this.dom = dh.append(pel, o);
23772 this.addClass(config.cls);
23774 this.constrain = config.constrain !== false;
23775 this.visibilityMode = Roo.Element.VISIBILITY;
23777 this.id = this.dom.id = config.id;
23779 this.id = Roo.id(this.dom);
23781 this.zindex = config.zindex || this.getZIndex();
23782 this.position("absolute", this.zindex);
23784 this.shadowOffset = config.shadowOffset || 4;
23785 this.shadow = new Roo.Shadow({
23786 offset : this.shadowOffset,
23787 mode : config.shadow
23790 this.shadowOffset = 0;
23792 this.useShim = config.shim !== false && Roo.useShims;
23793 this.useDisplay = config.useDisplay;
23797 var supr = Roo.Element.prototype;
23799 // shims are shared among layer to keep from having 100 iframes
23802 Roo.extend(Roo.Layer, Roo.Element, {
23804 getZIndex : function(){
23805 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
23808 getShim : function(){
23815 var shim = shims.shift();
23817 shim = this.createShim();
23818 shim.enableDisplayMode('block');
23819 shim.dom.style.display = 'none';
23820 shim.dom.style.visibility = 'visible';
23822 var pn = this.dom.parentNode;
23823 if(shim.dom.parentNode != pn){
23824 pn.insertBefore(shim.dom, this.dom);
23826 shim.setStyle('z-index', this.getZIndex()-2);
23831 hideShim : function(){
23833 this.shim.setDisplayed(false);
23834 shims.push(this.shim);
23839 disableShadow : function(){
23841 this.shadowDisabled = true;
23842 this.shadow.hide();
23843 this.lastShadowOffset = this.shadowOffset;
23844 this.shadowOffset = 0;
23848 enableShadow : function(show){
23850 this.shadowDisabled = false;
23851 this.shadowOffset = this.lastShadowOffset;
23852 delete this.lastShadowOffset;
23860 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
23861 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
23862 sync : function(doShow){
23863 var sw = this.shadow;
23864 if(!this.updating && this.isVisible() && (sw || this.useShim)){
23865 var sh = this.getShim();
23867 var w = this.getWidth(),
23868 h = this.getHeight();
23870 var l = this.getLeft(true),
23871 t = this.getTop(true);
23873 if(sw && !this.shadowDisabled){
23874 if(doShow && !sw.isVisible()){
23877 sw.realign(l, t, w, h);
23883 // fit the shim behind the shadow, so it is shimmed too
23884 var a = sw.adjusts, s = sh.dom.style;
23885 s.left = (Math.min(l, l+a.l))+"px";
23886 s.top = (Math.min(t, t+a.t))+"px";
23887 s.width = (w+a.w)+"px";
23888 s.height = (h+a.h)+"px";
23895 sh.setLeftTop(l, t);
23902 destroy : function(){
23905 this.shadow.hide();
23907 this.removeAllListeners();
23908 var pn = this.dom.parentNode;
23910 pn.removeChild(this.dom);
23912 Roo.Element.uncache(this.id);
23915 remove : function(){
23920 beginUpdate : function(){
23921 this.updating = true;
23925 endUpdate : function(){
23926 this.updating = false;
23931 hideUnders : function(negOffset){
23933 this.shadow.hide();
23939 constrainXY : function(){
23940 if(this.constrain){
23941 var vw = Roo.lib.Dom.getViewWidth(),
23942 vh = Roo.lib.Dom.getViewHeight();
23943 var s = Roo.get(document).getScroll();
23945 var xy = this.getXY();
23946 var x = xy[0], y = xy[1];
23947 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
23948 // only move it if it needs it
23950 // first validate right/bottom
23951 if((x + w) > vw+s.left){
23952 x = vw - w - this.shadowOffset;
23955 if((y + h) > vh+s.top){
23956 y = vh - h - this.shadowOffset;
23959 // then make sure top/left isn't negative
23970 var ay = this.avoidY;
23971 if(y <= ay && (y+h) >= ay){
23977 supr.setXY.call(this, xy);
23983 isVisible : function(){
23984 return this.visible;
23988 showAction : function(){
23989 this.visible = true; // track visibility to prevent getStyle calls
23990 if(this.useDisplay === true){
23991 this.setDisplayed("");
23992 }else if(this.lastXY){
23993 supr.setXY.call(this, this.lastXY);
23994 }else if(this.lastLT){
23995 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
24000 hideAction : function(){
24001 this.visible = false;
24002 if(this.useDisplay === true){
24003 this.setDisplayed(false);
24005 this.setLeftTop(-10000,-10000);
24009 // overridden Element method
24010 setVisible : function(v, a, d, c, e){
24015 var cb = function(){
24020 }.createDelegate(this);
24021 supr.setVisible.call(this, true, true, d, cb, e);
24024 this.hideUnders(true);
24033 }.createDelegate(this);
24035 supr.setVisible.call(this, v, a, d, cb, e);
24044 storeXY : function(xy){
24045 delete this.lastLT;
24049 storeLeftTop : function(left, top){
24050 delete this.lastXY;
24051 this.lastLT = [left, top];
24055 beforeFx : function(){
24056 this.beforeAction();
24057 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
24061 afterFx : function(){
24062 Roo.Layer.superclass.afterFx.apply(this, arguments);
24063 this.sync(this.isVisible());
24067 beforeAction : function(){
24068 if(!this.updating && this.shadow){
24069 this.shadow.hide();
24073 // overridden Element method
24074 setLeft : function(left){
24075 this.storeLeftTop(left, this.getTop(true));
24076 supr.setLeft.apply(this, arguments);
24080 setTop : function(top){
24081 this.storeLeftTop(this.getLeft(true), top);
24082 supr.setTop.apply(this, arguments);
24086 setLeftTop : function(left, top){
24087 this.storeLeftTop(left, top);
24088 supr.setLeftTop.apply(this, arguments);
24092 setXY : function(xy, a, d, c, e){
24094 this.beforeAction();
24096 var cb = this.createCB(c);
24097 supr.setXY.call(this, xy, a, d, cb, e);
24104 createCB : function(c){
24115 // overridden Element method
24116 setX : function(x, a, d, c, e){
24117 this.setXY([x, this.getY()], a, d, c, e);
24120 // overridden Element method
24121 setY : function(y, a, d, c, e){
24122 this.setXY([this.getX(), y], a, d, c, e);
24125 // overridden Element method
24126 setSize : function(w, h, a, d, c, e){
24127 this.beforeAction();
24128 var cb = this.createCB(c);
24129 supr.setSize.call(this, w, h, a, d, cb, e);
24135 // overridden Element method
24136 setWidth : function(w, a, d, c, e){
24137 this.beforeAction();
24138 var cb = this.createCB(c);
24139 supr.setWidth.call(this, w, a, d, cb, e);
24145 // overridden Element method
24146 setHeight : function(h, a, d, c, e){
24147 this.beforeAction();
24148 var cb = this.createCB(c);
24149 supr.setHeight.call(this, h, a, d, cb, e);
24155 // overridden Element method
24156 setBounds : function(x, y, w, h, a, d, c, e){
24157 this.beforeAction();
24158 var cb = this.createCB(c);
24160 this.storeXY([x, y]);
24161 supr.setXY.call(this, [x, y]);
24162 supr.setSize.call(this, w, h, a, d, cb, e);
24165 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
24171 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
24172 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
24173 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
24174 * @param {Number} zindex The new z-index to set
24175 * @return {this} The Layer
24177 setZIndex : function(zindex){
24178 this.zindex = zindex;
24179 this.setStyle("z-index", zindex + 2);
24181 this.shadow.setZIndex(zindex + 1);
24184 this.shim.setStyle("z-index", zindex);
24190 * Ext JS Library 1.1.1
24191 * Copyright(c) 2006-2007, Ext JS, LLC.
24193 * Originally Released Under LGPL - original licence link has changed is not relivant.
24196 * <script type="text/javascript">
24201 * @class Roo.Shadow
24202 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
24203 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
24204 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
24206 * Create a new Shadow
24207 * @param {Object} config The config object
24209 Roo.Shadow = function(config){
24210 Roo.apply(this, config);
24211 if(typeof this.mode != "string"){
24212 this.mode = this.defaultMode;
24214 var o = this.offset, a = {h: 0};
24215 var rad = Math.floor(this.offset/2);
24216 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
24222 a.l -= this.offset + rad;
24223 a.t -= this.offset + rad;
24234 a.l -= (this.offset - rad);
24235 a.t -= this.offset + rad;
24237 a.w -= (this.offset - rad)*2;
24248 a.l -= (this.offset - rad);
24249 a.t -= (this.offset - rad);
24251 a.w -= (this.offset + rad + 1);
24252 a.h -= (this.offset + rad);
24261 Roo.Shadow.prototype = {
24263 * @cfg {String} mode
24264 * The shadow display mode. Supports the following options:<br />
24265 * sides: Shadow displays on both sides and bottom only<br />
24266 * frame: Shadow displays equally on all four sides<br />
24267 * drop: Traditional bottom-right drop shadow (default)
24270 * @cfg {String} offset
24271 * The number of pixels to offset the shadow from the element (defaults to 4)
24276 defaultMode: "drop",
24279 * Displays the shadow under the target element
24280 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
24282 show : function(target){
24283 target = Roo.get(target);
24285 this.el = Roo.Shadow.Pool.pull();
24286 if(this.el.dom.nextSibling != target.dom){
24287 this.el.insertBefore(target);
24290 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
24292 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
24295 target.getLeft(true),
24296 target.getTop(true),
24300 this.el.dom.style.display = "block";
24304 * Returns true if the shadow is visible, else false
24306 isVisible : function(){
24307 return this.el ? true : false;
24311 * Direct alignment when values are already available. Show must be called at least once before
24312 * calling this method to ensure it is initialized.
24313 * @param {Number} left The target element left position
24314 * @param {Number} top The target element top position
24315 * @param {Number} width The target element width
24316 * @param {Number} height The target element height
24318 realign : function(l, t, w, h){
24322 var a = this.adjusts, d = this.el.dom, s = d.style;
24324 s.left = (l+a.l)+"px";
24325 s.top = (t+a.t)+"px";
24326 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
24328 if(s.width != sws || s.height != shs){
24332 var cn = d.childNodes;
24333 var sww = Math.max(0, (sw-12))+"px";
24334 cn[0].childNodes[1].style.width = sww;
24335 cn[1].childNodes[1].style.width = sww;
24336 cn[2].childNodes[1].style.width = sww;
24337 cn[1].style.height = Math.max(0, (sh-12))+"px";
24343 * Hides this shadow
24347 this.el.dom.style.display = "none";
24348 Roo.Shadow.Pool.push(this.el);
24354 * Adjust the z-index of this shadow
24355 * @param {Number} zindex The new z-index
24357 setZIndex : function(z){
24360 this.el.setStyle("z-index", z);
24365 // Private utility class that manages the internal Shadow cache
24366 Roo.Shadow.Pool = function(){
24368 var markup = Roo.isIE ?
24369 '<div class="x-ie-shadow"></div>' :
24370 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
24373 var sh = p.shift();
24375 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
24376 sh.autoBoxAdjust = false;
24381 push : function(sh){
24387 * Ext JS Library 1.1.1
24388 * Copyright(c) 2006-2007, Ext JS, LLC.
24390 * Originally Released Under LGPL - original licence link has changed is not relivant.
24393 * <script type="text/javascript">
24398 * @class Roo.SplitBar
24399 * @extends Roo.util.Observable
24400 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
24404 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
24405 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
24406 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
24407 split.minSize = 100;
24408 split.maxSize = 600;
24409 split.animate = true;
24410 split.on('moved', splitterMoved);
24413 * Create a new SplitBar
24414 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
24415 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
24416 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24417 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
24418 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
24419 position of the SplitBar).
24421 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
24424 this.el = Roo.get(dragElement, true);
24425 this.el.dom.unselectable = "on";
24427 this.resizingEl = Roo.get(resizingElement, true);
24431 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
24432 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
24435 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
24438 * The minimum size of the resizing element. (Defaults to 0)
24444 * The maximum size of the resizing element. (Defaults to 2000)
24447 this.maxSize = 2000;
24450 * Whether to animate the transition to the new size
24453 this.animate = false;
24456 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
24459 this.useShim = false;
24464 if(!existingProxy){
24466 this.proxy = Roo.SplitBar.createProxy(this.orientation);
24468 this.proxy = Roo.get(existingProxy).dom;
24471 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
24474 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
24477 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
24480 this.dragSpecs = {};
24483 * @private The adapter to use to positon and resize elements
24485 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
24486 this.adapter.init(this);
24488 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24490 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
24491 this.el.addClass("x-splitbar-h");
24494 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
24495 this.el.addClass("x-splitbar-v");
24501 * Fires when the splitter is moved (alias for {@link #event-moved})
24502 * @param {Roo.SplitBar} this
24503 * @param {Number} newSize the new width or height
24508 * Fires when the splitter is moved
24509 * @param {Roo.SplitBar} this
24510 * @param {Number} newSize the new width or height
24514 * @event beforeresize
24515 * Fires before the splitter is dragged
24516 * @param {Roo.SplitBar} this
24518 "beforeresize" : true,
24520 "beforeapply" : true
24523 Roo.util.Observable.call(this);
24526 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
24527 onStartProxyDrag : function(x, y){
24528 this.fireEvent("beforeresize", this);
24530 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
24532 o.enableDisplayMode("block");
24533 // all splitbars share the same overlay
24534 Roo.SplitBar.prototype.overlay = o;
24536 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
24537 this.overlay.show();
24538 Roo.get(this.proxy).setDisplayed("block");
24539 var size = this.adapter.getElementSize(this);
24540 this.activeMinSize = this.getMinimumSize();;
24541 this.activeMaxSize = this.getMaximumSize();;
24542 var c1 = size - this.activeMinSize;
24543 var c2 = Math.max(this.activeMaxSize - size, 0);
24544 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24545 this.dd.resetConstraints();
24546 this.dd.setXConstraint(
24547 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
24548 this.placement == Roo.SplitBar.LEFT ? c2 : c1
24550 this.dd.setYConstraint(0, 0);
24552 this.dd.resetConstraints();
24553 this.dd.setXConstraint(0, 0);
24554 this.dd.setYConstraint(
24555 this.placement == Roo.SplitBar.TOP ? c1 : c2,
24556 this.placement == Roo.SplitBar.TOP ? c2 : c1
24559 this.dragSpecs.startSize = size;
24560 this.dragSpecs.startPoint = [x, y];
24561 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
24565 * @private Called after the drag operation by the DDProxy
24567 onEndProxyDrag : function(e){
24568 Roo.get(this.proxy).setDisplayed(false);
24569 var endPoint = Roo.lib.Event.getXY(e);
24571 this.overlay.hide();
24574 if(this.orientation == Roo.SplitBar.HORIZONTAL){
24575 newSize = this.dragSpecs.startSize +
24576 (this.placement == Roo.SplitBar.LEFT ?
24577 endPoint[0] - this.dragSpecs.startPoint[0] :
24578 this.dragSpecs.startPoint[0] - endPoint[0]
24581 newSize = this.dragSpecs.startSize +
24582 (this.placement == Roo.SplitBar.TOP ?
24583 endPoint[1] - this.dragSpecs.startPoint[1] :
24584 this.dragSpecs.startPoint[1] - endPoint[1]
24587 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
24588 if(newSize != this.dragSpecs.startSize){
24589 if(this.fireEvent('beforeapply', this, newSize) !== false){
24590 this.adapter.setElementSize(this, newSize);
24591 this.fireEvent("moved", this, newSize);
24592 this.fireEvent("resize", this, newSize);
24598 * Get the adapter this SplitBar uses
24599 * @return The adapter object
24601 getAdapter : function(){
24602 return this.adapter;
24606 * Set the adapter this SplitBar uses
24607 * @param {Object} adapter A SplitBar adapter object
24609 setAdapter : function(adapter){
24610 this.adapter = adapter;
24611 this.adapter.init(this);
24615 * Gets the minimum size for the resizing element
24616 * @return {Number} The minimum size
24618 getMinimumSize : function(){
24619 return this.minSize;
24623 * Sets the minimum size for the resizing element
24624 * @param {Number} minSize The minimum size
24626 setMinimumSize : function(minSize){
24627 this.minSize = minSize;
24631 * Gets the maximum size for the resizing element
24632 * @return {Number} The maximum size
24634 getMaximumSize : function(){
24635 return this.maxSize;
24639 * Sets the maximum size for the resizing element
24640 * @param {Number} maxSize The maximum size
24642 setMaximumSize : function(maxSize){
24643 this.maxSize = maxSize;
24647 * Sets the initialize size for the resizing element
24648 * @param {Number} size The initial size
24650 setCurrentSize : function(size){
24651 var oldAnimate = this.animate;
24652 this.animate = false;
24653 this.adapter.setElementSize(this, size);
24654 this.animate = oldAnimate;
24658 * Destroy this splitbar.
24659 * @param {Boolean} removeEl True to remove the element
24661 destroy : function(removeEl){
24663 this.shim.remove();
24666 this.proxy.parentNode.removeChild(this.proxy);
24674 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
24676 Roo.SplitBar.createProxy = function(dir){
24677 var proxy = new Roo.Element(document.createElement("div"));
24678 proxy.unselectable();
24679 var cls = 'x-splitbar-proxy';
24680 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
24681 document.body.appendChild(proxy.dom);
24686 * @class Roo.SplitBar.BasicLayoutAdapter
24687 * Default Adapter. It assumes the splitter and resizing element are not positioned
24688 * elements and only gets/sets the width of the element. Generally used for table based layouts.
24690 Roo.SplitBar.BasicLayoutAdapter = function(){
24693 Roo.SplitBar.BasicLayoutAdapter.prototype = {
24694 // do nothing for now
24695 init : function(s){
24699 * Called before drag operations to get the current size of the resizing element.
24700 * @param {Roo.SplitBar} s The SplitBar using this adapter
24702 getElementSize : function(s){
24703 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24704 return s.resizingEl.getWidth();
24706 return s.resizingEl.getHeight();
24711 * Called after drag operations to set the size of the resizing element.
24712 * @param {Roo.SplitBar} s The SplitBar using this adapter
24713 * @param {Number} newSize The new size to set
24714 * @param {Function} onComplete A function to be invoked when resizing is complete
24716 setElementSize : function(s, newSize, onComplete){
24717 if(s.orientation == Roo.SplitBar.HORIZONTAL){
24719 s.resizingEl.setWidth(newSize);
24721 onComplete(s, newSize);
24724 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
24729 s.resizingEl.setHeight(newSize);
24731 onComplete(s, newSize);
24734 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
24741 *@class Roo.SplitBar.AbsoluteLayoutAdapter
24742 * @extends Roo.SplitBar.BasicLayoutAdapter
24743 * Adapter that moves the splitter element to align with the resized sizing element.
24744 * Used with an absolute positioned SplitBar.
24745 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
24746 * document.body, make sure you assign an id to the body element.
24748 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
24749 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
24750 this.container = Roo.get(container);
24753 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
24754 init : function(s){
24755 this.basic.init(s);
24758 getElementSize : function(s){
24759 return this.basic.getElementSize(s);
24762 setElementSize : function(s, newSize, onComplete){
24763 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
24766 moveSplitter : function(s){
24767 var yes = Roo.SplitBar;
24768 switch(s.placement){
24770 s.el.setX(s.resizingEl.getRight());
24773 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
24776 s.el.setY(s.resizingEl.getBottom());
24779 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
24786 * Orientation constant - Create a vertical SplitBar
24790 Roo.SplitBar.VERTICAL = 1;
24793 * Orientation constant - Create a horizontal SplitBar
24797 Roo.SplitBar.HORIZONTAL = 2;
24800 * Placement constant - The resizing element is to the left of the splitter element
24804 Roo.SplitBar.LEFT = 1;
24807 * Placement constant - The resizing element is to the right of the splitter element
24811 Roo.SplitBar.RIGHT = 2;
24814 * Placement constant - The resizing element is positioned above the splitter element
24818 Roo.SplitBar.TOP = 3;
24821 * Placement constant - The resizing element is positioned under splitter element
24825 Roo.SplitBar.BOTTOM = 4;
24828 * Ext JS Library 1.1.1
24829 * Copyright(c) 2006-2007, Ext JS, LLC.
24831 * Originally Released Under LGPL - original licence link has changed is not relivant.
24834 * <script type="text/javascript">
24839 * @extends Roo.util.Observable
24840 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
24841 * This class also supports single and multi selection modes. <br>
24842 * Create a data model bound view:
24844 var store = new Roo.data.Store(...);
24846 var view = new Roo.View({
24848 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
24850 singleSelect: true,
24851 selectedClass: "ydataview-selected",
24855 // listen for node click?
24856 view.on("click", function(vw, index, node, e){
24857 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
24861 dataModel.load("foobar.xml");
24863 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
24865 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
24866 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
24868 * Note: old style constructor is still suported (container, template, config)
24871 * Create a new View
24872 * @param {Object} config The config object
24875 Roo.View = function(config, depreciated_tpl, depreciated_config){
24877 this.parent = false;
24879 if (typeof(depreciated_tpl) == 'undefined') {
24880 // new way.. - universal constructor.
24881 Roo.apply(this, config);
24882 this.el = Roo.get(this.el);
24885 this.el = Roo.get(config);
24886 this.tpl = depreciated_tpl;
24887 Roo.apply(this, depreciated_config);
24889 this.wrapEl = this.el.wrap().wrap();
24890 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
24893 if(typeof(this.tpl) == "string"){
24894 this.tpl = new Roo.Template(this.tpl);
24896 // support xtype ctors..
24897 this.tpl = new Roo.factory(this.tpl, Roo);
24901 this.tpl.compile();
24906 * @event beforeclick
24907 * Fires before a click is processed. Returns false to cancel the default action.
24908 * @param {Roo.View} this
24909 * @param {Number} index The index of the target node
24910 * @param {HTMLElement} node The target node
24911 * @param {Roo.EventObject} e The raw event object
24913 "beforeclick" : true,
24916 * Fires when a template node is clicked.
24917 * @param {Roo.View} this
24918 * @param {Number} index The index of the target node
24919 * @param {HTMLElement} node The target node
24920 * @param {Roo.EventObject} e The raw event object
24925 * Fires when a template node is double clicked.
24926 * @param {Roo.View} this
24927 * @param {Number} index The index of the target node
24928 * @param {HTMLElement} node The target node
24929 * @param {Roo.EventObject} e The raw event object
24933 * @event contextmenu
24934 * Fires when a template node is right clicked.
24935 * @param {Roo.View} this
24936 * @param {Number} index The index of the target node
24937 * @param {HTMLElement} node The target node
24938 * @param {Roo.EventObject} e The raw event object
24940 "contextmenu" : true,
24942 * @event selectionchange
24943 * Fires when the selected nodes change.
24944 * @param {Roo.View} this
24945 * @param {Array} selections Array of the selected nodes
24947 "selectionchange" : true,
24950 * @event beforeselect
24951 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
24952 * @param {Roo.View} this
24953 * @param {HTMLElement} node The node to be selected
24954 * @param {Array} selections Array of currently selected nodes
24956 "beforeselect" : true,
24958 * @event preparedata
24959 * Fires on every row to render, to allow you to change the data.
24960 * @param {Roo.View} this
24961 * @param {Object} data to be rendered (change this)
24963 "preparedata" : true
24971 "click": this.onClick,
24972 "dblclick": this.onDblClick,
24973 "contextmenu": this.onContextMenu,
24977 this.selections = [];
24979 this.cmp = new Roo.CompositeElementLite([]);
24981 this.store = Roo.factory(this.store, Roo.data);
24982 this.setStore(this.store, true);
24985 if ( this.footer && this.footer.xtype) {
24987 var fctr = this.wrapEl.appendChild(document.createElement("div"));
24989 this.footer.dataSource = this.store
24990 this.footer.container = fctr;
24991 this.footer = Roo.factory(this.footer, Roo);
24992 fctr.insertFirst(this.el);
24994 // this is a bit insane - as the paging toolbar seems to detach the el..
24995 // dom.parentNode.parentNode.parentNode
24996 // they get detached?
25000 Roo.View.superclass.constructor.call(this);
25005 Roo.extend(Roo.View, Roo.util.Observable, {
25008 * @cfg {Roo.data.Store} store Data store to load data from.
25013 * @cfg {String|Roo.Element} el The container element.
25018 * @cfg {String|Roo.Template} tpl The template used by this View
25022 * @cfg {String} dataName the named area of the template to use as the data area
25023 * Works with domtemplates roo-name="name"
25027 * @cfg {String} selectedClass The css class to add to selected nodes
25029 selectedClass : "x-view-selected",
25031 * @cfg {String} emptyText The empty text to show when nothing is loaded.
25036 * @cfg {String} text to display on mask (default Loading)
25040 * @cfg {Boolean} multiSelect Allow multiple selection
25042 multiSelect : false,
25044 * @cfg {Boolean} singleSelect Allow single selection
25046 singleSelect: false,
25049 * @cfg {Boolean} toggleSelect - selecting
25051 toggleSelect : false,
25054 * @cfg {Boolean} tickable - selecting
25059 * Returns the element this view is bound to.
25060 * @return {Roo.Element}
25062 getEl : function(){
25063 return this.wrapEl;
25069 * Refreshes the view. - called by datachanged on the store. - do not call directly.
25071 refresh : function(){
25072 //Roo.log('refresh');
25075 // if we are using something like 'domtemplate', then
25076 // the what gets used is:
25077 // t.applySubtemplate(NAME, data, wrapping data..)
25078 // the outer template then get' applied with
25079 // the store 'extra data'
25080 // and the body get's added to the
25081 // roo-name="data" node?
25082 // <span class='roo-tpl-{name}'></span> ?????
25086 this.clearSelections();
25087 this.el.update("");
25089 var records = this.store.getRange();
25090 if(records.length < 1) {
25092 // is this valid?? = should it render a template??
25094 this.el.update(this.emptyText);
25098 if (this.dataName) {
25099 this.el.update(t.apply(this.store.meta)); //????
25100 el = this.el.child('.roo-tpl-' + this.dataName);
25103 for(var i = 0, len = records.length; i < len; i++){
25104 var data = this.prepareData(records[i].data, i, records[i]);
25105 this.fireEvent("preparedata", this, data, i, records[i]);
25107 var d = Roo.apply({}, data);
25110 Roo.apply(d, {'roo-id' : Roo.id()});
25114 Roo.each(this.parent.item, function(item){
25115 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
25118 Roo.apply(d, {'roo-data-checked' : 'checked'});
25122 html[html.length] = Roo.util.Format.trim(
25124 t.applySubtemplate(this.dataName, d, this.store.meta) :
25131 el.update(html.join(""));
25132 this.nodes = el.dom.childNodes;
25133 this.updateIndexes(0);
25138 * Function to override to reformat the data that is sent to
25139 * the template for each node.
25140 * DEPRICATED - use the preparedata event handler.
25141 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
25142 * a JSON object for an UpdateManager bound view).
25144 prepareData : function(data, index, record)
25146 this.fireEvent("preparedata", this, data, index, record);
25150 onUpdate : function(ds, record){
25151 // Roo.log('on update');
25152 this.clearSelections();
25153 var index = this.store.indexOf(record);
25154 var n = this.nodes[index];
25155 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
25156 n.parentNode.removeChild(n);
25157 this.updateIndexes(index, index);
25163 onAdd : function(ds, records, index)
25165 //Roo.log(['on Add', ds, records, index] );
25166 this.clearSelections();
25167 if(this.nodes.length == 0){
25171 var n = this.nodes[index];
25172 for(var i = 0, len = records.length; i < len; i++){
25173 var d = this.prepareData(records[i].data, i, records[i]);
25175 this.tpl.insertBefore(n, d);
25178 this.tpl.append(this.el, d);
25181 this.updateIndexes(index);
25184 onRemove : function(ds, record, index){
25185 // Roo.log('onRemove');
25186 this.clearSelections();
25187 var el = this.dataName ?
25188 this.el.child('.roo-tpl-' + this.dataName) :
25191 el.dom.removeChild(this.nodes[index]);
25192 this.updateIndexes(index);
25196 * Refresh an individual node.
25197 * @param {Number} index
25199 refreshNode : function(index){
25200 this.onUpdate(this.store, this.store.getAt(index));
25203 updateIndexes : function(startIndex, endIndex){
25204 var ns = this.nodes;
25205 startIndex = startIndex || 0;
25206 endIndex = endIndex || ns.length - 1;
25207 for(var i = startIndex; i <= endIndex; i++){
25208 ns[i].nodeIndex = i;
25213 * Changes the data store this view uses and refresh the view.
25214 * @param {Store} store
25216 setStore : function(store, initial){
25217 if(!initial && this.store){
25218 this.store.un("datachanged", this.refresh);
25219 this.store.un("add", this.onAdd);
25220 this.store.un("remove", this.onRemove);
25221 this.store.un("update", this.onUpdate);
25222 this.store.un("clear", this.refresh);
25223 this.store.un("beforeload", this.onBeforeLoad);
25224 this.store.un("load", this.onLoad);
25225 this.store.un("loadexception", this.onLoad);
25229 store.on("datachanged", this.refresh, this);
25230 store.on("add", this.onAdd, this);
25231 store.on("remove", this.onRemove, this);
25232 store.on("update", this.onUpdate, this);
25233 store.on("clear", this.refresh, this);
25234 store.on("beforeload", this.onBeforeLoad, this);
25235 store.on("load", this.onLoad, this);
25236 store.on("loadexception", this.onLoad, this);
25244 * onbeforeLoad - masks the loading area.
25247 onBeforeLoad : function(store,opts)
25249 //Roo.log('onBeforeLoad');
25251 this.el.update("");
25253 this.el.mask(this.mask ? this.mask : "Loading" );
25255 onLoad : function ()
25262 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
25263 * @param {HTMLElement} node
25264 * @return {HTMLElement} The template node
25266 findItemFromChild : function(node){
25267 var el = this.dataName ?
25268 this.el.child('.roo-tpl-' + this.dataName,true) :
25271 if(!node || node.parentNode == el){
25274 var p = node.parentNode;
25275 while(p && p != el){
25276 if(p.parentNode == el){
25285 onClick : function(e){
25286 var item = this.findItemFromChild(e.getTarget());
25288 var index = this.indexOf(item);
25289 if(this.onItemClick(item, index, e) !== false){
25290 this.fireEvent("click", this, index, item, e);
25293 this.clearSelections();
25298 onContextMenu : function(e){
25299 var item = this.findItemFromChild(e.getTarget());
25301 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
25306 onDblClick : function(e){
25307 var item = this.findItemFromChild(e.getTarget());
25309 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
25313 onItemClick : function(item, index, e)
25315 if(this.fireEvent("beforeclick", this, index, item, e) === false){
25318 if (this.toggleSelect) {
25319 var m = this.isSelected(item) ? 'unselect' : 'select';
25322 _t[m](item, true, false);
25325 if(this.multiSelect || this.singleSelect){
25326 if(this.multiSelect && e.shiftKey && this.lastSelection){
25327 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
25329 this.select(item, this.multiSelect && e.ctrlKey);
25330 this.lastSelection = item;
25333 if(!this.tickable){
25334 e.preventDefault();
25342 * Get the number of selected nodes.
25345 getSelectionCount : function(){
25346 return this.selections.length;
25350 * Get the currently selected nodes.
25351 * @return {Array} An array of HTMLElements
25353 getSelectedNodes : function(){
25354 return this.selections;
25358 * Get the indexes of the selected nodes.
25361 getSelectedIndexes : function(){
25362 var indexes = [], s = this.selections;
25363 for(var i = 0, len = s.length; i < len; i++){
25364 indexes.push(s[i].nodeIndex);
25370 * Clear all selections
25371 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
25373 clearSelections : function(suppressEvent){
25374 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
25375 this.cmp.elements = this.selections;
25376 this.cmp.removeClass(this.selectedClass);
25377 this.selections = [];
25378 if(!suppressEvent){
25379 this.fireEvent("selectionchange", this, this.selections);
25385 * Returns true if the passed node is selected
25386 * @param {HTMLElement/Number} node The node or node index
25387 * @return {Boolean}
25389 isSelected : function(node){
25390 var s = this.selections;
25394 node = this.getNode(node);
25395 return s.indexOf(node) !== -1;
25400 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
25401 * @param {Boolean} keepExisting (optional) true to keep existing selections
25402 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25404 select : function(nodeInfo, keepExisting, suppressEvent){
25405 if(nodeInfo instanceof Array){
25407 this.clearSelections(true);
25409 for(var i = 0, len = nodeInfo.length; i < len; i++){
25410 this.select(nodeInfo[i], true, true);
25414 var node = this.getNode(nodeInfo);
25415 if(!node || this.isSelected(node)){
25416 return; // already selected.
25419 this.clearSelections(true);
25422 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
25423 Roo.fly(node).addClass(this.selectedClass);
25424 this.selections.push(node);
25425 if(!suppressEvent){
25426 this.fireEvent("selectionchange", this, this.selections);
25434 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
25435 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
25436 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
25438 unselect : function(nodeInfo, keepExisting, suppressEvent)
25440 if(nodeInfo instanceof Array){
25441 Roo.each(this.selections, function(s) {
25442 this.unselect(s, nodeInfo);
25446 var node = this.getNode(nodeInfo);
25447 if(!node || !this.isSelected(node)){
25448 //Roo.log("not selected");
25449 return; // not selected.
25453 Roo.each(this.selections, function(s) {
25455 Roo.fly(node).removeClass(this.selectedClass);
25462 this.selections= ns;
25463 this.fireEvent("selectionchange", this, this.selections);
25467 * Gets a template node.
25468 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25469 * @return {HTMLElement} The node or null if it wasn't found
25471 getNode : function(nodeInfo){
25472 if(typeof nodeInfo == "string"){
25473 return document.getElementById(nodeInfo);
25474 }else if(typeof nodeInfo == "number"){
25475 return this.nodes[nodeInfo];
25481 * Gets a range template nodes.
25482 * @param {Number} startIndex
25483 * @param {Number} endIndex
25484 * @return {Array} An array of nodes
25486 getNodes : function(start, end){
25487 var ns = this.nodes;
25488 start = start || 0;
25489 end = typeof end == "undefined" ? ns.length - 1 : end;
25492 for(var i = start; i <= end; i++){
25496 for(var i = start; i >= end; i--){
25504 * Finds the index of the passed node
25505 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
25506 * @return {Number} The index of the node or -1
25508 indexOf : function(node){
25509 node = this.getNode(node);
25510 if(typeof node.nodeIndex == "number"){
25511 return node.nodeIndex;
25513 var ns = this.nodes;
25514 for(var i = 0, len = ns.length; i < len; i++){
25524 * Ext JS Library 1.1.1
25525 * Copyright(c) 2006-2007, Ext JS, LLC.
25527 * Originally Released Under LGPL - original licence link has changed is not relivant.
25530 * <script type="text/javascript">
25534 * @class Roo.JsonView
25535 * @extends Roo.View
25536 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
25538 var view = new Roo.JsonView({
25539 container: "my-element",
25540 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
25545 // listen for node click?
25546 view.on("click", function(vw, index, node, e){
25547 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
25550 // direct load of JSON data
25551 view.load("foobar.php");
25553 // Example from my blog list
25554 var tpl = new Roo.Template(
25555 '<div class="entry">' +
25556 '<a class="entry-title" href="{link}">{title}</a>' +
25557 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
25558 "</div><hr />"
25561 var moreView = new Roo.JsonView({
25562 container : "entry-list",
25566 moreView.on("beforerender", this.sortEntries, this);
25568 url: "/blog/get-posts.php",
25569 params: "allposts=true",
25570 text: "Loading Blog Entries..."
25574 * Note: old code is supported with arguments : (container, template, config)
25578 * Create a new JsonView
25580 * @param {Object} config The config object
25583 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
25586 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
25588 var um = this.el.getUpdateManager();
25589 um.setRenderer(this);
25590 um.on("update", this.onLoad, this);
25591 um.on("failure", this.onLoadException, this);
25594 * @event beforerender
25595 * Fires before rendering of the downloaded JSON data.
25596 * @param {Roo.JsonView} this
25597 * @param {Object} data The JSON data loaded
25601 * Fires when data is loaded.
25602 * @param {Roo.JsonView} this
25603 * @param {Object} data The JSON data loaded
25604 * @param {Object} response The raw Connect response object
25607 * @event loadexception
25608 * Fires when loading fails.
25609 * @param {Roo.JsonView} this
25610 * @param {Object} response The raw Connect response object
25613 'beforerender' : true,
25615 'loadexception' : true
25618 Roo.extend(Roo.JsonView, Roo.View, {
25620 * @type {String} The root property in the loaded JSON object that contains the data
25625 * Refreshes the view.
25627 refresh : function(){
25628 this.clearSelections();
25629 this.el.update("");
25631 var o = this.jsonData;
25632 if(o && o.length > 0){
25633 for(var i = 0, len = o.length; i < len; i++){
25634 var data = this.prepareData(o[i], i, o);
25635 html[html.length] = this.tpl.apply(data);
25638 html.push(this.emptyText);
25640 this.el.update(html.join(""));
25641 this.nodes = this.el.dom.childNodes;
25642 this.updateIndexes(0);
25646 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
25647 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
25650 url: "your-url.php",
25651 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
25652 callback: yourFunction,
25653 scope: yourObject, //(optional scope)
25656 text: "Loading...",
25661 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
25662 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
25663 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
25664 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
25665 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
25668 var um = this.el.getUpdateManager();
25669 um.update.apply(um, arguments);
25672 render : function(el, response){
25673 this.clearSelections();
25674 this.el.update("");
25677 o = Roo.util.JSON.decode(response.responseText);
25680 o = o[this.jsonRoot];
25685 * The current JSON data or null
25688 this.beforeRender();
25693 * Get the number of records in the current JSON dataset
25696 getCount : function(){
25697 return this.jsonData ? this.jsonData.length : 0;
25701 * Returns the JSON object for the specified node(s)
25702 * @param {HTMLElement/Array} node The node or an array of nodes
25703 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
25704 * you get the JSON object for the node
25706 getNodeData : function(node){
25707 if(node instanceof Array){
25709 for(var i = 0, len = node.length; i < len; i++){
25710 data.push(this.getNodeData(node[i]));
25714 return this.jsonData[this.indexOf(node)] || null;
25717 beforeRender : function(){
25718 this.snapshot = this.jsonData;
25720 this.sort.apply(this, this.sortInfo);
25722 this.fireEvent("beforerender", this, this.jsonData);
25725 onLoad : function(el, o){
25726 this.fireEvent("load", this, this.jsonData, o);
25729 onLoadException : function(el, o){
25730 this.fireEvent("loadexception", this, o);
25734 * Filter the data by a specific property.
25735 * @param {String} property A property on your JSON objects
25736 * @param {String/RegExp} value Either string that the property values
25737 * should start with, or a RegExp to test against the property
25739 filter : function(property, value){
25742 var ss = this.snapshot;
25743 if(typeof value == "string"){
25744 var vlen = value.length;
25746 this.clearFilter();
25749 value = value.toLowerCase();
25750 for(var i = 0, len = ss.length; i < len; i++){
25752 if(o[property].substr(0, vlen).toLowerCase() == value){
25756 } else if(value.exec){ // regex?
25757 for(var i = 0, len = ss.length; i < len; i++){
25759 if(value.test(o[property])){
25766 this.jsonData = data;
25772 * Filter by a function. The passed function will be called with each
25773 * object in the current dataset. If the function returns true the value is kept,
25774 * otherwise it is filtered.
25775 * @param {Function} fn
25776 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
25778 filterBy : function(fn, scope){
25781 var ss = this.snapshot;
25782 for(var i = 0, len = ss.length; i < len; i++){
25784 if(fn.call(scope || this, o)){
25788 this.jsonData = data;
25794 * Clears the current filter.
25796 clearFilter : function(){
25797 if(this.snapshot && this.jsonData != this.snapshot){
25798 this.jsonData = this.snapshot;
25805 * Sorts the data for this view and refreshes it.
25806 * @param {String} property A property on your JSON objects to sort on
25807 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
25808 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
25810 sort : function(property, dir, sortType){
25811 this.sortInfo = Array.prototype.slice.call(arguments, 0);
25814 var dsc = dir && dir.toLowerCase() == "desc";
25815 var f = function(o1, o2){
25816 var v1 = sortType ? sortType(o1[p]) : o1[p];
25817 var v2 = sortType ? sortType(o2[p]) : o2[p];
25820 return dsc ? +1 : -1;
25821 } else if(v1 > v2){
25822 return dsc ? -1 : +1;
25827 this.jsonData.sort(f);
25829 if(this.jsonData != this.snapshot){
25830 this.snapshot.sort(f);
25836 * Ext JS Library 1.1.1
25837 * Copyright(c) 2006-2007, Ext JS, LLC.
25839 * Originally Released Under LGPL - original licence link has changed is not relivant.
25842 * <script type="text/javascript">
25847 * @class Roo.ColorPalette
25848 * @extends Roo.Component
25849 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
25850 * Here's an example of typical usage:
25852 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
25853 cp.render('my-div');
25855 cp.on('select', function(palette, selColor){
25856 // do something with selColor
25860 * Create a new ColorPalette
25861 * @param {Object} config The config object
25863 Roo.ColorPalette = function(config){
25864 Roo.ColorPalette.superclass.constructor.call(this, config);
25868 * Fires when a color is selected
25869 * @param {ColorPalette} this
25870 * @param {String} color The 6-digit color hex code (without the # symbol)
25876 this.on("select", this.handler, this.scope, true);
25879 Roo.extend(Roo.ColorPalette, Roo.Component, {
25881 * @cfg {String} itemCls
25882 * The CSS class to apply to the containing element (defaults to "x-color-palette")
25884 itemCls : "x-color-palette",
25886 * @cfg {String} value
25887 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
25888 * the hex codes are case-sensitive.
25891 clickEvent:'click',
25893 ctype: "Roo.ColorPalette",
25896 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
25898 allowReselect : false,
25901 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
25902 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
25903 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
25904 * of colors with the width setting until the box is symmetrical.</p>
25905 * <p>You can override individual colors if needed:</p>
25907 var cp = new Roo.ColorPalette();
25908 cp.colors[0] = "FF0000"; // change the first box to red
25911 Or you can provide a custom array of your own for complete control:
25913 var cp = new Roo.ColorPalette();
25914 cp.colors = ["000000", "993300", "333300"];
25919 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
25920 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
25921 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
25922 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
25923 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
25927 onRender : function(container, position){
25928 var t = new Roo.MasterTemplate(
25929 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
25931 var c = this.colors;
25932 for(var i = 0, len = c.length; i < len; i++){
25935 var el = document.createElement("div");
25936 el.className = this.itemCls;
25938 container.dom.insertBefore(el, position);
25939 this.el = Roo.get(el);
25940 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
25941 if(this.clickEvent != 'click'){
25942 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
25947 afterRender : function(){
25948 Roo.ColorPalette.superclass.afterRender.call(this);
25950 var s = this.value;
25957 handleClick : function(e, t){
25958 e.preventDefault();
25959 if(!this.disabled){
25960 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
25961 this.select(c.toUpperCase());
25966 * Selects the specified color in the palette (fires the select event)
25967 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
25969 select : function(color){
25970 color = color.replace("#", "");
25971 if(color != this.value || this.allowReselect){
25974 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
25976 el.child("a.color-"+color).addClass("x-color-palette-sel");
25977 this.value = color;
25978 this.fireEvent("select", this, color);
25983 * Ext JS Library 1.1.1
25984 * Copyright(c) 2006-2007, Ext JS, LLC.
25986 * Originally Released Under LGPL - original licence link has changed is not relivant.
25989 * <script type="text/javascript">
25993 * @class Roo.DatePicker
25994 * @extends Roo.Component
25995 * Simple date picker class.
25997 * Create a new DatePicker
25998 * @param {Object} config The config object
26000 Roo.DatePicker = function(config){
26001 Roo.DatePicker.superclass.constructor.call(this, config);
26003 this.value = config && config.value ?
26004 config.value.clearTime() : new Date().clearTime();
26009 * Fires when a date is selected
26010 * @param {DatePicker} this
26011 * @param {Date} date The selected date
26015 * @event monthchange
26016 * Fires when the displayed month changes
26017 * @param {DatePicker} this
26018 * @param {Date} date The selected month
26020 'monthchange': true
26024 this.on("select", this.handler, this.scope || this);
26026 // build the disabledDatesRE
26027 if(!this.disabledDatesRE && this.disabledDates){
26028 var dd = this.disabledDates;
26030 for(var i = 0; i < dd.length; i++){
26032 if(i != dd.length-1) re += "|";
26034 this.disabledDatesRE = new RegExp(re + ")");
26038 Roo.extend(Roo.DatePicker, Roo.Component, {
26040 * @cfg {String} todayText
26041 * The text to display on the button that selects the current date (defaults to "Today")
26043 todayText : "Today",
26045 * @cfg {String} okText
26046 * The text to display on the ok button
26048 okText : " OK ", //   to give the user extra clicking room
26050 * @cfg {String} cancelText
26051 * The text to display on the cancel button
26053 cancelText : "Cancel",
26055 * @cfg {String} todayTip
26056 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
26058 todayTip : "{0} (Spacebar)",
26060 * @cfg {Date} minDate
26061 * Minimum allowable date (JavaScript date object, defaults to null)
26065 * @cfg {Date} maxDate
26066 * Maximum allowable date (JavaScript date object, defaults to null)
26070 * @cfg {String} minText
26071 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
26073 minText : "This date is before the minimum date",
26075 * @cfg {String} maxText
26076 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
26078 maxText : "This date is after the maximum date",
26080 * @cfg {String} format
26081 * The default date format string which can be overriden for localization support. The format must be
26082 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
26086 * @cfg {Array} disabledDays
26087 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
26089 disabledDays : null,
26091 * @cfg {String} disabledDaysText
26092 * The tooltip to display when the date falls on a disabled day (defaults to "")
26094 disabledDaysText : "",
26096 * @cfg {RegExp} disabledDatesRE
26097 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
26099 disabledDatesRE : null,
26101 * @cfg {String} disabledDatesText
26102 * The tooltip text to display when the date falls on a disabled date (defaults to "")
26104 disabledDatesText : "",
26106 * @cfg {Boolean} constrainToViewport
26107 * True to constrain the date picker to the viewport (defaults to true)
26109 constrainToViewport : true,
26111 * @cfg {Array} monthNames
26112 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
26114 monthNames : Date.monthNames,
26116 * @cfg {Array} dayNames
26117 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
26119 dayNames : Date.dayNames,
26121 * @cfg {String} nextText
26122 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
26124 nextText: 'Next Month (Control+Right)',
26126 * @cfg {String} prevText
26127 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
26129 prevText: 'Previous Month (Control+Left)',
26131 * @cfg {String} monthYearText
26132 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
26134 monthYearText: 'Choose a month (Control+Up/Down to move years)',
26136 * @cfg {Number} startDay
26137 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
26141 * @cfg {Bool} showClear
26142 * Show a clear button (usefull for date form elements that can be blank.)
26148 * Sets the value of the date field
26149 * @param {Date} value The date to set
26151 setValue : function(value){
26152 var old = this.value;
26154 if (typeof(value) == 'string') {
26156 value = Date.parseDate(value, this.format);
26159 value = new Date();
26162 this.value = value.clearTime(true);
26164 this.update(this.value);
26169 * Gets the current selected value of the date field
26170 * @return {Date} The selected date
26172 getValue : function(){
26177 focus : function(){
26179 this.update(this.activeDate);
26184 onRender : function(container, position){
26187 '<table cellspacing="0">',
26188 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
26189 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
26190 var dn = this.dayNames;
26191 for(var i = 0; i < 7; i++){
26192 var d = this.startDay+i;
26196 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
26198 m[m.length] = "</tr></thead><tbody><tr>";
26199 for(var i = 0; i < 42; i++) {
26200 if(i % 7 == 0 && i != 0){
26201 m[m.length] = "</tr><tr>";
26203 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
26205 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
26206 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
26208 var el = document.createElement("div");
26209 el.className = "x-date-picker";
26210 el.innerHTML = m.join("");
26212 container.dom.insertBefore(el, position);
26214 this.el = Roo.get(el);
26215 this.eventEl = Roo.get(el.firstChild);
26217 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
26218 handler: this.showPrevMonth,
26220 preventDefault:true,
26224 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
26225 handler: this.showNextMonth,
26227 preventDefault:true,
26231 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
26233 this.monthPicker = this.el.down('div.x-date-mp');
26234 this.monthPicker.enableDisplayMode('block');
26236 var kn = new Roo.KeyNav(this.eventEl, {
26237 "left" : function(e){
26239 this.showPrevMonth() :
26240 this.update(this.activeDate.add("d", -1));
26243 "right" : function(e){
26245 this.showNextMonth() :
26246 this.update(this.activeDate.add("d", 1));
26249 "up" : function(e){
26251 this.showNextYear() :
26252 this.update(this.activeDate.add("d", -7));
26255 "down" : function(e){
26257 this.showPrevYear() :
26258 this.update(this.activeDate.add("d", 7));
26261 "pageUp" : function(e){
26262 this.showNextMonth();
26265 "pageDown" : function(e){
26266 this.showPrevMonth();
26269 "enter" : function(e){
26270 e.stopPropagation();
26277 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
26279 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
26281 this.el.unselectable();
26283 this.cells = this.el.select("table.x-date-inner tbody td");
26284 this.textNodes = this.el.query("table.x-date-inner tbody span");
26286 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
26288 tooltip: this.monthYearText
26291 this.mbtn.on('click', this.showMonthPicker, this);
26292 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
26295 var today = (new Date()).dateFormat(this.format);
26297 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
26298 if (this.showClear) {
26299 baseTb.add( new Roo.Toolbar.Fill());
26302 text: String.format(this.todayText, today),
26303 tooltip: String.format(this.todayTip, today),
26304 handler: this.selectToday,
26308 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
26311 if (this.showClear) {
26313 baseTb.add( new Roo.Toolbar.Fill());
26316 cls: 'x-btn-icon x-btn-clear',
26317 handler: function() {
26319 this.fireEvent("select", this, '');
26329 this.update(this.value);
26332 createMonthPicker : function(){
26333 if(!this.monthPicker.dom.firstChild){
26334 var buf = ['<table border="0" cellspacing="0">'];
26335 for(var i = 0; i < 6; i++){
26337 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
26338 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
26340 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
26341 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
26345 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
26347 '</button><button type="button" class="x-date-mp-cancel">',
26349 '</button></td></tr>',
26352 this.monthPicker.update(buf.join(''));
26353 this.monthPicker.on('click', this.onMonthClick, this);
26354 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
26356 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
26357 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
26359 this.mpMonths.each(function(m, a, i){
26362 m.dom.xmonth = 5 + Math.round(i * .5);
26364 m.dom.xmonth = Math.round((i-1) * .5);
26370 showMonthPicker : function(){
26371 this.createMonthPicker();
26372 var size = this.el.getSize();
26373 this.monthPicker.setSize(size);
26374 this.monthPicker.child('table').setSize(size);
26376 this.mpSelMonth = (this.activeDate || this.value).getMonth();
26377 this.updateMPMonth(this.mpSelMonth);
26378 this.mpSelYear = (this.activeDate || this.value).getFullYear();
26379 this.updateMPYear(this.mpSelYear);
26381 this.monthPicker.slideIn('t', {duration:.2});
26384 updateMPYear : function(y){
26386 var ys = this.mpYears.elements;
26387 for(var i = 1; i <= 10; i++){
26388 var td = ys[i-1], y2;
26390 y2 = y + Math.round(i * .5);
26391 td.firstChild.innerHTML = y2;
26394 y2 = y - (5-Math.round(i * .5));
26395 td.firstChild.innerHTML = y2;
26398 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
26402 updateMPMonth : function(sm){
26403 this.mpMonths.each(function(m, a, i){
26404 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
26408 selectMPMonth: function(m){
26412 onMonthClick : function(e, t){
26414 var el = new Roo.Element(t), pn;
26415 if(el.is('button.x-date-mp-cancel')){
26416 this.hideMonthPicker();
26418 else if(el.is('button.x-date-mp-ok')){
26419 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26420 this.hideMonthPicker();
26422 else if(pn = el.up('td.x-date-mp-month', 2)){
26423 this.mpMonths.removeClass('x-date-mp-sel');
26424 pn.addClass('x-date-mp-sel');
26425 this.mpSelMonth = pn.dom.xmonth;
26427 else if(pn = el.up('td.x-date-mp-year', 2)){
26428 this.mpYears.removeClass('x-date-mp-sel');
26429 pn.addClass('x-date-mp-sel');
26430 this.mpSelYear = pn.dom.xyear;
26432 else if(el.is('a.x-date-mp-prev')){
26433 this.updateMPYear(this.mpyear-10);
26435 else if(el.is('a.x-date-mp-next')){
26436 this.updateMPYear(this.mpyear+10);
26440 onMonthDblClick : function(e, t){
26442 var el = new Roo.Element(t), pn;
26443 if(pn = el.up('td.x-date-mp-month', 2)){
26444 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
26445 this.hideMonthPicker();
26447 else if(pn = el.up('td.x-date-mp-year', 2)){
26448 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
26449 this.hideMonthPicker();
26453 hideMonthPicker : function(disableAnim){
26454 if(this.monthPicker){
26455 if(disableAnim === true){
26456 this.monthPicker.hide();
26458 this.monthPicker.slideOut('t', {duration:.2});
26464 showPrevMonth : function(e){
26465 this.update(this.activeDate.add("mo", -1));
26469 showNextMonth : function(e){
26470 this.update(this.activeDate.add("mo", 1));
26474 showPrevYear : function(){
26475 this.update(this.activeDate.add("y", -1));
26479 showNextYear : function(){
26480 this.update(this.activeDate.add("y", 1));
26484 handleMouseWheel : function(e){
26485 var delta = e.getWheelDelta();
26487 this.showPrevMonth();
26489 } else if(delta < 0){
26490 this.showNextMonth();
26496 handleDateClick : function(e, t){
26498 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
26499 this.setValue(new Date(t.dateValue));
26500 this.fireEvent("select", this, this.value);
26505 selectToday : function(){
26506 this.setValue(new Date().clearTime());
26507 this.fireEvent("select", this, this.value);
26511 update : function(date)
26513 var vd = this.activeDate;
26514 this.activeDate = date;
26516 var t = date.getTime();
26517 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
26518 this.cells.removeClass("x-date-selected");
26519 this.cells.each(function(c){
26520 if(c.dom.firstChild.dateValue == t){
26521 c.addClass("x-date-selected");
26522 setTimeout(function(){
26523 try{c.dom.firstChild.focus();}catch(e){}
26532 var days = date.getDaysInMonth();
26533 var firstOfMonth = date.getFirstDateOfMonth();
26534 var startingPos = firstOfMonth.getDay()-this.startDay;
26536 if(startingPos <= this.startDay){
26540 var pm = date.add("mo", -1);
26541 var prevStart = pm.getDaysInMonth()-startingPos;
26543 var cells = this.cells.elements;
26544 var textEls = this.textNodes;
26545 days += startingPos;
26547 // convert everything to numbers so it's fast
26548 var day = 86400000;
26549 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
26550 var today = new Date().clearTime().getTime();
26551 var sel = date.clearTime().getTime();
26552 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
26553 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
26554 var ddMatch = this.disabledDatesRE;
26555 var ddText = this.disabledDatesText;
26556 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
26557 var ddaysText = this.disabledDaysText;
26558 var format = this.format;
26560 var setCellClass = function(cal, cell){
26562 var t = d.getTime();
26563 cell.firstChild.dateValue = t;
26565 cell.className += " x-date-today";
26566 cell.title = cal.todayText;
26569 cell.className += " x-date-selected";
26570 setTimeout(function(){
26571 try{cell.firstChild.focus();}catch(e){}
26576 cell.className = " x-date-disabled";
26577 cell.title = cal.minText;
26581 cell.className = " x-date-disabled";
26582 cell.title = cal.maxText;
26586 if(ddays.indexOf(d.getDay()) != -1){
26587 cell.title = ddaysText;
26588 cell.className = " x-date-disabled";
26591 if(ddMatch && format){
26592 var fvalue = d.dateFormat(format);
26593 if(ddMatch.test(fvalue)){
26594 cell.title = ddText.replace("%0", fvalue);
26595 cell.className = " x-date-disabled";
26601 for(; i < startingPos; i++) {
26602 textEls[i].innerHTML = (++prevStart);
26603 d.setDate(d.getDate()+1);
26604 cells[i].className = "x-date-prevday";
26605 setCellClass(this, cells[i]);
26607 for(; i < days; i++){
26608 intDay = i - startingPos + 1;
26609 textEls[i].innerHTML = (intDay);
26610 d.setDate(d.getDate()+1);
26611 cells[i].className = "x-date-active";
26612 setCellClass(this, cells[i]);
26615 for(; i < 42; i++) {
26616 textEls[i].innerHTML = (++extraDays);
26617 d.setDate(d.getDate()+1);
26618 cells[i].className = "x-date-nextday";
26619 setCellClass(this, cells[i]);
26622 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
26623 this.fireEvent('monthchange', this, date);
26625 if(!this.internalRender){
26626 var main = this.el.dom.firstChild;
26627 var w = main.offsetWidth;
26628 this.el.setWidth(w + this.el.getBorderWidth("lr"));
26629 Roo.fly(main).setWidth(w);
26630 this.internalRender = true;
26631 // opera does not respect the auto grow header center column
26632 // then, after it gets a width opera refuses to recalculate
26633 // without a second pass
26634 if(Roo.isOpera && !this.secondPass){
26635 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
26636 this.secondPass = true;
26637 this.update.defer(10, this, [date]);
26645 * Ext JS Library 1.1.1
26646 * Copyright(c) 2006-2007, Ext JS, LLC.
26648 * Originally Released Under LGPL - original licence link has changed is not relivant.
26651 * <script type="text/javascript">
26654 * @class Roo.TabPanel
26655 * @extends Roo.util.Observable
26656 * A lightweight tab container.
26660 // basic tabs 1, built from existing content
26661 var tabs = new Roo.TabPanel("tabs1");
26662 tabs.addTab("script", "View Script");
26663 tabs.addTab("markup", "View Markup");
26664 tabs.activate("script");
26666 // more advanced tabs, built from javascript
26667 var jtabs = new Roo.TabPanel("jtabs");
26668 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
26670 // set up the UpdateManager
26671 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
26672 var updater = tab2.getUpdateManager();
26673 updater.setDefaultUrl("ajax1.htm");
26674 tab2.on('activate', updater.refresh, updater, true);
26676 // Use setUrl for Ajax loading
26677 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
26678 tab3.setUrl("ajax2.htm", null, true);
26681 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
26684 jtabs.activate("jtabs-1");
26687 * Create a new TabPanel.
26688 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
26689 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
26691 Roo.TabPanel = function(container, config){
26693 * The container element for this TabPanel.
26694 * @type Roo.Element
26696 this.el = Roo.get(container, true);
26698 if(typeof config == "boolean"){
26699 this.tabPosition = config ? "bottom" : "top";
26701 Roo.apply(this, config);
26704 if(this.tabPosition == "bottom"){
26705 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26706 this.el.addClass("x-tabs-bottom");
26708 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
26709 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
26710 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
26712 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
26714 if(this.tabPosition != "bottom"){
26715 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
26716 * @type Roo.Element
26718 this.bodyEl = Roo.get(this.createBody(this.el.dom));
26719 this.el.addClass("x-tabs-top");
26723 this.bodyEl.setStyle("position", "relative");
26725 this.active = null;
26726 this.activateDelegate = this.activate.createDelegate(this);
26731 * Fires when the active tab changes
26732 * @param {Roo.TabPanel} this
26733 * @param {Roo.TabPanelItem} activePanel The new active tab
26737 * @event beforetabchange
26738 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
26739 * @param {Roo.TabPanel} this
26740 * @param {Object} e Set cancel to true on this object to cancel the tab change
26741 * @param {Roo.TabPanelItem} tab The tab being changed to
26743 "beforetabchange" : true
26746 Roo.EventManager.onWindowResize(this.onResize, this);
26747 this.cpad = this.el.getPadding("lr");
26748 this.hiddenCount = 0;
26751 // toolbar on the tabbar support...
26752 if (this.toolbar) {
26753 var tcfg = this.toolbar;
26754 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
26755 this.toolbar = new Roo.Toolbar(tcfg);
26756 if (Roo.isSafari) {
26757 var tbl = tcfg.container.child('table', true);
26758 tbl.setAttribute('width', '100%');
26765 Roo.TabPanel.superclass.constructor.call(this);
26768 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
26770 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
26772 tabPosition : "top",
26774 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
26776 currentTabWidth : 0,
26778 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
26782 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
26786 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
26788 preferredTabWidth : 175,
26790 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
26792 resizeTabs : false,
26794 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
26796 monitorResize : true,
26798 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
26803 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
26804 * @param {String} id The id of the div to use <b>or create</b>
26805 * @param {String} text The text for the tab
26806 * @param {String} content (optional) Content to put in the TabPanelItem body
26807 * @param {Boolean} closable (optional) True to create a close icon on the tab
26808 * @return {Roo.TabPanelItem} The created TabPanelItem
26810 addTab : function(id, text, content, closable){
26811 var item = new Roo.TabPanelItem(this, id, text, closable);
26812 this.addTabItem(item);
26814 item.setContent(content);
26820 * Returns the {@link Roo.TabPanelItem} with the specified id/index
26821 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
26822 * @return {Roo.TabPanelItem}
26824 getTab : function(id){
26825 return this.items[id];
26829 * Hides the {@link Roo.TabPanelItem} with the specified id/index
26830 * @param {String/Number} id The id or index of the TabPanelItem to hide.
26832 hideTab : function(id){
26833 var t = this.items[id];
26836 this.hiddenCount++;
26837 this.autoSizeTabs();
26842 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
26843 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
26845 unhideTab : function(id){
26846 var t = this.items[id];
26848 t.setHidden(false);
26849 this.hiddenCount--;
26850 this.autoSizeTabs();
26855 * Adds an existing {@link Roo.TabPanelItem}.
26856 * @param {Roo.TabPanelItem} item The TabPanelItem to add
26858 addTabItem : function(item){
26859 this.items[item.id] = item;
26860 this.items.push(item);
26861 if(this.resizeTabs){
26862 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
26863 this.autoSizeTabs();
26870 * Removes a {@link Roo.TabPanelItem}.
26871 * @param {String/Number} id The id or index of the TabPanelItem to remove.
26873 removeTab : function(id){
26874 var items = this.items;
26875 var tab = items[id];
26876 if(!tab) { return; }
26877 var index = items.indexOf(tab);
26878 if(this.active == tab && items.length > 1){
26879 var newTab = this.getNextAvailable(index);
26884 this.stripEl.dom.removeChild(tab.pnode.dom);
26885 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
26886 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
26888 items.splice(index, 1);
26889 delete this.items[tab.id];
26890 tab.fireEvent("close", tab);
26891 tab.purgeListeners();
26892 this.autoSizeTabs();
26895 getNextAvailable : function(start){
26896 var items = this.items;
26898 // look for a next tab that will slide over to
26899 // replace the one being removed
26900 while(index < items.length){
26901 var item = items[++index];
26902 if(item && !item.isHidden()){
26906 // if one isn't found select the previous tab (on the left)
26909 var item = items[--index];
26910 if(item && !item.isHidden()){
26918 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
26919 * @param {String/Number} id The id or index of the TabPanelItem to disable.
26921 disableTab : function(id){
26922 var tab = this.items[id];
26923 if(tab && this.active != tab){
26929 * Enables a {@link Roo.TabPanelItem} that is disabled.
26930 * @param {String/Number} id The id or index of the TabPanelItem to enable.
26932 enableTab : function(id){
26933 var tab = this.items[id];
26938 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
26939 * @param {String/Number} id The id or index of the TabPanelItem to activate.
26940 * @return {Roo.TabPanelItem} The TabPanelItem.
26942 activate : function(id){
26943 var tab = this.items[id];
26947 if(tab == this.active || tab.disabled){
26951 this.fireEvent("beforetabchange", this, e, tab);
26952 if(e.cancel !== true && !tab.disabled){
26954 this.active.hide();
26956 this.active = this.items[id];
26957 this.active.show();
26958 this.fireEvent("tabchange", this, this.active);
26964 * Gets the active {@link Roo.TabPanelItem}.
26965 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
26967 getActiveTab : function(){
26968 return this.active;
26972 * Updates the tab body element to fit the height of the container element
26973 * for overflow scrolling
26974 * @param {Number} targetHeight (optional) Override the starting height from the elements height
26976 syncHeight : function(targetHeight){
26977 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
26978 var bm = this.bodyEl.getMargins();
26979 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
26980 this.bodyEl.setHeight(newHeight);
26984 onResize : function(){
26985 if(this.monitorResize){
26986 this.autoSizeTabs();
26991 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
26993 beginUpdate : function(){
26994 this.updating = true;
26998 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
27000 endUpdate : function(){
27001 this.updating = false;
27002 this.autoSizeTabs();
27006 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
27008 autoSizeTabs : function(){
27009 var count = this.items.length;
27010 var vcount = count - this.hiddenCount;
27011 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
27012 var w = Math.max(this.el.getWidth() - this.cpad, 10);
27013 var availWidth = Math.floor(w / vcount);
27014 var b = this.stripBody;
27015 if(b.getWidth() > w){
27016 var tabs = this.items;
27017 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
27018 if(availWidth < this.minTabWidth){
27019 /*if(!this.sleft){ // incomplete scrolling code
27020 this.createScrollButtons();
27023 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
27026 if(this.currentTabWidth < this.preferredTabWidth){
27027 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
27033 * Returns the number of tabs in this TabPanel.
27036 getCount : function(){
27037 return this.items.length;
27041 * Resizes all the tabs to the passed width
27042 * @param {Number} The new width
27044 setTabWidth : function(width){
27045 this.currentTabWidth = width;
27046 for(var i = 0, len = this.items.length; i < len; i++) {
27047 if(!this.items[i].isHidden())this.items[i].setWidth(width);
27052 * Destroys this TabPanel
27053 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
27055 destroy : function(removeEl){
27056 Roo.EventManager.removeResizeListener(this.onResize, this);
27057 for(var i = 0, len = this.items.length; i < len; i++){
27058 this.items[i].purgeListeners();
27060 if(removeEl === true){
27061 this.el.update("");
27068 * @class Roo.TabPanelItem
27069 * @extends Roo.util.Observable
27070 * Represents an individual item (tab plus body) in a TabPanel.
27071 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
27072 * @param {String} id The id of this TabPanelItem
27073 * @param {String} text The text for the tab of this TabPanelItem
27074 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
27076 Roo.TabPanelItem = function(tabPanel, id, text, closable){
27078 * The {@link Roo.TabPanel} this TabPanelItem belongs to
27079 * @type Roo.TabPanel
27081 this.tabPanel = tabPanel;
27083 * The id for this TabPanelItem
27088 this.disabled = false;
27092 this.loaded = false;
27093 this.closable = closable;
27096 * The body element for this TabPanelItem.
27097 * @type Roo.Element
27099 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
27100 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
27101 this.bodyEl.setStyle("display", "block");
27102 this.bodyEl.setStyle("zoom", "1");
27105 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
27107 this.el = Roo.get(els.el, true);
27108 this.inner = Roo.get(els.inner, true);
27109 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
27110 this.pnode = Roo.get(els.el.parentNode, true);
27111 this.el.on("mousedown", this.onTabMouseDown, this);
27112 this.el.on("click", this.onTabClick, this);
27115 var c = Roo.get(els.close, true);
27116 c.dom.title = this.closeText;
27117 c.addClassOnOver("close-over");
27118 c.on("click", this.closeClick, this);
27124 * Fires when this tab becomes the active tab.
27125 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27126 * @param {Roo.TabPanelItem} this
27130 * @event beforeclose
27131 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
27132 * @param {Roo.TabPanelItem} this
27133 * @param {Object} e Set cancel to true on this object to cancel the close.
27135 "beforeclose": true,
27138 * Fires when this tab is closed.
27139 * @param {Roo.TabPanelItem} this
27143 * @event deactivate
27144 * Fires when this tab is no longer the active tab.
27145 * @param {Roo.TabPanel} tabPanel The parent TabPanel
27146 * @param {Roo.TabPanelItem} this
27148 "deactivate" : true
27150 this.hidden = false;
27152 Roo.TabPanelItem.superclass.constructor.call(this);
27155 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
27156 purgeListeners : function(){
27157 Roo.util.Observable.prototype.purgeListeners.call(this);
27158 this.el.removeAllListeners();
27161 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
27164 this.pnode.addClass("on");
27167 this.tabPanel.stripWrap.repaint();
27169 this.fireEvent("activate", this.tabPanel, this);
27173 * Returns true if this tab is the active tab.
27174 * @return {Boolean}
27176 isActive : function(){
27177 return this.tabPanel.getActiveTab() == this;
27181 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
27184 this.pnode.removeClass("on");
27186 this.fireEvent("deactivate", this.tabPanel, this);
27189 hideAction : function(){
27190 this.bodyEl.hide();
27191 this.bodyEl.setStyle("position", "absolute");
27192 this.bodyEl.setLeft("-20000px");
27193 this.bodyEl.setTop("-20000px");
27196 showAction : function(){
27197 this.bodyEl.setStyle("position", "relative");
27198 this.bodyEl.setTop("");
27199 this.bodyEl.setLeft("");
27200 this.bodyEl.show();
27204 * Set the tooltip for the tab.
27205 * @param {String} tooltip The tab's tooltip
27207 setTooltip : function(text){
27208 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
27209 this.textEl.dom.qtip = text;
27210 this.textEl.dom.removeAttribute('title');
27212 this.textEl.dom.title = text;
27216 onTabClick : function(e){
27217 e.preventDefault();
27218 this.tabPanel.activate(this.id);
27221 onTabMouseDown : function(e){
27222 e.preventDefault();
27223 this.tabPanel.activate(this.id);
27226 getWidth : function(){
27227 return this.inner.getWidth();
27230 setWidth : function(width){
27231 var iwidth = width - this.pnode.getPadding("lr");
27232 this.inner.setWidth(iwidth);
27233 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
27234 this.pnode.setWidth(width);
27238 * Show or hide the tab
27239 * @param {Boolean} hidden True to hide or false to show.
27241 setHidden : function(hidden){
27242 this.hidden = hidden;
27243 this.pnode.setStyle("display", hidden ? "none" : "");
27247 * Returns true if this tab is "hidden"
27248 * @return {Boolean}
27250 isHidden : function(){
27251 return this.hidden;
27255 * Returns the text for this tab
27258 getText : function(){
27262 autoSize : function(){
27263 //this.el.beginMeasure();
27264 this.textEl.setWidth(1);
27266 * #2804 [new] Tabs in Roojs
27267 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
27269 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
27270 //this.el.endMeasure();
27274 * Sets the text for the tab (Note: this also sets the tooltip text)
27275 * @param {String} text The tab's text and tooltip
27277 setText : function(text){
27279 this.textEl.update(text);
27280 this.setTooltip(text);
27281 if(!this.tabPanel.resizeTabs){
27286 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
27288 activate : function(){
27289 this.tabPanel.activate(this.id);
27293 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
27295 disable : function(){
27296 if(this.tabPanel.active != this){
27297 this.disabled = true;
27298 this.pnode.addClass("disabled");
27303 * Enables this TabPanelItem if it was previously disabled.
27305 enable : function(){
27306 this.disabled = false;
27307 this.pnode.removeClass("disabled");
27311 * Sets the content for this TabPanelItem.
27312 * @param {String} content The content
27313 * @param {Boolean} loadScripts true to look for and load scripts
27315 setContent : function(content, loadScripts){
27316 this.bodyEl.update(content, loadScripts);
27320 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
27321 * @return {Roo.UpdateManager} The UpdateManager
27323 getUpdateManager : function(){
27324 return this.bodyEl.getUpdateManager();
27328 * Set a URL to be used to load the content for this TabPanelItem.
27329 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
27330 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
27331 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
27332 * @return {Roo.UpdateManager} The UpdateManager
27334 setUrl : function(url, params, loadOnce){
27335 if(this.refreshDelegate){
27336 this.un('activate', this.refreshDelegate);
27338 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
27339 this.on("activate", this.refreshDelegate);
27340 return this.bodyEl.getUpdateManager();
27344 _handleRefresh : function(url, params, loadOnce){
27345 if(!loadOnce || !this.loaded){
27346 var updater = this.bodyEl.getUpdateManager();
27347 updater.update(url, params, this._setLoaded.createDelegate(this));
27352 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
27353 * Will fail silently if the setUrl method has not been called.
27354 * This does not activate the panel, just updates its content.
27356 refresh : function(){
27357 if(this.refreshDelegate){
27358 this.loaded = false;
27359 this.refreshDelegate();
27364 _setLoaded : function(){
27365 this.loaded = true;
27369 closeClick : function(e){
27372 this.fireEvent("beforeclose", this, o);
27373 if(o.cancel !== true){
27374 this.tabPanel.removeTab(this.id);
27378 * The text displayed in the tooltip for the close icon.
27381 closeText : "Close this tab"
27385 Roo.TabPanel.prototype.createStrip = function(container){
27386 var strip = document.createElement("div");
27387 strip.className = "x-tabs-wrap";
27388 container.appendChild(strip);
27392 Roo.TabPanel.prototype.createStripList = function(strip){
27393 // div wrapper for retard IE
27394 // returns the "tr" element.
27395 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
27396 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
27397 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
27398 return strip.firstChild.firstChild.firstChild.firstChild;
27401 Roo.TabPanel.prototype.createBody = function(container){
27402 var body = document.createElement("div");
27403 Roo.id(body, "tab-body");
27404 Roo.fly(body).addClass("x-tabs-body");
27405 container.appendChild(body);
27409 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
27410 var body = Roo.getDom(id);
27412 body = document.createElement("div");
27415 Roo.fly(body).addClass("x-tabs-item-body");
27416 bodyEl.insertBefore(body, bodyEl.firstChild);
27420 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
27421 var td = document.createElement("td");
27422 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
27423 //stripEl.appendChild(td);
27425 td.className = "x-tabs-closable";
27426 if(!this.closeTpl){
27427 this.closeTpl = new Roo.Template(
27428 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27429 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
27430 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
27433 var el = this.closeTpl.overwrite(td, {"text": text});
27434 var close = el.getElementsByTagName("div")[0];
27435 var inner = el.getElementsByTagName("em")[0];
27436 return {"el": el, "close": close, "inner": inner};
27439 this.tabTpl = new Roo.Template(
27440 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
27441 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
27444 var el = this.tabTpl.overwrite(td, {"text": text});
27445 var inner = el.getElementsByTagName("em")[0];
27446 return {"el": el, "inner": inner};
27450 * Ext JS Library 1.1.1
27451 * Copyright(c) 2006-2007, Ext JS, LLC.
27453 * Originally Released Under LGPL - original licence link has changed is not relivant.
27456 * <script type="text/javascript">
27460 * @class Roo.Button
27461 * @extends Roo.util.Observable
27462 * Simple Button class
27463 * @cfg {String} text The button text
27464 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
27465 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
27466 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
27467 * @cfg {Object} scope The scope of the handler
27468 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
27469 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
27470 * @cfg {Boolean} hidden True to start hidden (defaults to false)
27471 * @cfg {Boolean} disabled True to start disabled (defaults to false)
27472 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
27473 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
27474 applies if enableToggle = true)
27475 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
27476 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
27477 an {@link Roo.util.ClickRepeater} config object (defaults to false).
27479 * Create a new button
27480 * @param {Object} config The config object
27482 Roo.Button = function(renderTo, config)
27486 renderTo = config.renderTo || false;
27489 Roo.apply(this, config);
27493 * Fires when this button is clicked
27494 * @param {Button} this
27495 * @param {EventObject} e The click event
27500 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
27501 * @param {Button} this
27502 * @param {Boolean} pressed
27507 * Fires when the mouse hovers over the button
27508 * @param {Button} this
27509 * @param {Event} e The event object
27511 'mouseover' : true,
27514 * Fires when the mouse exits the button
27515 * @param {Button} this
27516 * @param {Event} e The event object
27521 * Fires when the button is rendered
27522 * @param {Button} this
27527 this.menu = Roo.menu.MenuMgr.get(this.menu);
27529 // register listeners first!! - so render can be captured..
27530 Roo.util.Observable.call(this);
27532 this.render(renderTo);
27538 Roo.extend(Roo.Button, Roo.util.Observable, {
27544 * Read-only. True if this button is hidden
27549 * Read-only. True if this button is disabled
27554 * Read-only. True if this button is pressed (only if enableToggle = true)
27560 * @cfg {Number} tabIndex
27561 * The DOM tabIndex for this button (defaults to undefined)
27563 tabIndex : undefined,
27566 * @cfg {Boolean} enableToggle
27567 * True to enable pressed/not pressed toggling (defaults to false)
27569 enableToggle: false,
27571 * @cfg {Mixed} menu
27572 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
27576 * @cfg {String} menuAlign
27577 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
27579 menuAlign : "tl-bl?",
27582 * @cfg {String} iconCls
27583 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
27585 iconCls : undefined,
27587 * @cfg {String} type
27588 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
27593 menuClassTarget: 'tr',
27596 * @cfg {String} clickEvent
27597 * The type of event to map to the button's event handler (defaults to 'click')
27599 clickEvent : 'click',
27602 * @cfg {Boolean} handleMouseEvents
27603 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
27605 handleMouseEvents : true,
27608 * @cfg {String} tooltipType
27609 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
27611 tooltipType : 'qtip',
27614 * @cfg {String} cls
27615 * A CSS class to apply to the button's main element.
27619 * @cfg {Roo.Template} template (Optional)
27620 * An {@link Roo.Template} with which to create the Button's main element. This Template must
27621 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
27622 * require code modifications if required elements (e.g. a button) aren't present.
27626 render : function(renderTo){
27628 if(this.hideParent){
27629 this.parentEl = Roo.get(renderTo);
27631 if(!this.dhconfig){
27632 if(!this.template){
27633 if(!Roo.Button.buttonTemplate){
27634 // hideous table template
27635 Roo.Button.buttonTemplate = new Roo.Template(
27636 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
27637 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
27638 "</tr></tbody></table>");
27640 this.template = Roo.Button.buttonTemplate;
27642 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
27643 var btnEl = btn.child("button:first");
27644 btnEl.on('focus', this.onFocus, this);
27645 btnEl.on('blur', this.onBlur, this);
27647 btn.addClass(this.cls);
27650 btnEl.setStyle('background-image', 'url(' +this.icon +')');
27653 btnEl.addClass(this.iconCls);
27655 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
27658 if(this.tabIndex !== undefined){
27659 btnEl.dom.tabIndex = this.tabIndex;
27662 if(typeof this.tooltip == 'object'){
27663 Roo.QuickTips.tips(Roo.apply({
27667 btnEl.dom[this.tooltipType] = this.tooltip;
27671 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
27675 this.el.dom.id = this.el.id = this.id;
27678 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
27679 this.menu.on("show", this.onMenuShow, this);
27680 this.menu.on("hide", this.onMenuHide, this);
27682 btn.addClass("x-btn");
27683 if(Roo.isIE && !Roo.isIE7){
27684 this.autoWidth.defer(1, this);
27688 if(this.handleMouseEvents){
27689 btn.on("mouseover", this.onMouseOver, this);
27690 btn.on("mouseout", this.onMouseOut, this);
27691 btn.on("mousedown", this.onMouseDown, this);
27693 btn.on(this.clickEvent, this.onClick, this);
27694 //btn.on("mouseup", this.onMouseUp, this);
27701 Roo.ButtonToggleMgr.register(this);
27703 this.el.addClass("x-btn-pressed");
27706 var repeater = new Roo.util.ClickRepeater(btn,
27707 typeof this.repeat == "object" ? this.repeat : {}
27709 repeater.on("click", this.onClick, this);
27712 this.fireEvent('render', this);
27716 * Returns the button's underlying element
27717 * @return {Roo.Element} The element
27719 getEl : function(){
27724 * Destroys this Button and removes any listeners.
27726 destroy : function(){
27727 Roo.ButtonToggleMgr.unregister(this);
27728 this.el.removeAllListeners();
27729 this.purgeListeners();
27734 autoWidth : function(){
27736 this.el.setWidth("auto");
27737 if(Roo.isIE7 && Roo.isStrict){
27738 var ib = this.el.child('button');
27739 if(ib && ib.getWidth() > 20){
27741 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
27746 this.el.beginMeasure();
27748 if(this.el.getWidth() < this.minWidth){
27749 this.el.setWidth(this.minWidth);
27752 this.el.endMeasure();
27759 * Assigns this button's click handler
27760 * @param {Function} handler The function to call when the button is clicked
27761 * @param {Object} scope (optional) Scope for the function passed in
27763 setHandler : function(handler, scope){
27764 this.handler = handler;
27765 this.scope = scope;
27769 * Sets this button's text
27770 * @param {String} text The button text
27772 setText : function(text){
27775 this.el.child("td.x-btn-center button.x-btn-text").update(text);
27781 * Gets the text for this button
27782 * @return {String} The button text
27784 getText : function(){
27792 this.hidden = false;
27794 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
27802 this.hidden = true;
27804 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
27809 * Convenience function for boolean show/hide
27810 * @param {Boolean} visible True to show, false to hide
27812 setVisible: function(visible){
27821 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
27822 * @param {Boolean} state (optional) Force a particular state
27824 toggle : function(state){
27825 state = state === undefined ? !this.pressed : state;
27826 if(state != this.pressed){
27828 this.el.addClass("x-btn-pressed");
27829 this.pressed = true;
27830 this.fireEvent("toggle", this, true);
27832 this.el.removeClass("x-btn-pressed");
27833 this.pressed = false;
27834 this.fireEvent("toggle", this, false);
27836 if(this.toggleHandler){
27837 this.toggleHandler.call(this.scope || this, this, state);
27845 focus : function(){
27846 this.el.child('button:first').focus();
27850 * Disable this button
27852 disable : function(){
27854 this.el.addClass("x-btn-disabled");
27856 this.disabled = true;
27860 * Enable this button
27862 enable : function(){
27864 this.el.removeClass("x-btn-disabled");
27866 this.disabled = false;
27870 * Convenience function for boolean enable/disable
27871 * @param {Boolean} enabled True to enable, false to disable
27873 setDisabled : function(v){
27874 this[v !== true ? "enable" : "disable"]();
27878 onClick : function(e)
27881 e.preventDefault();
27886 if(!this.disabled){
27887 if(this.enableToggle){
27890 if(this.menu && !this.menu.isVisible()){
27891 this.menu.show(this.el, this.menuAlign);
27893 this.fireEvent("click", this, e);
27895 this.el.removeClass("x-btn-over");
27896 this.handler.call(this.scope || this, this, e);
27901 onMouseOver : function(e){
27902 if(!this.disabled){
27903 this.el.addClass("x-btn-over");
27904 this.fireEvent('mouseover', this, e);
27908 onMouseOut : function(e){
27909 if(!e.within(this.el, true)){
27910 this.el.removeClass("x-btn-over");
27911 this.fireEvent('mouseout', this, e);
27915 onFocus : function(e){
27916 if(!this.disabled){
27917 this.el.addClass("x-btn-focus");
27921 onBlur : function(e){
27922 this.el.removeClass("x-btn-focus");
27925 onMouseDown : function(e){
27926 if(!this.disabled && e.button == 0){
27927 this.el.addClass("x-btn-click");
27928 Roo.get(document).on('mouseup', this.onMouseUp, this);
27932 onMouseUp : function(e){
27934 this.el.removeClass("x-btn-click");
27935 Roo.get(document).un('mouseup', this.onMouseUp, this);
27939 onMenuShow : function(e){
27940 this.el.addClass("x-btn-menu-active");
27943 onMenuHide : function(e){
27944 this.el.removeClass("x-btn-menu-active");
27948 // Private utility class used by Button
27949 Roo.ButtonToggleMgr = function(){
27952 function toggleGroup(btn, state){
27954 var g = groups[btn.toggleGroup];
27955 for(var i = 0, l = g.length; i < l; i++){
27957 g[i].toggle(false);
27964 register : function(btn){
27965 if(!btn.toggleGroup){
27968 var g = groups[btn.toggleGroup];
27970 g = groups[btn.toggleGroup] = [];
27973 btn.on("toggle", toggleGroup);
27976 unregister : function(btn){
27977 if(!btn.toggleGroup){
27980 var g = groups[btn.toggleGroup];
27983 btn.un("toggle", toggleGroup);
27989 * Ext JS Library 1.1.1
27990 * Copyright(c) 2006-2007, Ext JS, LLC.
27992 * Originally Released Under LGPL - original licence link has changed is not relivant.
27995 * <script type="text/javascript">
27999 * @class Roo.SplitButton
28000 * @extends Roo.Button
28001 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
28002 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
28003 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
28004 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
28005 * @cfg {String} arrowTooltip The title attribute of the arrow
28007 * Create a new menu button
28008 * @param {String/HTMLElement/Element} renderTo The element to append the button to
28009 * @param {Object} config The config object
28011 Roo.SplitButton = function(renderTo, config){
28012 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
28014 * @event arrowclick
28015 * Fires when this button's arrow is clicked
28016 * @param {SplitButton} this
28017 * @param {EventObject} e The click event
28019 this.addEvents({"arrowclick":true});
28022 Roo.extend(Roo.SplitButton, Roo.Button, {
28023 render : function(renderTo){
28024 // this is one sweet looking template!
28025 var tpl = new Roo.Template(
28026 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
28027 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
28028 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
28029 "</tbody></table></td><td>",
28030 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
28031 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
28032 "</tbody></table></td></tr></table>"
28034 var btn = tpl.append(renderTo, [this.text, this.type], true);
28035 var btnEl = btn.child("button");
28037 btn.addClass(this.cls);
28040 btnEl.setStyle('background-image', 'url(' +this.icon +')');
28043 btnEl.addClass(this.iconCls);
28045 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
28049 if(this.handleMouseEvents){
28050 btn.on("mouseover", this.onMouseOver, this);
28051 btn.on("mouseout", this.onMouseOut, this);
28052 btn.on("mousedown", this.onMouseDown, this);
28053 btn.on("mouseup", this.onMouseUp, this);
28055 btn.on(this.clickEvent, this.onClick, this);
28057 if(typeof this.tooltip == 'object'){
28058 Roo.QuickTips.tips(Roo.apply({
28062 btnEl.dom[this.tooltipType] = this.tooltip;
28065 if(this.arrowTooltip){
28066 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
28075 this.el.addClass("x-btn-pressed");
28077 if(Roo.isIE && !Roo.isIE7){
28078 this.autoWidth.defer(1, this);
28083 this.menu.on("show", this.onMenuShow, this);
28084 this.menu.on("hide", this.onMenuHide, this);
28086 this.fireEvent('render', this);
28090 autoWidth : function(){
28092 var tbl = this.el.child("table:first");
28093 var tbl2 = this.el.child("table:last");
28094 this.el.setWidth("auto");
28095 tbl.setWidth("auto");
28096 if(Roo.isIE7 && Roo.isStrict){
28097 var ib = this.el.child('button:first');
28098 if(ib && ib.getWidth() > 20){
28100 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
28105 this.el.beginMeasure();
28107 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
28108 tbl.setWidth(this.minWidth-tbl2.getWidth());
28111 this.el.endMeasure();
28114 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
28118 * Sets this button's click handler
28119 * @param {Function} handler The function to call when the button is clicked
28120 * @param {Object} scope (optional) Scope for the function passed above
28122 setHandler : function(handler, scope){
28123 this.handler = handler;
28124 this.scope = scope;
28128 * Sets this button's arrow click handler
28129 * @param {Function} handler The function to call when the arrow is clicked
28130 * @param {Object} scope (optional) Scope for the function passed above
28132 setArrowHandler : function(handler, scope){
28133 this.arrowHandler = handler;
28134 this.scope = scope;
28140 focus : function(){
28142 this.el.child("button:first").focus();
28147 onClick : function(e){
28148 e.preventDefault();
28149 if(!this.disabled){
28150 if(e.getTarget(".x-btn-menu-arrow-wrap")){
28151 if(this.menu && !this.menu.isVisible()){
28152 this.menu.show(this.el, this.menuAlign);
28154 this.fireEvent("arrowclick", this, e);
28155 if(this.arrowHandler){
28156 this.arrowHandler.call(this.scope || this, this, e);
28159 this.fireEvent("click", this, e);
28161 this.handler.call(this.scope || this, this, e);
28167 onMouseDown : function(e){
28168 if(!this.disabled){
28169 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
28173 onMouseUp : function(e){
28174 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
28179 // backwards compat
28180 Roo.MenuButton = Roo.SplitButton;/*
28182 * Ext JS Library 1.1.1
28183 * Copyright(c) 2006-2007, Ext JS, LLC.
28185 * Originally Released Under LGPL - original licence link has changed is not relivant.
28188 * <script type="text/javascript">
28192 * @class Roo.Toolbar
28193 * Basic Toolbar class.
28195 * Creates a new Toolbar
28196 * @param {Object} container The config object
28198 Roo.Toolbar = function(container, buttons, config)
28200 /// old consturctor format still supported..
28201 if(container instanceof Array){ // omit the container for later rendering
28202 buttons = container;
28206 if (typeof(container) == 'object' && container.xtype) {
28207 config = container;
28208 container = config.container;
28209 buttons = config.buttons || []; // not really - use items!!
28212 if (config && config.items) {
28213 xitems = config.items;
28214 delete config.items;
28216 Roo.apply(this, config);
28217 this.buttons = buttons;
28220 this.render(container);
28222 this.xitems = xitems;
28223 Roo.each(xitems, function(b) {
28229 Roo.Toolbar.prototype = {
28231 * @cfg {Array} items
28232 * array of button configs or elements to add (will be converted to a MixedCollection)
28236 * @cfg {String/HTMLElement/Element} container
28237 * The id or element that will contain the toolbar
28240 render : function(ct){
28241 this.el = Roo.get(ct);
28243 this.el.addClass(this.cls);
28245 // using a table allows for vertical alignment
28246 // 100% width is needed by Safari...
28247 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
28248 this.tr = this.el.child("tr", true);
28250 this.items = new Roo.util.MixedCollection(false, function(o){
28251 return o.id || ("item" + (++autoId));
28254 this.add.apply(this, this.buttons);
28255 delete this.buttons;
28260 * Adds element(s) to the toolbar -- this function takes a variable number of
28261 * arguments of mixed type and adds them to the toolbar.
28262 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
28264 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
28265 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
28266 * <li>Field: Any form field (equivalent to {@link #addField})</li>
28267 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
28268 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
28269 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
28270 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
28271 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
28272 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
28274 * @param {Mixed} arg2
28275 * @param {Mixed} etc.
28278 var a = arguments, l = a.length;
28279 for(var i = 0; i < l; i++){
28284 _add : function(el) {
28287 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
28290 if (el.applyTo){ // some kind of form field
28291 return this.addField(el);
28293 if (el.render){ // some kind of Toolbar.Item
28294 return this.addItem(el);
28296 if (typeof el == "string"){ // string
28297 if(el == "separator" || el == "-"){
28298 return this.addSeparator();
28301 return this.addSpacer();
28304 return this.addFill();
28306 return this.addText(el);
28309 if(el.tagName){ // element
28310 return this.addElement(el);
28312 if(typeof el == "object"){ // must be button config?
28313 return this.addButton(el);
28315 // and now what?!?!
28321 * Add an Xtype element
28322 * @param {Object} xtype Xtype Object
28323 * @return {Object} created Object
28325 addxtype : function(e){
28326 return this.add(e);
28330 * Returns the Element for this toolbar.
28331 * @return {Roo.Element}
28333 getEl : function(){
28339 * @return {Roo.Toolbar.Item} The separator item
28341 addSeparator : function(){
28342 return this.addItem(new Roo.Toolbar.Separator());
28346 * Adds a spacer element
28347 * @return {Roo.Toolbar.Spacer} The spacer item
28349 addSpacer : function(){
28350 return this.addItem(new Roo.Toolbar.Spacer());
28354 * Adds a fill element that forces subsequent additions to the right side of the toolbar
28355 * @return {Roo.Toolbar.Fill} The fill item
28357 addFill : function(){
28358 return this.addItem(new Roo.Toolbar.Fill());
28362 * Adds any standard HTML element to the toolbar
28363 * @param {String/HTMLElement/Element} el The element or id of the element to add
28364 * @return {Roo.Toolbar.Item} The element's item
28366 addElement : function(el){
28367 return this.addItem(new Roo.Toolbar.Item(el));
28370 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
28371 * @type Roo.util.MixedCollection
28376 * Adds any Toolbar.Item or subclass
28377 * @param {Roo.Toolbar.Item} item
28378 * @return {Roo.Toolbar.Item} The item
28380 addItem : function(item){
28381 var td = this.nextBlock();
28383 this.items.add(item);
28388 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
28389 * @param {Object/Array} config A button config or array of configs
28390 * @return {Roo.Toolbar.Button/Array}
28392 addButton : function(config){
28393 if(config instanceof Array){
28395 for(var i = 0, len = config.length; i < len; i++) {
28396 buttons.push(this.addButton(config[i]));
28401 if(!(config instanceof Roo.Toolbar.Button)){
28403 new Roo.Toolbar.SplitButton(config) :
28404 new Roo.Toolbar.Button(config);
28406 var td = this.nextBlock();
28413 * Adds text to the toolbar
28414 * @param {String} text The text to add
28415 * @return {Roo.Toolbar.Item} The element's item
28417 addText : function(text){
28418 return this.addItem(new Roo.Toolbar.TextItem(text));
28422 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
28423 * @param {Number} index The index where the item is to be inserted
28424 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
28425 * @return {Roo.Toolbar.Button/Item}
28427 insertButton : function(index, item){
28428 if(item instanceof Array){
28430 for(var i = 0, len = item.length; i < len; i++) {
28431 buttons.push(this.insertButton(index + i, item[i]));
28435 if (!(item instanceof Roo.Toolbar.Button)){
28436 item = new Roo.Toolbar.Button(item);
28438 var td = document.createElement("td");
28439 this.tr.insertBefore(td, this.tr.childNodes[index]);
28441 this.items.insert(index, item);
28446 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
28447 * @param {Object} config
28448 * @return {Roo.Toolbar.Item} The element's item
28450 addDom : function(config, returnEl){
28451 var td = this.nextBlock();
28452 Roo.DomHelper.overwrite(td, config);
28453 var ti = new Roo.Toolbar.Item(td.firstChild);
28455 this.items.add(ti);
28460 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
28461 * @type Roo.util.MixedCollection
28466 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
28467 * Note: the field should not have been rendered yet. For a field that has already been
28468 * rendered, use {@link #addElement}.
28469 * @param {Roo.form.Field} field
28470 * @return {Roo.ToolbarItem}
28474 addField : function(field) {
28475 if (!this.fields) {
28477 this.fields = new Roo.util.MixedCollection(false, function(o){
28478 return o.id || ("item" + (++autoId));
28483 var td = this.nextBlock();
28485 var ti = new Roo.Toolbar.Item(td.firstChild);
28487 this.items.add(ti);
28488 this.fields.add(field);
28499 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
28500 this.el.child('div').hide();
28508 this.el.child('div').show();
28512 nextBlock : function(){
28513 var td = document.createElement("td");
28514 this.tr.appendChild(td);
28519 destroy : function(){
28520 if(this.items){ // rendered?
28521 Roo.destroy.apply(Roo, this.items.items);
28523 if(this.fields){ // rendered?
28524 Roo.destroy.apply(Roo, this.fields.items);
28526 Roo.Element.uncache(this.el, this.tr);
28531 * @class Roo.Toolbar.Item
28532 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
28534 * Creates a new Item
28535 * @param {HTMLElement} el
28537 Roo.Toolbar.Item = function(el){
28539 if (typeof (el.xtype) != 'undefined') {
28544 this.el = Roo.getDom(el);
28545 this.id = Roo.id(this.el);
28546 this.hidden = false;
28551 * Fires when the button is rendered
28552 * @param {Button} this
28556 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
28558 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
28559 //Roo.Toolbar.Item.prototype = {
28562 * Get this item's HTML Element
28563 * @return {HTMLElement}
28565 getEl : function(){
28570 render : function(td){
28573 td.appendChild(this.el);
28575 this.fireEvent('render', this);
28579 * Removes and destroys this item.
28581 destroy : function(){
28582 this.td.parentNode.removeChild(this.td);
28589 this.hidden = false;
28590 this.td.style.display = "";
28597 this.hidden = true;
28598 this.td.style.display = "none";
28602 * Convenience function for boolean show/hide.
28603 * @param {Boolean} visible true to show/false to hide
28605 setVisible: function(visible){
28614 * Try to focus this item.
28616 focus : function(){
28617 Roo.fly(this.el).focus();
28621 * Disables this item.
28623 disable : function(){
28624 Roo.fly(this.td).addClass("x-item-disabled");
28625 this.disabled = true;
28626 this.el.disabled = true;
28630 * Enables this item.
28632 enable : function(){
28633 Roo.fly(this.td).removeClass("x-item-disabled");
28634 this.disabled = false;
28635 this.el.disabled = false;
28641 * @class Roo.Toolbar.Separator
28642 * @extends Roo.Toolbar.Item
28643 * A simple toolbar separator class
28645 * Creates a new Separator
28647 Roo.Toolbar.Separator = function(cfg){
28649 var s = document.createElement("span");
28650 s.className = "ytb-sep";
28655 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
28657 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
28658 enable:Roo.emptyFn,
28659 disable:Roo.emptyFn,
28664 * @class Roo.Toolbar.Spacer
28665 * @extends Roo.Toolbar.Item
28666 * A simple element that adds extra horizontal space to a toolbar.
28668 * Creates a new Spacer
28670 Roo.Toolbar.Spacer = function(cfg){
28671 var s = document.createElement("div");
28672 s.className = "ytb-spacer";
28676 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
28678 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
28679 enable:Roo.emptyFn,
28680 disable:Roo.emptyFn,
28685 * @class Roo.Toolbar.Fill
28686 * @extends Roo.Toolbar.Spacer
28687 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
28689 * Creates a new Spacer
28691 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
28693 render : function(td){
28694 td.style.width = '100%';
28695 Roo.Toolbar.Fill.superclass.render.call(this, td);
28700 * @class Roo.Toolbar.TextItem
28701 * @extends Roo.Toolbar.Item
28702 * A simple class that renders text directly into a toolbar.
28704 * Creates a new TextItem
28705 * @param {String} text
28707 Roo.Toolbar.TextItem = function(cfg){
28708 var text = cfg || "";
28709 if (typeof(cfg) == 'object') {
28710 text = cfg.text || "";
28714 var s = document.createElement("span");
28715 s.className = "ytb-text";
28716 s.innerHTML = text;
28721 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
28723 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
28726 enable:Roo.emptyFn,
28727 disable:Roo.emptyFn,
28732 * @class Roo.Toolbar.Button
28733 * @extends Roo.Button
28734 * A button that renders into a toolbar.
28736 * Creates a new Button
28737 * @param {Object} config A standard {@link Roo.Button} config object
28739 Roo.Toolbar.Button = function(config){
28740 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
28742 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
28743 render : function(td){
28745 Roo.Toolbar.Button.superclass.render.call(this, td);
28749 * Removes and destroys this button
28751 destroy : function(){
28752 Roo.Toolbar.Button.superclass.destroy.call(this);
28753 this.td.parentNode.removeChild(this.td);
28757 * Shows this button
28760 this.hidden = false;
28761 this.td.style.display = "";
28765 * Hides this button
28768 this.hidden = true;
28769 this.td.style.display = "none";
28773 * Disables this item
28775 disable : function(){
28776 Roo.fly(this.td).addClass("x-item-disabled");
28777 this.disabled = true;
28781 * Enables this item
28783 enable : function(){
28784 Roo.fly(this.td).removeClass("x-item-disabled");
28785 this.disabled = false;
28788 // backwards compat
28789 Roo.ToolbarButton = Roo.Toolbar.Button;
28792 * @class Roo.Toolbar.SplitButton
28793 * @extends Roo.SplitButton
28794 * A menu button that renders into a toolbar.
28796 * Creates a new SplitButton
28797 * @param {Object} config A standard {@link Roo.SplitButton} config object
28799 Roo.Toolbar.SplitButton = function(config){
28800 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
28802 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
28803 render : function(td){
28805 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
28809 * Removes and destroys this button
28811 destroy : function(){
28812 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
28813 this.td.parentNode.removeChild(this.td);
28817 * Shows this button
28820 this.hidden = false;
28821 this.td.style.display = "";
28825 * Hides this button
28828 this.hidden = true;
28829 this.td.style.display = "none";
28833 // backwards compat
28834 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
28836 * Ext JS Library 1.1.1
28837 * Copyright(c) 2006-2007, Ext JS, LLC.
28839 * Originally Released Under LGPL - original licence link has changed is not relivant.
28842 * <script type="text/javascript">
28846 * @class Roo.PagingToolbar
28847 * @extends Roo.Toolbar
28848 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
28850 * Create a new PagingToolbar
28851 * @param {Object} config The config object
28853 Roo.PagingToolbar = function(el, ds, config)
28855 // old args format still supported... - xtype is prefered..
28856 if (typeof(el) == 'object' && el.xtype) {
28857 // created from xtype...
28859 ds = el.dataSource;
28860 el = config.container;
28863 if (config.items) {
28864 items = config.items;
28868 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
28871 this.renderButtons(this.el);
28874 // supprot items array.
28876 Roo.each(items, function(e) {
28877 this.add(Roo.factory(e));
28882 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
28884 * @cfg {Roo.data.Store} dataSource
28885 * The underlying data store providing the paged data
28888 * @cfg {String/HTMLElement/Element} container
28889 * container The id or element that will contain the toolbar
28892 * @cfg {Boolean} displayInfo
28893 * True to display the displayMsg (defaults to false)
28896 * @cfg {Number} pageSize
28897 * The number of records to display per page (defaults to 20)
28901 * @cfg {String} displayMsg
28902 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
28904 displayMsg : 'Displaying {0} - {1} of {2}',
28906 * @cfg {String} emptyMsg
28907 * The message to display when no records are found (defaults to "No data to display")
28909 emptyMsg : 'No data to display',
28911 * Customizable piece of the default paging text (defaults to "Page")
28914 beforePageText : "Page",
28916 * Customizable piece of the default paging text (defaults to "of %0")
28919 afterPageText : "of {0}",
28921 * Customizable piece of the default paging text (defaults to "First Page")
28924 firstText : "First Page",
28926 * Customizable piece of the default paging text (defaults to "Previous Page")
28929 prevText : "Previous Page",
28931 * Customizable piece of the default paging text (defaults to "Next Page")
28934 nextText : "Next Page",
28936 * Customizable piece of the default paging text (defaults to "Last Page")
28939 lastText : "Last Page",
28941 * Customizable piece of the default paging text (defaults to "Refresh")
28944 refreshText : "Refresh",
28947 renderButtons : function(el){
28948 Roo.PagingToolbar.superclass.render.call(this, el);
28949 this.first = this.addButton({
28950 tooltip: this.firstText,
28951 cls: "x-btn-icon x-grid-page-first",
28953 handler: this.onClick.createDelegate(this, ["first"])
28955 this.prev = this.addButton({
28956 tooltip: this.prevText,
28957 cls: "x-btn-icon x-grid-page-prev",
28959 handler: this.onClick.createDelegate(this, ["prev"])
28961 //this.addSeparator();
28962 this.add(this.beforePageText);
28963 this.field = Roo.get(this.addDom({
28968 cls: "x-grid-page-number"
28970 this.field.on("keydown", this.onPagingKeydown, this);
28971 this.field.on("focus", function(){this.dom.select();});
28972 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
28973 this.field.setHeight(18);
28974 //this.addSeparator();
28975 this.next = this.addButton({
28976 tooltip: this.nextText,
28977 cls: "x-btn-icon x-grid-page-next",
28979 handler: this.onClick.createDelegate(this, ["next"])
28981 this.last = this.addButton({
28982 tooltip: this.lastText,
28983 cls: "x-btn-icon x-grid-page-last",
28985 handler: this.onClick.createDelegate(this, ["last"])
28987 //this.addSeparator();
28988 this.loading = this.addButton({
28989 tooltip: this.refreshText,
28990 cls: "x-btn-icon x-grid-loading",
28991 handler: this.onClick.createDelegate(this, ["refresh"])
28994 if(this.displayInfo){
28995 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
29000 updateInfo : function(){
29001 if(this.displayEl){
29002 var count = this.ds.getCount();
29003 var msg = count == 0 ?
29007 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
29009 this.displayEl.update(msg);
29014 onLoad : function(ds, r, o){
29015 this.cursor = o.params ? o.params.start : 0;
29016 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
29018 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
29019 this.field.dom.value = ap;
29020 this.first.setDisabled(ap == 1);
29021 this.prev.setDisabled(ap == 1);
29022 this.next.setDisabled(ap == ps);
29023 this.last.setDisabled(ap == ps);
29024 this.loading.enable();
29029 getPageData : function(){
29030 var total = this.ds.getTotalCount();
29033 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
29034 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
29039 onLoadError : function(){
29040 this.loading.enable();
29044 onPagingKeydown : function(e){
29045 var k = e.getKey();
29046 var d = this.getPageData();
29048 var v = this.field.dom.value, pageNum;
29049 if(!v || isNaN(pageNum = parseInt(v, 10))){
29050 this.field.dom.value = d.activePage;
29053 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
29054 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29057 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
29059 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
29060 this.field.dom.value = pageNum;
29061 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
29064 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29066 var v = this.field.dom.value, pageNum;
29067 var increment = (e.shiftKey) ? 10 : 1;
29068 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
29070 if(!v || isNaN(pageNum = parseInt(v, 10))) {
29071 this.field.dom.value = d.activePage;
29074 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
29076 this.field.dom.value = parseInt(v, 10) + increment;
29077 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
29078 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
29085 beforeLoad : function(){
29087 this.loading.disable();
29092 onClick : function(which){
29096 ds.load({params:{start: 0, limit: this.pageSize}});
29099 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
29102 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
29105 var total = ds.getTotalCount();
29106 var extra = total % this.pageSize;
29107 var lastStart = extra ? (total - extra) : total-this.pageSize;
29108 ds.load({params:{start: lastStart, limit: this.pageSize}});
29111 ds.load({params:{start: this.cursor, limit: this.pageSize}});
29117 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
29118 * @param {Roo.data.Store} store The data store to unbind
29120 unbind : function(ds){
29121 ds.un("beforeload", this.beforeLoad, this);
29122 ds.un("load", this.onLoad, this);
29123 ds.un("loadexception", this.onLoadError, this);
29124 ds.un("remove", this.updateInfo, this);
29125 ds.un("add", this.updateInfo, this);
29126 this.ds = undefined;
29130 * Binds the paging toolbar to the specified {@link Roo.data.Store}
29131 * @param {Roo.data.Store} store The data store to bind
29133 bind : function(ds){
29134 ds.on("beforeload", this.beforeLoad, this);
29135 ds.on("load", this.onLoad, this);
29136 ds.on("loadexception", this.onLoadError, this);
29137 ds.on("remove", this.updateInfo, this);
29138 ds.on("add", this.updateInfo, this);
29143 * Ext JS Library 1.1.1
29144 * Copyright(c) 2006-2007, Ext JS, LLC.
29146 * Originally Released Under LGPL - original licence link has changed is not relivant.
29149 * <script type="text/javascript">
29153 * @class Roo.Resizable
29154 * @extends Roo.util.Observable
29155 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
29156 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
29157 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
29158 * the element will be wrapped for you automatically.</p>
29159 * <p>Here is the list of valid resize handles:</p>
29162 ------ -------------------
29171 'hd' horizontal drag
29174 * <p>Here's an example showing the creation of a typical Resizable:</p>
29176 var resizer = new Roo.Resizable("element-id", {
29184 resizer.on("resize", myHandler);
29186 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
29187 * resizer.east.setDisplayed(false);</p>
29188 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
29189 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
29190 * resize operation's new size (defaults to [0, 0])
29191 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
29192 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
29193 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
29194 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
29195 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
29196 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
29197 * @cfg {Number} width The width of the element in pixels (defaults to null)
29198 * @cfg {Number} height The height of the element in pixels (defaults to null)
29199 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
29200 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
29201 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
29202 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
29203 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
29204 * in favor of the handles config option (defaults to false)
29205 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
29206 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
29207 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
29208 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
29209 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
29210 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
29211 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
29212 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
29213 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
29214 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
29215 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
29217 * Create a new resizable component
29218 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
29219 * @param {Object} config configuration options
29221 Roo.Resizable = function(el, config)
29223 this.el = Roo.get(el);
29225 if(config && config.wrap){
29226 config.resizeChild = this.el;
29227 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
29228 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
29229 this.el.setStyle("overflow", "hidden");
29230 this.el.setPositioning(config.resizeChild.getPositioning());
29231 config.resizeChild.clearPositioning();
29232 if(!config.width || !config.height){
29233 var csize = config.resizeChild.getSize();
29234 this.el.setSize(csize.width, csize.height);
29236 if(config.pinned && !config.adjustments){
29237 config.adjustments = "auto";
29241 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
29242 this.proxy.unselectable();
29243 this.proxy.enableDisplayMode('block');
29245 Roo.apply(this, config);
29248 this.disableTrackOver = true;
29249 this.el.addClass("x-resizable-pinned");
29251 // if the element isn't positioned, make it relative
29252 var position = this.el.getStyle("position");
29253 if(position != "absolute" && position != "fixed"){
29254 this.el.setStyle("position", "relative");
29256 if(!this.handles){ // no handles passed, must be legacy style
29257 this.handles = 's,e,se';
29258 if(this.multiDirectional){
29259 this.handles += ',n,w';
29262 if(this.handles == "all"){
29263 this.handles = "n s e w ne nw se sw";
29265 var hs = this.handles.split(/\s*?[,;]\s*?| /);
29266 var ps = Roo.Resizable.positions;
29267 for(var i = 0, len = hs.length; i < len; i++){
29268 if(hs[i] && ps[hs[i]]){
29269 var pos = ps[hs[i]];
29270 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
29274 this.corner = this.southeast;
29276 // updateBox = the box can move..
29277 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
29278 this.updateBox = true;
29281 this.activeHandle = null;
29283 if(this.resizeChild){
29284 if(typeof this.resizeChild == "boolean"){
29285 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
29287 this.resizeChild = Roo.get(this.resizeChild, true);
29291 if(this.adjustments == "auto"){
29292 var rc = this.resizeChild;
29293 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
29294 if(rc && (hw || hn)){
29295 rc.position("relative");
29296 rc.setLeft(hw ? hw.el.getWidth() : 0);
29297 rc.setTop(hn ? hn.el.getHeight() : 0);
29299 this.adjustments = [
29300 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
29301 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
29305 if(this.draggable){
29306 this.dd = this.dynamic ?
29307 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
29308 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
29314 * @event beforeresize
29315 * Fired before resize is allowed. Set enabled to false to cancel resize.
29316 * @param {Roo.Resizable} this
29317 * @param {Roo.EventObject} e The mousedown event
29319 "beforeresize" : true,
29322 * Fired a resizing.
29323 * @param {Roo.Resizable} this
29324 * @param {Number} x The new x position
29325 * @param {Number} y The new y position
29326 * @param {Number} w The new w width
29327 * @param {Number} h The new h hight
29328 * @param {Roo.EventObject} e The mouseup event
29333 * Fired after a resize.
29334 * @param {Roo.Resizable} this
29335 * @param {Number} width The new width
29336 * @param {Number} height The new height
29337 * @param {Roo.EventObject} e The mouseup event
29342 if(this.width !== null && this.height !== null){
29343 this.resizeTo(this.width, this.height);
29345 this.updateChildSize();
29348 this.el.dom.style.zoom = 1;
29350 Roo.Resizable.superclass.constructor.call(this);
29353 Roo.extend(Roo.Resizable, Roo.util.Observable, {
29354 resizeChild : false,
29355 adjustments : [0, 0],
29365 multiDirectional : false,
29366 disableTrackOver : false,
29367 easing : 'easeOutStrong',
29368 widthIncrement : 0,
29369 heightIncrement : 0,
29373 preserveRatio : false,
29374 transparent: false,
29380 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
29382 constrainTo: undefined,
29384 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
29386 resizeRegion: undefined,
29390 * Perform a manual resize
29391 * @param {Number} width
29392 * @param {Number} height
29394 resizeTo : function(width, height){
29395 this.el.setSize(width, height);
29396 this.updateChildSize();
29397 this.fireEvent("resize", this, width, height, null);
29401 startSizing : function(e, handle){
29402 this.fireEvent("beforeresize", this, e);
29403 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
29406 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
29407 this.overlay.unselectable();
29408 this.overlay.enableDisplayMode("block");
29409 this.overlay.on("mousemove", this.onMouseMove, this);
29410 this.overlay.on("mouseup", this.onMouseUp, this);
29412 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
29414 this.resizing = true;
29415 this.startBox = this.el.getBox();
29416 this.startPoint = e.getXY();
29417 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
29418 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
29420 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
29421 this.overlay.show();
29423 if(this.constrainTo) {
29424 var ct = Roo.get(this.constrainTo);
29425 this.resizeRegion = ct.getRegion().adjust(
29426 ct.getFrameWidth('t'),
29427 ct.getFrameWidth('l'),
29428 -ct.getFrameWidth('b'),
29429 -ct.getFrameWidth('r')
29433 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
29435 this.proxy.setBox(this.startBox);
29437 this.proxy.setStyle('visibility', 'visible');
29443 onMouseDown : function(handle, e){
29446 this.activeHandle = handle;
29447 this.startSizing(e, handle);
29452 onMouseUp : function(e){
29453 var size = this.resizeElement();
29454 this.resizing = false;
29456 this.overlay.hide();
29458 this.fireEvent("resize", this, size.width, size.height, e);
29462 updateChildSize : function(){
29464 if(this.resizeChild){
29466 var child = this.resizeChild;
29467 var adj = this.adjustments;
29468 if(el.dom.offsetWidth){
29469 var b = el.getSize(true);
29470 child.setSize(b.width+adj[0], b.height+adj[1]);
29472 // Second call here for IE
29473 // The first call enables instant resizing and
29474 // the second call corrects scroll bars if they
29477 setTimeout(function(){
29478 if(el.dom.offsetWidth){
29479 var b = el.getSize(true);
29480 child.setSize(b.width+adj[0], b.height+adj[1]);
29488 snap : function(value, inc, min){
29489 if(!inc || !value) return value;
29490 var newValue = value;
29491 var m = value % inc;
29494 newValue = value + (inc-m);
29496 newValue = value - m;
29499 return Math.max(min, newValue);
29503 resizeElement : function(){
29504 var box = this.proxy.getBox();
29505 if(this.updateBox){
29506 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
29508 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
29510 this.updateChildSize();
29518 constrain : function(v, diff, m, mx){
29521 }else if(v - diff > mx){
29528 onMouseMove : function(e){
29531 try{// try catch so if something goes wrong the user doesn't get hung
29533 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
29537 //var curXY = this.startPoint;
29538 var curSize = this.curSize || this.startBox;
29539 var x = this.startBox.x, y = this.startBox.y;
29540 var ox = x, oy = y;
29541 var w = curSize.width, h = curSize.height;
29542 var ow = w, oh = h;
29543 var mw = this.minWidth, mh = this.minHeight;
29544 var mxw = this.maxWidth, mxh = this.maxHeight;
29545 var wi = this.widthIncrement;
29546 var hi = this.heightIncrement;
29548 var eventXY = e.getXY();
29549 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
29550 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
29552 var pos = this.activeHandle.position;
29557 w = Math.min(Math.max(mw, w), mxw);
29562 h = Math.min(Math.max(mh, h), mxh);
29567 w = Math.min(Math.max(mw, w), mxw);
29568 h = Math.min(Math.max(mh, h), mxh);
29571 diffY = this.constrain(h, diffY, mh, mxh);
29578 var adiffX = Math.abs(diffX);
29579 var sub = (adiffX % wi); // how much
29580 if (sub > (wi/2)) { // far enough to snap
29581 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
29583 // remove difference..
29584 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
29588 x = Math.max(this.minX, x);
29591 diffX = this.constrain(w, diffX, mw, mxw);
29597 w = Math.min(Math.max(mw, w), mxw);
29598 diffY = this.constrain(h, diffY, mh, mxh);
29603 diffX = this.constrain(w, diffX, mw, mxw);
29604 diffY = this.constrain(h, diffY, mh, mxh);
29611 diffX = this.constrain(w, diffX, mw, mxw);
29613 h = Math.min(Math.max(mh, h), mxh);
29619 var sw = this.snap(w, wi, mw);
29620 var sh = this.snap(h, hi, mh);
29621 if(sw != w || sh != h){
29644 if(this.preserveRatio){
29649 h = Math.min(Math.max(mh, h), mxh);
29654 w = Math.min(Math.max(mw, w), mxw);
29659 w = Math.min(Math.max(mw, w), mxw);
29665 w = Math.min(Math.max(mw, w), mxw);
29671 h = Math.min(Math.max(mh, h), mxh);
29679 h = Math.min(Math.max(mh, h), mxh);
29689 h = Math.min(Math.max(mh, h), mxh);
29697 if (pos == 'hdrag') {
29700 this.proxy.setBounds(x, y, w, h);
29702 this.resizeElement();
29706 this.fireEvent("resizing", this, x, y, w, h, e);
29710 handleOver : function(){
29712 this.el.addClass("x-resizable-over");
29717 handleOut : function(){
29718 if(!this.resizing){
29719 this.el.removeClass("x-resizable-over");
29724 * Returns the element this component is bound to.
29725 * @return {Roo.Element}
29727 getEl : function(){
29732 * Returns the resizeChild element (or null).
29733 * @return {Roo.Element}
29735 getResizeChild : function(){
29736 return this.resizeChild;
29738 groupHandler : function()
29743 * Destroys this resizable. If the element was wrapped and
29744 * removeEl is not true then the element remains.
29745 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
29747 destroy : function(removeEl){
29748 this.proxy.remove();
29750 this.overlay.removeAllListeners();
29751 this.overlay.remove();
29753 var ps = Roo.Resizable.positions;
29755 if(typeof ps[k] != "function" && this[ps[k]]){
29756 var h = this[ps[k]];
29757 h.el.removeAllListeners();
29762 this.el.update("");
29769 // hash to map config positions to true positions
29770 Roo.Resizable.positions = {
29771 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
29776 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
29778 // only initialize the template if resizable is used
29779 var tpl = Roo.DomHelper.createTemplate(
29780 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
29783 Roo.Resizable.Handle.prototype.tpl = tpl;
29785 this.position = pos;
29787 // show north drag fro topdra
29788 var handlepos = pos == 'hdrag' ? 'north' : pos;
29790 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
29791 if (pos == 'hdrag') {
29792 this.el.setStyle('cursor', 'pointer');
29794 this.el.unselectable();
29796 this.el.setOpacity(0);
29798 this.el.on("mousedown", this.onMouseDown, this);
29799 if(!disableTrackOver){
29800 this.el.on("mouseover", this.onMouseOver, this);
29801 this.el.on("mouseout", this.onMouseOut, this);
29806 Roo.Resizable.Handle.prototype = {
29807 afterResize : function(rz){
29812 onMouseDown : function(e){
29813 this.rz.onMouseDown(this, e);
29816 onMouseOver : function(e){
29817 this.rz.handleOver(this, e);
29820 onMouseOut : function(e){
29821 this.rz.handleOut(this, e);
29825 * Ext JS Library 1.1.1
29826 * Copyright(c) 2006-2007, Ext JS, LLC.
29828 * Originally Released Under LGPL - original licence link has changed is not relivant.
29831 * <script type="text/javascript">
29835 * @class Roo.Editor
29836 * @extends Roo.Component
29837 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
29839 * Create a new Editor
29840 * @param {Roo.form.Field} field The Field object (or descendant)
29841 * @param {Object} config The config object
29843 Roo.Editor = function(field, config){
29844 Roo.Editor.superclass.constructor.call(this, config);
29845 this.field = field;
29848 * @event beforestartedit
29849 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
29850 * false from the handler of this event.
29851 * @param {Editor} this
29852 * @param {Roo.Element} boundEl The underlying element bound to this editor
29853 * @param {Mixed} value The field value being set
29855 "beforestartedit" : true,
29858 * Fires when this editor is displayed
29859 * @param {Roo.Element} boundEl The underlying element bound to this editor
29860 * @param {Mixed} value The starting field value
29862 "startedit" : true,
29864 * @event beforecomplete
29865 * Fires after a change has been made to the field, but before the change is reflected in the underlying
29866 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
29867 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
29868 * event will not fire since no edit actually occurred.
29869 * @param {Editor} this
29870 * @param {Mixed} value The current field value
29871 * @param {Mixed} startValue The original field value
29873 "beforecomplete" : true,
29876 * Fires after editing is complete and any changed value has been written to the underlying field.
29877 * @param {Editor} this
29878 * @param {Mixed} value The current field value
29879 * @param {Mixed} startValue The original field value
29883 * @event specialkey
29884 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
29885 * {@link Roo.EventObject#getKey} to determine which key was pressed.
29886 * @param {Roo.form.Field} this
29887 * @param {Roo.EventObject} e The event object
29889 "specialkey" : true
29893 Roo.extend(Roo.Editor, Roo.Component, {
29895 * @cfg {Boolean/String} autosize
29896 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
29897 * or "height" to adopt the height only (defaults to false)
29900 * @cfg {Boolean} revertInvalid
29901 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
29902 * validation fails (defaults to true)
29905 * @cfg {Boolean} ignoreNoChange
29906 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
29907 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
29908 * will never be ignored.
29911 * @cfg {Boolean} hideEl
29912 * False to keep the bound element visible while the editor is displayed (defaults to true)
29915 * @cfg {Mixed} value
29916 * The data value of the underlying field (defaults to "")
29920 * @cfg {String} alignment
29921 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
29925 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
29926 * for bottom-right shadow (defaults to "frame")
29930 * @cfg {Boolean} constrain True to constrain the editor to the viewport
29934 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
29936 completeOnEnter : false,
29938 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
29940 cancelOnEsc : false,
29942 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
29947 onRender : function(ct, position){
29948 this.el = new Roo.Layer({
29949 shadow: this.shadow,
29955 constrain: this.constrain
29957 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
29958 if(this.field.msgTarget != 'title'){
29959 this.field.msgTarget = 'qtip';
29961 this.field.render(this.el);
29963 this.field.el.dom.setAttribute('autocomplete', 'off');
29965 this.field.on("specialkey", this.onSpecialKey, this);
29966 if(this.swallowKeys){
29967 this.field.el.swallowEvent(['keydown','keypress']);
29970 this.field.on("blur", this.onBlur, this);
29971 if(this.field.grow){
29972 this.field.on("autosize", this.el.sync, this.el, {delay:1});
29976 onSpecialKey : function(field, e)
29978 //Roo.log('editor onSpecialKey');
29979 if(this.completeOnEnter && e.getKey() == e.ENTER){
29981 this.completeEdit();
29984 // do not fire special key otherwise it might hide close the editor...
29985 if(e.getKey() == e.ENTER){
29988 if(this.cancelOnEsc && e.getKey() == e.ESC){
29992 this.fireEvent('specialkey', field, e);
29997 * Starts the editing process and shows the editor.
29998 * @param {String/HTMLElement/Element} el The element to edit
29999 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
30000 * to the innerHTML of el.
30002 startEdit : function(el, value){
30004 this.completeEdit();
30006 this.boundEl = Roo.get(el);
30007 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
30008 if(!this.rendered){
30009 this.render(this.parentEl || document.body);
30011 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
30014 this.startValue = v;
30015 this.field.setValue(v);
30017 var sz = this.boundEl.getSize();
30018 switch(this.autoSize){
30020 this.setSize(sz.width, "");
30023 this.setSize("", sz.height);
30026 this.setSize(sz.width, sz.height);
30029 this.el.alignTo(this.boundEl, this.alignment);
30030 this.editing = true;
30032 Roo.QuickTips.disable();
30038 * Sets the height and width of this editor.
30039 * @param {Number} width The new width
30040 * @param {Number} height The new height
30042 setSize : function(w, h){
30043 this.field.setSize(w, h);
30050 * Realigns the editor to the bound field based on the current alignment config value.
30052 realign : function(){
30053 this.el.alignTo(this.boundEl, this.alignment);
30057 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
30058 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
30060 completeEdit : function(remainVisible){
30064 var v = this.getValue();
30065 if(this.revertInvalid !== false && !this.field.isValid()){
30066 v = this.startValue;
30067 this.cancelEdit(true);
30069 if(String(v) === String(this.startValue) && this.ignoreNoChange){
30070 this.editing = false;
30074 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
30075 this.editing = false;
30076 if(this.updateEl && this.boundEl){
30077 this.boundEl.update(v);
30079 if(remainVisible !== true){
30082 this.fireEvent("complete", this, v, this.startValue);
30087 onShow : function(){
30089 if(this.hideEl !== false){
30090 this.boundEl.hide();
30093 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
30094 this.fixIEFocus = true;
30095 this.deferredFocus.defer(50, this);
30097 this.field.focus();
30099 this.fireEvent("startedit", this.boundEl, this.startValue);
30102 deferredFocus : function(){
30104 this.field.focus();
30109 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
30110 * reverted to the original starting value.
30111 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
30112 * cancel (defaults to false)
30114 cancelEdit : function(remainVisible){
30116 this.setValue(this.startValue);
30117 if(remainVisible !== true){
30124 onBlur : function(){
30125 if(this.allowBlur !== true && this.editing){
30126 this.completeEdit();
30131 onHide : function(){
30133 this.completeEdit();
30137 if(this.field.collapse){
30138 this.field.collapse();
30141 if(this.hideEl !== false){
30142 this.boundEl.show();
30145 Roo.QuickTips.enable();
30150 * Sets the data value of the editor
30151 * @param {Mixed} value Any valid value supported by the underlying field
30153 setValue : function(v){
30154 this.field.setValue(v);
30158 * Gets the data value of the editor
30159 * @return {Mixed} The data value
30161 getValue : function(){
30162 return this.field.getValue();
30166 * Ext JS Library 1.1.1
30167 * Copyright(c) 2006-2007, Ext JS, LLC.
30169 * Originally Released Under LGPL - original licence link has changed is not relivant.
30172 * <script type="text/javascript">
30176 * @class Roo.BasicDialog
30177 * @extends Roo.util.Observable
30178 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
30180 var dlg = new Roo.BasicDialog("my-dlg", {
30189 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
30190 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
30191 dlg.addButton('Cancel', dlg.hide, dlg);
30194 <b>A Dialog should always be a direct child of the body element.</b>
30195 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
30196 * @cfg {String} title Default text to display in the title bar (defaults to null)
30197 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30198 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
30199 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
30200 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
30201 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
30202 * (defaults to null with no animation)
30203 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
30204 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
30205 * property for valid values (defaults to 'all')
30206 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
30207 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
30208 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
30209 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
30210 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
30211 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
30212 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
30213 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
30214 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
30215 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
30216 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
30217 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
30218 * draggable = true (defaults to false)
30219 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
30220 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
30221 * shadow (defaults to false)
30222 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
30223 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
30224 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
30225 * @cfg {Array} buttons Array of buttons
30226 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
30228 * Create a new BasicDialog.
30229 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
30230 * @param {Object} config Configuration options
30232 Roo.BasicDialog = function(el, config){
30233 this.el = Roo.get(el);
30234 var dh = Roo.DomHelper;
30235 if(!this.el && config && config.autoCreate){
30236 if(typeof config.autoCreate == "object"){
30237 if(!config.autoCreate.id){
30238 config.autoCreate.id = el;
30240 this.el = dh.append(document.body,
30241 config.autoCreate, true);
30243 this.el = dh.append(document.body,
30244 {tag: "div", id: el, style:'visibility:hidden;'}, true);
30248 el.setDisplayed(true);
30249 el.hide = this.hideAction;
30251 el.addClass("x-dlg");
30253 Roo.apply(this, config);
30255 this.proxy = el.createProxy("x-dlg-proxy");
30256 this.proxy.hide = this.hideAction;
30257 this.proxy.setOpacity(.5);
30261 el.setWidth(config.width);
30264 el.setHeight(config.height);
30266 this.size = el.getSize();
30267 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
30268 this.xy = [config.x,config.y];
30270 this.xy = el.getCenterXY(true);
30272 /** The header element @type Roo.Element */
30273 this.header = el.child("> .x-dlg-hd");
30274 /** The body element @type Roo.Element */
30275 this.body = el.child("> .x-dlg-bd");
30276 /** The footer element @type Roo.Element */
30277 this.footer = el.child("> .x-dlg-ft");
30280 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
30283 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
30286 this.header.unselectable();
30288 this.header.update(this.title);
30290 // this element allows the dialog to be focused for keyboard event
30291 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
30292 this.focusEl.swallowEvent("click", true);
30294 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
30296 // wrap the body and footer for special rendering
30297 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
30299 this.bwrap.dom.appendChild(this.footer.dom);
30302 this.bg = this.el.createChild({
30303 tag: "div", cls:"x-dlg-bg",
30304 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
30306 this.centerBg = this.bg.child("div.x-dlg-bg-center");
30309 if(this.autoScroll !== false && !this.autoTabs){
30310 this.body.setStyle("overflow", "auto");
30313 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
30315 if(this.closable !== false){
30316 this.el.addClass("x-dlg-closable");
30317 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
30318 this.close.on("click", this.closeClick, this);
30319 this.close.addClassOnOver("x-dlg-close-over");
30321 if(this.collapsible !== false){
30322 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
30323 this.collapseBtn.on("click", this.collapseClick, this);
30324 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
30325 this.header.on("dblclick", this.collapseClick, this);
30327 if(this.resizable !== false){
30328 this.el.addClass("x-dlg-resizable");
30329 this.resizer = new Roo.Resizable(el, {
30330 minWidth: this.minWidth || 80,
30331 minHeight:this.minHeight || 80,
30332 handles: this.resizeHandles || "all",
30335 this.resizer.on("beforeresize", this.beforeResize, this);
30336 this.resizer.on("resize", this.onResize, this);
30338 if(this.draggable !== false){
30339 el.addClass("x-dlg-draggable");
30340 if (!this.proxyDrag) {
30341 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
30344 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
30346 dd.setHandleElId(this.header.id);
30347 dd.endDrag = this.endMove.createDelegate(this);
30348 dd.startDrag = this.startMove.createDelegate(this);
30349 dd.onDrag = this.onDrag.createDelegate(this);
30354 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
30355 this.mask.enableDisplayMode("block");
30357 this.el.addClass("x-dlg-modal");
30360 this.shadow = new Roo.Shadow({
30361 mode : typeof this.shadow == "string" ? this.shadow : "sides",
30362 offset : this.shadowOffset
30365 this.shadowOffset = 0;
30367 if(Roo.useShims && this.shim !== false){
30368 this.shim = this.el.createShim();
30369 this.shim.hide = this.hideAction;
30377 if (this.buttons) {
30378 var bts= this.buttons;
30380 Roo.each(bts, function(b) {
30389 * Fires when a key is pressed
30390 * @param {Roo.BasicDialog} this
30391 * @param {Roo.EventObject} e
30396 * Fires when this dialog is moved by the user.
30397 * @param {Roo.BasicDialog} this
30398 * @param {Number} x The new page X
30399 * @param {Number} y The new page Y
30404 * Fires when this dialog is resized by the user.
30405 * @param {Roo.BasicDialog} this
30406 * @param {Number} width The new width
30407 * @param {Number} height The new height
30411 * @event beforehide
30412 * Fires before this dialog is hidden.
30413 * @param {Roo.BasicDialog} this
30415 "beforehide" : true,
30418 * Fires when this dialog is hidden.
30419 * @param {Roo.BasicDialog} this
30423 * @event beforeshow
30424 * Fires before this dialog is shown.
30425 * @param {Roo.BasicDialog} this
30427 "beforeshow" : true,
30430 * Fires when this dialog is shown.
30431 * @param {Roo.BasicDialog} this
30435 el.on("keydown", this.onKeyDown, this);
30436 el.on("mousedown", this.toFront, this);
30437 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
30439 Roo.DialogManager.register(this);
30440 Roo.BasicDialog.superclass.constructor.call(this);
30443 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
30444 shadowOffset: Roo.isIE ? 6 : 5,
30447 minButtonWidth: 75,
30448 defaultButton: null,
30449 buttonAlign: "right",
30454 * Sets the dialog title text
30455 * @param {String} text The title text to display
30456 * @return {Roo.BasicDialog} this
30458 setTitle : function(text){
30459 this.header.update(text);
30464 closeClick : function(){
30469 collapseClick : function(){
30470 this[this.collapsed ? "expand" : "collapse"]();
30474 * Collapses the dialog to its minimized state (only the title bar is visible).
30475 * Equivalent to the user clicking the collapse dialog button.
30477 collapse : function(){
30478 if(!this.collapsed){
30479 this.collapsed = true;
30480 this.el.addClass("x-dlg-collapsed");
30481 this.restoreHeight = this.el.getHeight();
30482 this.resizeTo(this.el.getWidth(), this.header.getHeight());
30487 * Expands a collapsed dialog back to its normal state. Equivalent to the user
30488 * clicking the expand dialog button.
30490 expand : function(){
30491 if(this.collapsed){
30492 this.collapsed = false;
30493 this.el.removeClass("x-dlg-collapsed");
30494 this.resizeTo(this.el.getWidth(), this.restoreHeight);
30499 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
30500 * @return {Roo.TabPanel} The tabs component
30502 initTabs : function(){
30503 var tabs = this.getTabs();
30504 while(tabs.getTab(0)){
30507 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
30509 tabs.addTab(Roo.id(dom), dom.title);
30517 beforeResize : function(){
30518 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
30522 onResize : function(){
30523 this.refreshSize();
30524 this.syncBodyHeight();
30525 this.adjustAssets();
30527 this.fireEvent("resize", this, this.size.width, this.size.height);
30531 onKeyDown : function(e){
30532 if(this.isVisible()){
30533 this.fireEvent("keydown", this, e);
30538 * Resizes the dialog.
30539 * @param {Number} width
30540 * @param {Number} height
30541 * @return {Roo.BasicDialog} this
30543 resizeTo : function(width, height){
30544 this.el.setSize(width, height);
30545 this.size = {width: width, height: height};
30546 this.syncBodyHeight();
30547 if(this.fixedcenter){
30550 if(this.isVisible()){
30551 this.constrainXY();
30552 this.adjustAssets();
30554 this.fireEvent("resize", this, width, height);
30560 * Resizes the dialog to fit the specified content size.
30561 * @param {Number} width
30562 * @param {Number} height
30563 * @return {Roo.BasicDialog} this
30565 setContentSize : function(w, h){
30566 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
30567 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
30568 //if(!this.el.isBorderBox()){
30569 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
30570 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
30573 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
30574 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
30576 this.resizeTo(w, h);
30581 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
30582 * executed in response to a particular key being pressed while the dialog is active.
30583 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
30584 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
30585 * @param {Function} fn The function to call
30586 * @param {Object} scope (optional) The scope of the function
30587 * @return {Roo.BasicDialog} this
30589 addKeyListener : function(key, fn, scope){
30590 var keyCode, shift, ctrl, alt;
30591 if(typeof key == "object" && !(key instanceof Array)){
30592 keyCode = key["key"];
30593 shift = key["shift"];
30594 ctrl = key["ctrl"];
30599 var handler = function(dlg, e){
30600 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
30601 var k = e.getKey();
30602 if(keyCode instanceof Array){
30603 for(var i = 0, len = keyCode.length; i < len; i++){
30604 if(keyCode[i] == k){
30605 fn.call(scope || window, dlg, k, e);
30611 fn.call(scope || window, dlg, k, e);
30616 this.on("keydown", handler);
30621 * Returns the TabPanel component (creates it if it doesn't exist).
30622 * Note: If you wish to simply check for the existence of tabs without creating them,
30623 * check for a null 'tabs' property.
30624 * @return {Roo.TabPanel} The tabs component
30626 getTabs : function(){
30628 this.el.addClass("x-dlg-auto-tabs");
30629 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
30630 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
30636 * Adds a button to the footer section of the dialog.
30637 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
30638 * object or a valid Roo.DomHelper element config
30639 * @param {Function} handler The function called when the button is clicked
30640 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
30641 * @return {Roo.Button} The new button
30643 addButton : function(config, handler, scope){
30644 var dh = Roo.DomHelper;
30646 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
30648 if(!this.btnContainer){
30649 var tb = this.footer.createChild({
30651 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
30652 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
30654 this.btnContainer = tb.firstChild.firstChild.firstChild;
30659 minWidth: this.minButtonWidth,
30662 if(typeof config == "string"){
30663 bconfig.text = config;
30666 bconfig.dhconfig = config;
30668 Roo.apply(bconfig, config);
30672 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
30673 bconfig.position = Math.max(0, bconfig.position);
30674 fc = this.btnContainer.childNodes[bconfig.position];
30677 var btn = new Roo.Button(
30679 this.btnContainer.insertBefore(document.createElement("td"),fc)
30680 : this.btnContainer.appendChild(document.createElement("td")),
30681 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
30684 this.syncBodyHeight();
30687 * Array of all the buttons that have been added to this dialog via addButton
30692 this.buttons.push(btn);
30697 * Sets the default button to be focused when the dialog is displayed.
30698 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
30699 * @return {Roo.BasicDialog} this
30701 setDefaultButton : function(btn){
30702 this.defaultButton = btn;
30707 getHeaderFooterHeight : function(safe){
30710 height += this.header.getHeight();
30713 var fm = this.footer.getMargins();
30714 height += (this.footer.getHeight()+fm.top+fm.bottom);
30716 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
30717 height += this.centerBg.getPadding("tb");
30722 syncBodyHeight : function()
30724 var bd = this.body, // the text
30725 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
30727 var height = this.size.height - this.getHeaderFooterHeight(false);
30728 bd.setHeight(height-bd.getMargins("tb"));
30729 var hh = this.header.getHeight();
30730 var h = this.size.height-hh;
30733 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
30734 bw.setHeight(h-cb.getPadding("tb"));
30736 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
30737 bd.setWidth(bw.getWidth(true));
30739 this.tabs.syncHeight();
30741 this.tabs.el.repaint();
30747 * Restores the previous state of the dialog if Roo.state is configured.
30748 * @return {Roo.BasicDialog} this
30750 restoreState : function(){
30751 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
30752 if(box && box.width){
30753 this.xy = [box.x, box.y];
30754 this.resizeTo(box.width, box.height);
30760 beforeShow : function(){
30762 if(this.fixedcenter){
30763 this.xy = this.el.getCenterXY(true);
30766 Roo.get(document.body).addClass("x-body-masked");
30767 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30770 this.constrainXY();
30774 animShow : function(){
30775 var b = Roo.get(this.animateTarget).getBox();
30776 this.proxy.setSize(b.width, b.height);
30777 this.proxy.setLocation(b.x, b.y);
30779 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
30780 true, .35, this.showEl.createDelegate(this));
30784 * Shows the dialog.
30785 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
30786 * @return {Roo.BasicDialog} this
30788 show : function(animateTarget){
30789 if (this.fireEvent("beforeshow", this) === false){
30792 if(this.syncHeightBeforeShow){
30793 this.syncBodyHeight();
30794 }else if(this.firstShow){
30795 this.firstShow = false;
30796 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
30798 this.animateTarget = animateTarget || this.animateTarget;
30799 if(!this.el.isVisible()){
30801 if(this.animateTarget && Roo.get(this.animateTarget)){
30811 showEl : function(){
30813 this.el.setXY(this.xy);
30815 this.adjustAssets(true);
30818 // IE peekaboo bug - fix found by Dave Fenwick
30822 this.fireEvent("show", this);
30826 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
30827 * dialog itself will receive focus.
30829 focus : function(){
30830 if(this.defaultButton){
30831 this.defaultButton.focus();
30833 this.focusEl.focus();
30838 constrainXY : function(){
30839 if(this.constraintoviewport !== false){
30840 if(!this.viewSize){
30841 if(this.container){
30842 var s = this.container.getSize();
30843 this.viewSize = [s.width, s.height];
30845 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
30848 var s = Roo.get(this.container||document).getScroll();
30850 var x = this.xy[0], y = this.xy[1];
30851 var w = this.size.width, h = this.size.height;
30852 var vw = this.viewSize[0], vh = this.viewSize[1];
30853 // only move it if it needs it
30855 // first validate right/bottom
30856 if(x + w > vw+s.left){
30860 if(y + h > vh+s.top){
30864 // then make sure top/left isn't negative
30876 if(this.isVisible()){
30877 this.el.setLocation(x, y);
30878 this.adjustAssets();
30885 onDrag : function(){
30886 if(!this.proxyDrag){
30887 this.xy = this.el.getXY();
30888 this.adjustAssets();
30893 adjustAssets : function(doShow){
30894 var x = this.xy[0], y = this.xy[1];
30895 var w = this.size.width, h = this.size.height;
30896 if(doShow === true){
30898 this.shadow.show(this.el);
30904 if(this.shadow && this.shadow.isVisible()){
30905 this.shadow.show(this.el);
30907 if(this.shim && this.shim.isVisible()){
30908 this.shim.setBounds(x, y, w, h);
30913 adjustViewport : function(w, h){
30915 w = Roo.lib.Dom.getViewWidth();
30916 h = Roo.lib.Dom.getViewHeight();
30919 this.viewSize = [w, h];
30920 if(this.modal && this.mask.isVisible()){
30921 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
30922 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30924 if(this.isVisible()){
30925 this.constrainXY();
30930 * Destroys this dialog and all its supporting elements (including any tabs, shim,
30931 * shadow, proxy, mask, etc.) Also removes all event listeners.
30932 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
30934 destroy : function(removeEl){
30935 if(this.isVisible()){
30936 this.animateTarget = null;
30939 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
30941 this.tabs.destroy(removeEl);
30954 for(var i = 0, len = this.buttons.length; i < len; i++){
30955 this.buttons[i].destroy();
30958 this.el.removeAllListeners();
30959 if(removeEl === true){
30960 this.el.update("");
30963 Roo.DialogManager.unregister(this);
30967 startMove : function(){
30968 if(this.proxyDrag){
30971 if(this.constraintoviewport !== false){
30972 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
30977 endMove : function(){
30978 if(!this.proxyDrag){
30979 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
30981 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
30984 this.refreshSize();
30985 this.adjustAssets();
30987 this.fireEvent("move", this, this.xy[0], this.xy[1]);
30991 * Brings this dialog to the front of any other visible dialogs
30992 * @return {Roo.BasicDialog} this
30994 toFront : function(){
30995 Roo.DialogManager.bringToFront(this);
31000 * Sends this dialog to the back (under) of any other visible dialogs
31001 * @return {Roo.BasicDialog} this
31003 toBack : function(){
31004 Roo.DialogManager.sendToBack(this);
31009 * Centers this dialog in the viewport
31010 * @return {Roo.BasicDialog} this
31012 center : function(){
31013 var xy = this.el.getCenterXY(true);
31014 this.moveTo(xy[0], xy[1]);
31019 * Moves the dialog's top-left corner to the specified point
31020 * @param {Number} x
31021 * @param {Number} y
31022 * @return {Roo.BasicDialog} this
31024 moveTo : function(x, y){
31026 if(this.isVisible()){
31027 this.el.setXY(this.xy);
31028 this.adjustAssets();
31034 * Aligns the dialog to the specified element
31035 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31036 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
31037 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31038 * @return {Roo.BasicDialog} this
31040 alignTo : function(element, position, offsets){
31041 this.xy = this.el.getAlignToXY(element, position, offsets);
31042 if(this.isVisible()){
31043 this.el.setXY(this.xy);
31044 this.adjustAssets();
31050 * Anchors an element to another element and realigns it when the window is resized.
31051 * @param {String/HTMLElement/Roo.Element} element The element to align to.
31052 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
31053 * @param {Array} offsets (optional) Offset the positioning by [x, y]
31054 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
31055 * is a number, it is used as the buffer delay (defaults to 50ms).
31056 * @return {Roo.BasicDialog} this
31058 anchorTo : function(el, alignment, offsets, monitorScroll){
31059 var action = function(){
31060 this.alignTo(el, alignment, offsets);
31062 Roo.EventManager.onWindowResize(action, this);
31063 var tm = typeof monitorScroll;
31064 if(tm != 'undefined'){
31065 Roo.EventManager.on(window, 'scroll', action, this,
31066 {buffer: tm == 'number' ? monitorScroll : 50});
31073 * Returns true if the dialog is visible
31074 * @return {Boolean}
31076 isVisible : function(){
31077 return this.el.isVisible();
31081 animHide : function(callback){
31082 var b = Roo.get(this.animateTarget).getBox();
31084 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
31086 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
31087 this.hideEl.createDelegate(this, [callback]));
31091 * Hides the dialog.
31092 * @param {Function} callback (optional) Function to call when the dialog is hidden
31093 * @return {Roo.BasicDialog} this
31095 hide : function(callback){
31096 if (this.fireEvent("beforehide", this) === false){
31100 this.shadow.hide();
31105 // sometimes animateTarget seems to get set.. causing problems...
31106 // this just double checks..
31107 if(this.animateTarget && Roo.get(this.animateTarget)) {
31108 this.animHide(callback);
31111 this.hideEl(callback);
31117 hideEl : function(callback){
31121 Roo.get(document.body).removeClass("x-body-masked");
31123 this.fireEvent("hide", this);
31124 if(typeof callback == "function"){
31130 hideAction : function(){
31131 this.setLeft("-10000px");
31132 this.setTop("-10000px");
31133 this.setStyle("visibility", "hidden");
31137 refreshSize : function(){
31138 this.size = this.el.getSize();
31139 this.xy = this.el.getXY();
31140 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
31144 // z-index is managed by the DialogManager and may be overwritten at any time
31145 setZIndex : function(index){
31147 this.mask.setStyle("z-index", index);
31150 this.shim.setStyle("z-index", ++index);
31153 this.shadow.setZIndex(++index);
31155 this.el.setStyle("z-index", ++index);
31157 this.proxy.setStyle("z-index", ++index);
31160 this.resizer.proxy.setStyle("z-index", ++index);
31163 this.lastZIndex = index;
31167 * Returns the element for this dialog
31168 * @return {Roo.Element} The underlying dialog Element
31170 getEl : function(){
31176 * @class Roo.DialogManager
31177 * Provides global access to BasicDialogs that have been created and
31178 * support for z-indexing (layering) multiple open dialogs.
31180 Roo.DialogManager = function(){
31182 var accessList = [];
31186 var sortDialogs = function(d1, d2){
31187 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
31191 var orderDialogs = function(){
31192 accessList.sort(sortDialogs);
31193 var seed = Roo.DialogManager.zseed;
31194 for(var i = 0, len = accessList.length; i < len; i++){
31195 var dlg = accessList[i];
31197 dlg.setZIndex(seed + (i*10));
31204 * The starting z-index for BasicDialogs (defaults to 9000)
31205 * @type Number The z-index value
31210 register : function(dlg){
31211 list[dlg.id] = dlg;
31212 accessList.push(dlg);
31216 unregister : function(dlg){
31217 delete list[dlg.id];
31220 if(!accessList.indexOf){
31221 for( i = 0, len = accessList.length; i < len; i++){
31222 if(accessList[i] == dlg){
31223 accessList.splice(i, 1);
31228 i = accessList.indexOf(dlg);
31230 accessList.splice(i, 1);
31236 * Gets a registered dialog by id
31237 * @param {String/Object} id The id of the dialog or a dialog
31238 * @return {Roo.BasicDialog} this
31240 get : function(id){
31241 return typeof id == "object" ? id : list[id];
31245 * Brings the specified dialog to the front
31246 * @param {String/Object} dlg The id of the dialog or a dialog
31247 * @return {Roo.BasicDialog} this
31249 bringToFront : function(dlg){
31250 dlg = this.get(dlg);
31253 dlg._lastAccess = new Date().getTime();
31260 * Sends the specified dialog to the back
31261 * @param {String/Object} dlg The id of the dialog or a dialog
31262 * @return {Roo.BasicDialog} this
31264 sendToBack : function(dlg){
31265 dlg = this.get(dlg);
31266 dlg._lastAccess = -(new Date().getTime());
31272 * Hides all dialogs
31274 hideAll : function(){
31275 for(var id in list){
31276 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
31285 * @class Roo.LayoutDialog
31286 * @extends Roo.BasicDialog
31287 * Dialog which provides adjustments for working with a layout in a Dialog.
31288 * Add your necessary layout config options to the dialog's config.<br>
31289 * Example usage (including a nested layout):
31292 dialog = new Roo.LayoutDialog("download-dlg", {
31301 // layout config merges with the dialog config
31303 tabPosition: "top",
31304 alwaysShowTabs: true
31307 dialog.addKeyListener(27, dialog.hide, dialog);
31308 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
31309 dialog.addButton("Build It!", this.getDownload, this);
31311 // we can even add nested layouts
31312 var innerLayout = new Roo.BorderLayout("dl-inner", {
31322 innerLayout.beginUpdate();
31323 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
31324 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
31325 innerLayout.endUpdate(true);
31327 var layout = dialog.getLayout();
31328 layout.beginUpdate();
31329 layout.add("center", new Roo.ContentPanel("standard-panel",
31330 {title: "Download the Source", fitToFrame:true}));
31331 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
31332 {title: "Build your own roo.js"}));
31333 layout.getRegion("center").showPanel(sp);
31334 layout.endUpdate();
31338 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
31339 * @param {Object} config configuration options
31341 Roo.LayoutDialog = function(el, cfg){
31344 if (typeof(cfg) == 'undefined') {
31345 config = Roo.apply({}, el);
31346 // not sure why we use documentElement here.. - it should always be body.
31347 // IE7 borks horribly if we use documentElement.
31348 // webkit also does not like documentElement - it creates a body element...
31349 el = Roo.get( document.body || document.documentElement ).createChild();
31350 //config.autoCreate = true;
31354 config.autoTabs = false;
31355 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
31356 this.body.setStyle({overflow:"hidden", position:"relative"});
31357 this.layout = new Roo.BorderLayout(this.body.dom, config);
31358 this.layout.monitorWindowResize = false;
31359 this.el.addClass("x-dlg-auto-layout");
31360 // fix case when center region overwrites center function
31361 this.center = Roo.BasicDialog.prototype.center;
31362 this.on("show", this.layout.layout, this.layout, true);
31363 if (config.items) {
31364 var xitems = config.items;
31365 delete config.items;
31366 Roo.each(xitems, this.addxtype, this);
31371 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
31373 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
31376 endUpdate : function(){
31377 this.layout.endUpdate();
31381 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
31384 beginUpdate : function(){
31385 this.layout.beginUpdate();
31389 * Get the BorderLayout for this dialog
31390 * @return {Roo.BorderLayout}
31392 getLayout : function(){
31393 return this.layout;
31396 showEl : function(){
31397 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
31399 this.layout.layout();
31404 // Use the syncHeightBeforeShow config option to control this automatically
31405 syncBodyHeight : function(){
31406 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
31407 if(this.layout){this.layout.layout();}
31411 * Add an xtype element (actually adds to the layout.)
31412 * @return {Object} xdata xtype object data.
31415 addxtype : function(c) {
31416 return this.layout.addxtype(c);
31420 * Ext JS Library 1.1.1
31421 * Copyright(c) 2006-2007, Ext JS, LLC.
31423 * Originally Released Under LGPL - original licence link has changed is not relivant.
31426 * <script type="text/javascript">
31430 * @class Roo.MessageBox
31431 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
31435 Roo.Msg.alert('Status', 'Changes saved successfully.');
31437 // Prompt for user data:
31438 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
31440 // process text value...
31444 // Show a dialog using config options:
31446 title:'Save Changes?',
31447 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
31448 buttons: Roo.Msg.YESNOCANCEL,
31455 Roo.MessageBox = function(){
31456 var dlg, opt, mask, waitTimer;
31457 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
31458 var buttons, activeTextEl, bwidth;
31461 var handleButton = function(button){
31463 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
31467 var handleHide = function(){
31468 if(opt && opt.cls){
31469 dlg.el.removeClass(opt.cls);
31472 Roo.TaskMgr.stop(waitTimer);
31478 var updateButtons = function(b){
31481 buttons["ok"].hide();
31482 buttons["cancel"].hide();
31483 buttons["yes"].hide();
31484 buttons["no"].hide();
31485 dlg.footer.dom.style.display = 'none';
31488 dlg.footer.dom.style.display = '';
31489 for(var k in buttons){
31490 if(typeof buttons[k] != "function"){
31493 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
31494 width += buttons[k].el.getWidth()+15;
31504 var handleEsc = function(d, k, e){
31505 if(opt && opt.closable !== false){
31515 * Returns a reference to the underlying {@link Roo.BasicDialog} element
31516 * @return {Roo.BasicDialog} The BasicDialog element
31518 getDialog : function(){
31520 dlg = new Roo.BasicDialog("x-msg-box", {
31525 constraintoviewport:false,
31527 collapsible : false,
31530 width:400, height:100,
31531 buttonAlign:"center",
31532 closeClick : function(){
31533 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
31534 handleButton("no");
31536 handleButton("cancel");
31540 dlg.on("hide", handleHide);
31542 dlg.addKeyListener(27, handleEsc);
31544 var bt = this.buttonText;
31545 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
31546 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
31547 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
31548 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
31549 bodyEl = dlg.body.createChild({
31551 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
31553 msgEl = bodyEl.dom.firstChild;
31554 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
31555 textboxEl.enableDisplayMode();
31556 textboxEl.addKeyListener([10,13], function(){
31557 if(dlg.isVisible() && opt && opt.buttons){
31558 if(opt.buttons.ok){
31559 handleButton("ok");
31560 }else if(opt.buttons.yes){
31561 handleButton("yes");
31565 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
31566 textareaEl.enableDisplayMode();
31567 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
31568 progressEl.enableDisplayMode();
31569 var pf = progressEl.dom.firstChild;
31571 pp = Roo.get(pf.firstChild);
31572 pp.setHeight(pf.offsetHeight);
31580 * Updates the message box body text
31581 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
31582 * the XHTML-compliant non-breaking space character '&#160;')
31583 * @return {Roo.MessageBox} This message box
31585 updateText : function(text){
31586 if(!dlg.isVisible() && !opt.width){
31587 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
31589 msgEl.innerHTML = text || ' ';
31591 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
31592 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
31594 Math.min(opt.width || cw , this.maxWidth),
31595 Math.max(opt.minWidth || this.minWidth, bwidth)
31598 activeTextEl.setWidth(w);
31600 if(dlg.isVisible()){
31601 dlg.fixedcenter = false;
31603 // to big, make it scroll. = But as usual stupid IE does not support
31606 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
31607 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
31608 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
31610 bodyEl.dom.style.height = '';
31611 bodyEl.dom.style.overflowY = '';
31614 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
31616 bodyEl.dom.style.overflowX = '';
31619 dlg.setContentSize(w, bodyEl.getHeight());
31620 if(dlg.isVisible()){
31621 dlg.fixedcenter = true;
31627 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
31628 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
31629 * @param {Number} value Any number between 0 and 1 (e.g., .5)
31630 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
31631 * @return {Roo.MessageBox} This message box
31633 updateProgress : function(value, text){
31635 this.updateText(text);
31637 if (pp) { // weird bug on my firefox - for some reason this is not defined
31638 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
31644 * Returns true if the message box is currently displayed
31645 * @return {Boolean} True if the message box is visible, else false
31647 isVisible : function(){
31648 return dlg && dlg.isVisible();
31652 * Hides the message box if it is displayed
31655 if(this.isVisible()){
31661 * Displays a new message box, or reinitializes an existing message box, based on the config options
31662 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
31663 * The following config object properties are supported:
31665 Property Type Description
31666 ---------- --------------- ------------------------------------------------------------------------------------
31667 animEl String/Element An id or Element from which the message box should animate as it opens and
31668 closes (defaults to undefined)
31669 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
31670 cancel:'Bar'}), or false to not show any buttons (defaults to false)
31671 closable Boolean False to hide the top-right close button (defaults to true). Note that
31672 progress and wait dialogs will ignore this property and always hide the
31673 close button as they can only be closed programmatically.
31674 cls String A custom CSS class to apply to the message box element
31675 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
31676 displayed (defaults to 75)
31677 fn Function A callback function to execute after closing the dialog. The arguments to the
31678 function will be btn (the name of the button that was clicked, if applicable,
31679 e.g. "ok"), and text (the value of the active text field, if applicable).
31680 Progress and wait dialogs will ignore this option since they do not respond to
31681 user actions and can only be closed programmatically, so any required function
31682 should be called by the same code after it closes the dialog.
31683 icon String A CSS class that provides a background image to be used as an icon for
31684 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
31685 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
31686 minWidth Number The minimum width in pixels of the message box (defaults to 100)
31687 modal Boolean False to allow user interaction with the page while the message box is
31688 displayed (defaults to true)
31689 msg String A string that will replace the existing message box body text (defaults
31690 to the XHTML-compliant non-breaking space character ' ')
31691 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
31692 progress Boolean True to display a progress bar (defaults to false)
31693 progressText String The text to display inside the progress bar if progress = true (defaults to '')
31694 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
31695 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
31696 title String The title text
31697 value String The string value to set into the active textbox element if displayed
31698 wait Boolean True to display a progress bar (defaults to false)
31699 width Number The width of the dialog in pixels
31706 msg: 'Please enter your address:',
31708 buttons: Roo.MessageBox.OKCANCEL,
31711 animEl: 'addAddressBtn'
31714 * @param {Object} config Configuration options
31715 * @return {Roo.MessageBox} This message box
31717 show : function(options)
31720 // this causes nightmares if you show one dialog after another
31721 // especially on callbacks..
31723 if(this.isVisible()){
31726 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
31727 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
31728 Roo.log("New Dialog Message:" + options.msg )
31729 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
31730 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
31733 var d = this.getDialog();
31735 d.setTitle(opt.title || " ");
31736 d.close.setDisplayed(opt.closable !== false);
31737 activeTextEl = textboxEl;
31738 opt.prompt = opt.prompt || (opt.multiline ? true : false);
31743 textareaEl.setHeight(typeof opt.multiline == "number" ?
31744 opt.multiline : this.defaultTextHeight);
31745 activeTextEl = textareaEl;
31754 progressEl.setDisplayed(opt.progress === true);
31755 this.updateProgress(0);
31756 activeTextEl.dom.value = opt.value || "";
31758 dlg.setDefaultButton(activeTextEl);
31760 var bs = opt.buttons;
31763 db = buttons["ok"];
31764 }else if(bs && bs.yes){
31765 db = buttons["yes"];
31767 dlg.setDefaultButton(db);
31769 bwidth = updateButtons(opt.buttons);
31770 this.updateText(opt.msg);
31772 d.el.addClass(opt.cls);
31774 d.proxyDrag = opt.proxyDrag === true;
31775 d.modal = opt.modal !== false;
31776 d.mask = opt.modal !== false ? mask : false;
31777 if(!d.isVisible()){
31778 // force it to the end of the z-index stack so it gets a cursor in FF
31779 document.body.appendChild(dlg.el.dom);
31780 d.animateTarget = null;
31781 d.show(options.animEl);
31787 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
31788 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
31789 * and closing the message box when the process is complete.
31790 * @param {String} title The title bar text
31791 * @param {String} msg The message box body text
31792 * @return {Roo.MessageBox} This message box
31794 progress : function(title, msg){
31801 minWidth: this.minProgressWidth,
31808 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
31809 * If a callback function is passed it will be called after the user clicks the button, and the
31810 * id of the button that was clicked will be passed as the only parameter to the callback
31811 * (could also be the top-right close button).
31812 * @param {String} title The title bar text
31813 * @param {String} msg The message box body text
31814 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31815 * @param {Object} scope (optional) The scope of the callback function
31816 * @return {Roo.MessageBox} This message box
31818 alert : function(title, msg, fn, scope){
31831 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
31832 * interaction while waiting for a long-running process to complete that does not have defined intervals.
31833 * You are responsible for closing the message box when the process is complete.
31834 * @param {String} msg The message box body text
31835 * @param {String} title (optional) The title bar text
31836 * @return {Roo.MessageBox} This message box
31838 wait : function(msg, title){
31849 waitTimer = Roo.TaskMgr.start({
31851 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
31859 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
31860 * If a callback function is passed it will be called after the user clicks either button, and the id of the
31861 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
31862 * @param {String} title The title bar text
31863 * @param {String} msg The message box body text
31864 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31865 * @param {Object} scope (optional) The scope of the callback function
31866 * @return {Roo.MessageBox} This message box
31868 confirm : function(title, msg, fn, scope){
31872 buttons: this.YESNO,
31881 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
31882 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
31883 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
31884 * (could also be the top-right close button) and the text that was entered will be passed as the two
31885 * parameters to the callback.
31886 * @param {String} title The title bar text
31887 * @param {String} msg The message box body text
31888 * @param {Function} fn (optional) The callback function invoked after the message box is closed
31889 * @param {Object} scope (optional) The scope of the callback function
31890 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
31891 * property, or the height in pixels to create the textbox (defaults to false / single-line)
31892 * @return {Roo.MessageBox} This message box
31894 prompt : function(title, msg, fn, scope, multiline){
31898 buttons: this.OKCANCEL,
31903 multiline: multiline,
31910 * Button config that displays a single OK button
31915 * Button config that displays Yes and No buttons
31918 YESNO : {yes:true, no:true},
31920 * Button config that displays OK and Cancel buttons
31923 OKCANCEL : {ok:true, cancel:true},
31925 * Button config that displays Yes, No and Cancel buttons
31928 YESNOCANCEL : {yes:true, no:true, cancel:true},
31931 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
31934 defaultTextHeight : 75,
31936 * The maximum width in pixels of the message box (defaults to 600)
31941 * The minimum width in pixels of the message box (defaults to 100)
31946 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
31947 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
31950 minProgressWidth : 250,
31952 * An object containing the default button text strings that can be overriden for localized language support.
31953 * Supported properties are: ok, cancel, yes and no.
31954 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
31967 * Shorthand for {@link Roo.MessageBox}
31969 Roo.Msg = Roo.MessageBox;/*
31971 * Ext JS Library 1.1.1
31972 * Copyright(c) 2006-2007, Ext JS, LLC.
31974 * Originally Released Under LGPL - original licence link has changed is not relivant.
31977 * <script type="text/javascript">
31980 * @class Roo.QuickTips
31981 * Provides attractive and customizable tooltips for any element.
31984 Roo.QuickTips = function(){
31985 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
31986 var ce, bd, xy, dd;
31987 var visible = false, disabled = true, inited = false;
31988 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
31990 var onOver = function(e){
31994 var t = e.getTarget();
31995 if(!t || t.nodeType !== 1 || t == document || t == document.body){
31998 if(ce && t == ce.el){
31999 clearTimeout(hideProc);
32002 if(t && tagEls[t.id]){
32003 tagEls[t.id].el = t;
32004 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
32007 var ttp, et = Roo.fly(t);
32008 var ns = cfg.namespace;
32009 if(tm.interceptTitles && t.title){
32012 t.removeAttribute("title");
32013 e.preventDefault();
32015 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
32018 showProc = show.defer(tm.showDelay, tm, [{
32021 width: et.getAttributeNS(ns, cfg.width),
32022 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
32023 title: et.getAttributeNS(ns, cfg.title),
32024 cls: et.getAttributeNS(ns, cfg.cls)
32029 var onOut = function(e){
32030 clearTimeout(showProc);
32031 var t = e.getTarget();
32032 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
32033 hideProc = setTimeout(hide, tm.hideDelay);
32037 var onMove = function(e){
32043 if(tm.trackMouse && ce){
32048 var onDown = function(e){
32049 clearTimeout(showProc);
32050 clearTimeout(hideProc);
32052 if(tm.hideOnClick){
32055 tm.enable.defer(100, tm);
32060 var getPad = function(){
32061 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
32064 var show = function(o){
32068 clearTimeout(dismissProc);
32070 if(removeCls){ // in case manually hidden
32071 el.removeClass(removeCls);
32075 el.addClass(ce.cls);
32076 removeCls = ce.cls;
32079 tipTitle.update(ce.title);
32082 tipTitle.update('');
32085 el.dom.style.width = tm.maxWidth+'px';
32086 //tipBody.dom.style.width = '';
32087 tipBodyText.update(o.text);
32088 var p = getPad(), w = ce.width;
32090 var td = tipBodyText.dom;
32091 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
32092 if(aw > tm.maxWidth){
32094 }else if(aw < tm.minWidth){
32100 //tipBody.setWidth(w);
32101 el.setWidth(parseInt(w, 10) + p);
32102 if(ce.autoHide === false){
32103 close.setDisplayed(true);
32108 close.setDisplayed(false);
32114 el.avoidY = xy[1]-18;
32119 el.setStyle("visibility", "visible");
32120 el.fadeIn({callback: afterShow});
32126 var afterShow = function(){
32130 if(tm.autoDismiss && ce.autoHide !== false){
32131 dismissProc = setTimeout(hide, tm.autoDismissDelay);
32136 var hide = function(noanim){
32137 clearTimeout(dismissProc);
32138 clearTimeout(hideProc);
32140 if(el.isVisible()){
32142 if(noanim !== true && tm.animate){
32143 el.fadeOut({callback: afterHide});
32150 var afterHide = function(){
32153 el.removeClass(removeCls);
32160 * @cfg {Number} minWidth
32161 * The minimum width of the quick tip (defaults to 40)
32165 * @cfg {Number} maxWidth
32166 * The maximum width of the quick tip (defaults to 300)
32170 * @cfg {Boolean} interceptTitles
32171 * True to automatically use the element's DOM title value if available (defaults to false)
32173 interceptTitles : false,
32175 * @cfg {Boolean} trackMouse
32176 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
32178 trackMouse : false,
32180 * @cfg {Boolean} hideOnClick
32181 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
32183 hideOnClick : true,
32185 * @cfg {Number} showDelay
32186 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
32190 * @cfg {Number} hideDelay
32191 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
32195 * @cfg {Boolean} autoHide
32196 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
32197 * Used in conjunction with hideDelay.
32202 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
32203 * (defaults to true). Used in conjunction with autoDismissDelay.
32205 autoDismiss : true,
32208 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
32210 autoDismissDelay : 5000,
32212 * @cfg {Boolean} animate
32213 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
32218 * @cfg {String} title
32219 * Title text to display (defaults to ''). This can be any valid HTML markup.
32223 * @cfg {String} text
32224 * Body text to display (defaults to ''). This can be any valid HTML markup.
32228 * @cfg {String} cls
32229 * A CSS class to apply to the base quick tip element (defaults to '').
32233 * @cfg {Number} width
32234 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
32235 * minWidth or maxWidth.
32240 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
32241 * or display QuickTips in a page.
32244 tm = Roo.QuickTips;
32245 cfg = tm.tagConfig;
32247 if(!Roo.isReady){ // allow calling of init() before onReady
32248 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
32251 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
32252 el.fxDefaults = {stopFx: true};
32253 // maximum custom styling
32254 //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
32255 el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');
32256 tipTitle = el.child('h3');
32257 tipTitle.enableDisplayMode("block");
32258 tipBody = el.child('div.x-tip-bd');
32259 tipBodyText = el.child('div.x-tip-bd-inner');
32260 //bdLeft = el.child('div.x-tip-bd-left');
32261 //bdRight = el.child('div.x-tip-bd-right');
32262 close = el.child('div.x-tip-close');
32263 close.enableDisplayMode("block");
32264 close.on("click", hide);
32265 var d = Roo.get(document);
32266 d.on("mousedown", onDown);
32267 d.on("mouseover", onOver);
32268 d.on("mouseout", onOut);
32269 d.on("mousemove", onMove);
32270 esc = d.addKeyListener(27, hide);
32273 dd = el.initDD("default", null, {
32274 onDrag : function(){
32278 dd.setHandleElId(tipTitle.id);
32287 * Configures a new quick tip instance and assigns it to a target element. The following config options
32290 Property Type Description
32291 ---------- --------------------- ------------------------------------------------------------------------
32292 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
32294 * @param {Object} config The config object
32296 register : function(config){
32297 var cs = config instanceof Array ? config : arguments;
32298 for(var i = 0, len = cs.length; i < len; i++) {
32300 var target = c.target;
32302 if(target instanceof Array){
32303 for(var j = 0, jlen = target.length; j < jlen; j++){
32304 tagEls[target[j]] = c;
32307 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
32314 * Removes this quick tip from its element and destroys it.
32315 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
32317 unregister : function(el){
32318 delete tagEls[Roo.id(el)];
32322 * Enable this quick tip.
32324 enable : function(){
32325 if(inited && disabled){
32327 if(locks.length < 1){
32334 * Disable this quick tip.
32336 disable : function(){
32338 clearTimeout(showProc);
32339 clearTimeout(hideProc);
32340 clearTimeout(dismissProc);
32348 * Returns true if the quick tip is enabled, else false.
32350 isEnabled : function(){
32357 attribute : "qtip",
32367 // backwards compat
32368 Roo.QuickTips.tips = Roo.QuickTips.register;/*
32370 * Ext JS Library 1.1.1
32371 * Copyright(c) 2006-2007, Ext JS, LLC.
32373 * Originally Released Under LGPL - original licence link has changed is not relivant.
32376 * <script type="text/javascript">
32381 * @class Roo.tree.TreePanel
32382 * @extends Roo.data.Tree
32384 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
32385 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
32386 * @cfg {Boolean} enableDD true to enable drag and drop
32387 * @cfg {Boolean} enableDrag true to enable just drag
32388 * @cfg {Boolean} enableDrop true to enable just drop
32389 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
32390 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
32391 * @cfg {String} ddGroup The DD group this TreePanel belongs to
32392 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
32393 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
32394 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
32395 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
32396 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
32397 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
32398 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
32399 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
32400 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
32401 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
32402 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
32403 * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
32404 * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
32407 * @param {String/HTMLElement/Element} el The container element
32408 * @param {Object} config
32410 Roo.tree.TreePanel = function(el, config){
32412 var loader = false;
32414 root = config.root;
32415 delete config.root;
32417 if (config.loader) {
32418 loader = config.loader;
32419 delete config.loader;
32422 Roo.apply(this, config);
32423 Roo.tree.TreePanel.superclass.constructor.call(this);
32424 this.el = Roo.get(el);
32425 this.el.addClass('x-tree');
32426 //console.log(root);
32428 this.setRootNode( Roo.factory(root, Roo.tree));
32431 this.loader = Roo.factory(loader, Roo.tree);
32434 * Read-only. The id of the container element becomes this TreePanel's id.
32436 this.id = this.el.id;
32439 * @event beforeload
32440 * Fires before a node is loaded, return false to cancel
32441 * @param {Node} node The node being loaded
32443 "beforeload" : true,
32446 * Fires when a node is loaded
32447 * @param {Node} node The node that was loaded
32451 * @event textchange
32452 * Fires when the text for a node is changed
32453 * @param {Node} node The node
32454 * @param {String} text The new text
32455 * @param {String} oldText The old text
32457 "textchange" : true,
32459 * @event beforeexpand
32460 * Fires before a node is expanded, return false to cancel.
32461 * @param {Node} node The node
32462 * @param {Boolean} deep
32463 * @param {Boolean} anim
32465 "beforeexpand" : true,
32467 * @event beforecollapse
32468 * Fires before a node is collapsed, return false to cancel.
32469 * @param {Node} node The node
32470 * @param {Boolean} deep
32471 * @param {Boolean} anim
32473 "beforecollapse" : true,
32476 * Fires when a node is expanded
32477 * @param {Node} node The node
32481 * @event disabledchange
32482 * Fires when the disabled status of a node changes
32483 * @param {Node} node The node
32484 * @param {Boolean} disabled
32486 "disabledchange" : true,
32489 * Fires when a node is collapsed
32490 * @param {Node} node The node
32494 * @event beforeclick
32495 * Fires before click processing on a node. Return false to cancel the default action.
32496 * @param {Node} node The node
32497 * @param {Roo.EventObject} e The event object
32499 "beforeclick":true,
32501 * @event checkchange
32502 * Fires when a node with a checkbox's checked property changes
32503 * @param {Node} this This node
32504 * @param {Boolean} checked
32506 "checkchange":true,
32509 * Fires when a node is clicked
32510 * @param {Node} node The node
32511 * @param {Roo.EventObject} e The event object
32516 * Fires when a node is double clicked
32517 * @param {Node} node The node
32518 * @param {Roo.EventObject} e The event object
32522 * @event contextmenu
32523 * Fires when a node is right clicked
32524 * @param {Node} node The node
32525 * @param {Roo.EventObject} e The event object
32527 "contextmenu":true,
32529 * @event beforechildrenrendered
32530 * Fires right before the child nodes for a node are rendered
32531 * @param {Node} node The node
32533 "beforechildrenrendered":true,
32536 * Fires when a node starts being dragged
32537 * @param {Roo.tree.TreePanel} this
32538 * @param {Roo.tree.TreeNode} node
32539 * @param {event} e The raw browser event
32541 "startdrag" : true,
32544 * Fires when a drag operation is complete
32545 * @param {Roo.tree.TreePanel} this
32546 * @param {Roo.tree.TreeNode} node
32547 * @param {event} e The raw browser event
32552 * Fires when a dragged node is dropped on a valid DD target
32553 * @param {Roo.tree.TreePanel} this
32554 * @param {Roo.tree.TreeNode} node
32555 * @param {DD} dd The dd it was dropped on
32556 * @param {event} e The raw browser event
32560 * @event beforenodedrop
32561 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
32562 * passed to handlers has the following properties:<br />
32563 * <ul style="padding:5px;padding-left:16px;">
32564 * <li>tree - The TreePanel</li>
32565 * <li>target - The node being targeted for the drop</li>
32566 * <li>data - The drag data from the drag source</li>
32567 * <li>point - The point of the drop - append, above or below</li>
32568 * <li>source - The drag source</li>
32569 * <li>rawEvent - Raw mouse event</li>
32570 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
32571 * to be inserted by setting them on this object.</li>
32572 * <li>cancel - Set this to true to cancel the drop.</li>
32574 * @param {Object} dropEvent
32576 "beforenodedrop" : true,
32579 * Fires after a DD object is dropped on a node in this tree. The dropEvent
32580 * passed to handlers has the following properties:<br />
32581 * <ul style="padding:5px;padding-left:16px;">
32582 * <li>tree - The TreePanel</li>
32583 * <li>target - The node being targeted for the drop</li>
32584 * <li>data - The drag data from the drag source</li>
32585 * <li>point - The point of the drop - append, above or below</li>
32586 * <li>source - The drag source</li>
32587 * <li>rawEvent - Raw mouse event</li>
32588 * <li>dropNode - Dropped node(s).</li>
32590 * @param {Object} dropEvent
32594 * @event nodedragover
32595 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
32596 * passed to handlers has the following properties:<br />
32597 * <ul style="padding:5px;padding-left:16px;">
32598 * <li>tree - The TreePanel</li>
32599 * <li>target - The node being targeted for the drop</li>
32600 * <li>data - The drag data from the drag source</li>
32601 * <li>point - The point of the drop - append, above or below</li>
32602 * <li>source - The drag source</li>
32603 * <li>rawEvent - Raw mouse event</li>
32604 * <li>dropNode - Drop node(s) provided by the source.</li>
32605 * <li>cancel - Set this to true to signal drop not allowed.</li>
32607 * @param {Object} dragOverEvent
32609 "nodedragover" : true
32612 if(this.singleExpand){
32613 this.on("beforeexpand", this.restrictExpand, this);
32616 this.editor.tree = this;
32617 this.editor = Roo.factory(this.editor, Roo.tree);
32620 if (this.selModel) {
32621 this.selModel = Roo.factory(this.selModel, Roo.tree);
32625 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
32626 rootVisible : true,
32627 animate: Roo.enableFx,
32630 hlDrop : Roo.enableFx,
32634 rendererTip: false,
32636 restrictExpand : function(node){
32637 var p = node.parentNode;
32639 if(p.expandedChild && p.expandedChild.parentNode == p){
32640 p.expandedChild.collapse();
32642 p.expandedChild = node;
32646 // private override
32647 setRootNode : function(node){
32648 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
32649 if(!this.rootVisible){
32650 node.ui = new Roo.tree.RootTreeNodeUI(node);
32656 * Returns the container element for this TreePanel
32658 getEl : function(){
32663 * Returns the default TreeLoader for this TreePanel
32665 getLoader : function(){
32666 return this.loader;
32672 expandAll : function(){
32673 this.root.expand(true);
32677 * Collapse all nodes
32679 collapseAll : function(){
32680 this.root.collapse(true);
32684 * Returns the selection model used by this TreePanel
32686 getSelectionModel : function(){
32687 if(!this.selModel){
32688 this.selModel = new Roo.tree.DefaultSelectionModel();
32690 return this.selModel;
32694 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
32695 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
32696 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
32699 getChecked : function(a, startNode){
32700 startNode = startNode || this.root;
32702 var f = function(){
32703 if(this.attributes.checked){
32704 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
32707 startNode.cascade(f);
32712 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32713 * @param {String} path
32714 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32715 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
32716 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
32718 expandPath : function(path, attr, callback){
32719 attr = attr || "id";
32720 var keys = path.split(this.pathSeparator);
32721 var curNode = this.root;
32722 if(curNode.attributes[attr] != keys[1]){ // invalid root
32724 callback(false, null);
32729 var f = function(){
32730 if(++index == keys.length){
32732 callback(true, curNode);
32736 var c = curNode.findChild(attr, keys[index]);
32739 callback(false, curNode);
32744 c.expand(false, false, f);
32746 curNode.expand(false, false, f);
32750 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
32751 * @param {String} path
32752 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
32753 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
32754 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
32756 selectPath : function(path, attr, callback){
32757 attr = attr || "id";
32758 var keys = path.split(this.pathSeparator);
32759 var v = keys.pop();
32760 if(keys.length > 0){
32761 var f = function(success, node){
32762 if(success && node){
32763 var n = node.findChild(attr, v);
32769 }else if(callback){
32770 callback(false, n);
32774 callback(false, n);
32778 this.expandPath(keys.join(this.pathSeparator), attr, f);
32780 this.root.select();
32782 callback(true, this.root);
32787 getTreeEl : function(){
32792 * Trigger rendering of this TreePanel
32794 render : function(){
32795 if (this.innerCt) {
32796 return this; // stop it rendering more than once!!
32799 this.innerCt = this.el.createChild({tag:"ul",
32800 cls:"x-tree-root-ct " +
32801 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
32803 if(this.containerScroll){
32804 Roo.dd.ScrollManager.register(this.el);
32806 if((this.enableDD || this.enableDrop) && !this.dropZone){
32808 * The dropZone used by this tree if drop is enabled
32809 * @type Roo.tree.TreeDropZone
32811 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
32812 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
32815 if((this.enableDD || this.enableDrag) && !this.dragZone){
32817 * The dragZone used by this tree if drag is enabled
32818 * @type Roo.tree.TreeDragZone
32820 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
32821 ddGroup: this.ddGroup || "TreeDD",
32822 scroll: this.ddScroll
32825 this.getSelectionModel().init(this);
32827 Roo.log("ROOT not set in tree");
32830 this.root.render();
32831 if(!this.rootVisible){
32832 this.root.renderChildren();
32838 * Ext JS Library 1.1.1
32839 * Copyright(c) 2006-2007, Ext JS, LLC.
32841 * Originally Released Under LGPL - original licence link has changed is not relivant.
32844 * <script type="text/javascript">
32849 * @class Roo.tree.DefaultSelectionModel
32850 * @extends Roo.util.Observable
32851 * The default single selection for a TreePanel.
32852 * @param {Object} cfg Configuration
32854 Roo.tree.DefaultSelectionModel = function(cfg){
32855 this.selNode = null;
32861 * @event selectionchange
32862 * Fires when the selected node changes
32863 * @param {DefaultSelectionModel} this
32864 * @param {TreeNode} node the new selection
32866 "selectionchange" : true,
32869 * @event beforeselect
32870 * Fires before the selected node changes, return false to cancel the change
32871 * @param {DefaultSelectionModel} this
32872 * @param {TreeNode} node the new selection
32873 * @param {TreeNode} node the old selection
32875 "beforeselect" : true
32878 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
32881 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
32882 init : function(tree){
32884 tree.getTreeEl().on("keydown", this.onKeyDown, this);
32885 tree.on("click", this.onNodeClick, this);
32888 onNodeClick : function(node, e){
32889 if (e.ctrlKey && this.selNode == node) {
32890 this.unselect(node);
32898 * @param {TreeNode} node The node to select
32899 * @return {TreeNode} The selected node
32901 select : function(node){
32902 var last = this.selNode;
32903 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
32905 last.ui.onSelectedChange(false);
32907 this.selNode = node;
32908 node.ui.onSelectedChange(true);
32909 this.fireEvent("selectionchange", this, node, last);
32916 * @param {TreeNode} node The node to unselect
32918 unselect : function(node){
32919 if(this.selNode == node){
32920 this.clearSelections();
32925 * Clear all selections
32927 clearSelections : function(){
32928 var n = this.selNode;
32930 n.ui.onSelectedChange(false);
32931 this.selNode = null;
32932 this.fireEvent("selectionchange", this, null);
32938 * Get the selected node
32939 * @return {TreeNode} The selected node
32941 getSelectedNode : function(){
32942 return this.selNode;
32946 * Returns true if the node is selected
32947 * @param {TreeNode} node The node to check
32948 * @return {Boolean}
32950 isSelected : function(node){
32951 return this.selNode == node;
32955 * Selects the node above the selected node in the tree, intelligently walking the nodes
32956 * @return TreeNode The new selection
32958 selectPrevious : function(){
32959 var s = this.selNode || this.lastSelNode;
32963 var ps = s.previousSibling;
32965 if(!ps.isExpanded() || ps.childNodes.length < 1){
32966 return this.select(ps);
32968 var lc = ps.lastChild;
32969 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
32972 return this.select(lc);
32974 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
32975 return this.select(s.parentNode);
32981 * Selects the node above the selected node in the tree, intelligently walking the nodes
32982 * @return TreeNode The new selection
32984 selectNext : function(){
32985 var s = this.selNode || this.lastSelNode;
32989 if(s.firstChild && s.isExpanded()){
32990 return this.select(s.firstChild);
32991 }else if(s.nextSibling){
32992 return this.select(s.nextSibling);
32993 }else if(s.parentNode){
32995 s.parentNode.bubble(function(){
32996 if(this.nextSibling){
32997 newS = this.getOwnerTree().selModel.select(this.nextSibling);
33006 onKeyDown : function(e){
33007 var s = this.selNode || this.lastSelNode;
33008 // undesirable, but required
33013 var k = e.getKey();
33021 this.selectPrevious();
33024 e.preventDefault();
33025 if(s.hasChildNodes()){
33026 if(!s.isExpanded()){
33028 }else if(s.firstChild){
33029 this.select(s.firstChild, e);
33034 e.preventDefault();
33035 if(s.hasChildNodes() && s.isExpanded()){
33037 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
33038 this.select(s.parentNode, e);
33046 * @class Roo.tree.MultiSelectionModel
33047 * @extends Roo.util.Observable
33048 * Multi selection for a TreePanel.
33049 * @param {Object} cfg Configuration
33051 Roo.tree.MultiSelectionModel = function(){
33052 this.selNodes = [];
33056 * @event selectionchange
33057 * Fires when the selected nodes change
33058 * @param {MultiSelectionModel} this
33059 * @param {Array} nodes Array of the selected nodes
33061 "selectionchange" : true
33063 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
33067 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
33068 init : function(tree){
33070 tree.getTreeEl().on("keydown", this.onKeyDown, this);
33071 tree.on("click", this.onNodeClick, this);
33074 onNodeClick : function(node, e){
33075 this.select(node, e, e.ctrlKey);
33080 * @param {TreeNode} node The node to select
33081 * @param {EventObject} e (optional) An event associated with the selection
33082 * @param {Boolean} keepExisting True to retain existing selections
33083 * @return {TreeNode} The selected node
33085 select : function(node, e, keepExisting){
33086 if(keepExisting !== true){
33087 this.clearSelections(true);
33089 if(this.isSelected(node)){
33090 this.lastSelNode = node;
33093 this.selNodes.push(node);
33094 this.selMap[node.id] = node;
33095 this.lastSelNode = node;
33096 node.ui.onSelectedChange(true);
33097 this.fireEvent("selectionchange", this, this.selNodes);
33103 * @param {TreeNode} node The node to unselect
33105 unselect : function(node){
33106 if(this.selMap[node.id]){
33107 node.ui.onSelectedChange(false);
33108 var sn = this.selNodes;
33111 index = sn.indexOf(node);
33113 for(var i = 0, len = sn.length; i < len; i++){
33121 this.selNodes.splice(index, 1);
33123 delete this.selMap[node.id];
33124 this.fireEvent("selectionchange", this, this.selNodes);
33129 * Clear all selections
33131 clearSelections : function(suppressEvent){
33132 var sn = this.selNodes;
33134 for(var i = 0, len = sn.length; i < len; i++){
33135 sn[i].ui.onSelectedChange(false);
33137 this.selNodes = [];
33139 if(suppressEvent !== true){
33140 this.fireEvent("selectionchange", this, this.selNodes);
33146 * Returns true if the node is selected
33147 * @param {TreeNode} node The node to check
33148 * @return {Boolean}
33150 isSelected : function(node){
33151 return this.selMap[node.id] ? true : false;
33155 * Returns an array of the selected nodes
33158 getSelectedNodes : function(){
33159 return this.selNodes;
33162 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
33164 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
33166 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
33169 * Ext JS Library 1.1.1
33170 * Copyright(c) 2006-2007, Ext JS, LLC.
33172 * Originally Released Under LGPL - original licence link has changed is not relivant.
33175 * <script type="text/javascript">
33179 * @class Roo.tree.TreeNode
33180 * @extends Roo.data.Node
33181 * @cfg {String} text The text for this node
33182 * @cfg {Boolean} expanded true to start the node expanded
33183 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
33184 * @cfg {Boolean} allowDrop false if this node cannot be drop on
33185 * @cfg {Boolean} disabled true to start the node disabled
33186 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
33187 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
33188 * @cfg {String} cls A css class to be added to the node
33189 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
33190 * @cfg {String} href URL of the link used for the node (defaults to #)
33191 * @cfg {String} hrefTarget target frame for the link
33192 * @cfg {String} qtip An Ext QuickTip for the node
33193 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
33194 * @cfg {Boolean} singleClickExpand True for single click expand on this node
33195 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
33196 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
33197 * (defaults to undefined with no checkbox rendered)
33199 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33201 Roo.tree.TreeNode = function(attributes){
33202 attributes = attributes || {};
33203 if(typeof attributes == "string"){
33204 attributes = {text: attributes};
33206 this.childrenRendered = false;
33207 this.rendered = false;
33208 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
33209 this.expanded = attributes.expanded === true;
33210 this.isTarget = attributes.isTarget !== false;
33211 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
33212 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
33215 * Read-only. The text for this node. To change it use setText().
33218 this.text = attributes.text;
33220 * True if this node is disabled.
33223 this.disabled = attributes.disabled === true;
33227 * @event textchange
33228 * Fires when the text for this node is changed
33229 * @param {Node} this This node
33230 * @param {String} text The new text
33231 * @param {String} oldText The old text
33233 "textchange" : true,
33235 * @event beforeexpand
33236 * Fires before this node is expanded, return false to cancel.
33237 * @param {Node} this This node
33238 * @param {Boolean} deep
33239 * @param {Boolean} anim
33241 "beforeexpand" : true,
33243 * @event beforecollapse
33244 * Fires before this node is collapsed, return false to cancel.
33245 * @param {Node} this This node
33246 * @param {Boolean} deep
33247 * @param {Boolean} anim
33249 "beforecollapse" : true,
33252 * Fires when this node is expanded
33253 * @param {Node} this This node
33257 * @event disabledchange
33258 * Fires when the disabled status of this node changes
33259 * @param {Node} this This node
33260 * @param {Boolean} disabled
33262 "disabledchange" : true,
33265 * Fires when this node is collapsed
33266 * @param {Node} this This node
33270 * @event beforeclick
33271 * Fires before click processing. Return false to cancel the default action.
33272 * @param {Node} this This node
33273 * @param {Roo.EventObject} e The event object
33275 "beforeclick":true,
33277 * @event checkchange
33278 * Fires when a node with a checkbox's checked property changes
33279 * @param {Node} this This node
33280 * @param {Boolean} checked
33282 "checkchange":true,
33285 * Fires when this node is clicked
33286 * @param {Node} this This node
33287 * @param {Roo.EventObject} e The event object
33292 * Fires when this node is double clicked
33293 * @param {Node} this This node
33294 * @param {Roo.EventObject} e The event object
33298 * @event contextmenu
33299 * Fires when this node is right clicked
33300 * @param {Node} this This node
33301 * @param {Roo.EventObject} e The event object
33303 "contextmenu":true,
33305 * @event beforechildrenrendered
33306 * Fires right before the child nodes for this node are rendered
33307 * @param {Node} this This node
33309 "beforechildrenrendered":true
33312 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
33315 * Read-only. The UI for this node
33318 this.ui = new uiClass(this);
33320 // finally support items[]
33321 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
33326 Roo.each(this.attributes.items, function(c) {
33327 this.appendChild(Roo.factory(c,Roo.Tree));
33329 delete this.attributes.items;
33334 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
33335 preventHScroll: true,
33337 * Returns true if this node is expanded
33338 * @return {Boolean}
33340 isExpanded : function(){
33341 return this.expanded;
33345 * Returns the UI object for this node
33346 * @return {TreeNodeUI}
33348 getUI : function(){
33352 // private override
33353 setFirstChild : function(node){
33354 var of = this.firstChild;
33355 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
33356 if(this.childrenRendered && of && node != of){
33357 of.renderIndent(true, true);
33360 this.renderIndent(true, true);
33364 // private override
33365 setLastChild : function(node){
33366 var ol = this.lastChild;
33367 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
33368 if(this.childrenRendered && ol && node != ol){
33369 ol.renderIndent(true, true);
33372 this.renderIndent(true, true);
33376 // these methods are overridden to provide lazy rendering support
33377 // private override
33378 appendChild : function()
33380 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
33381 if(node && this.childrenRendered){
33384 this.ui.updateExpandIcon();
33388 // private override
33389 removeChild : function(node){
33390 this.ownerTree.getSelectionModel().unselect(node);
33391 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
33392 // if it's been rendered remove dom node
33393 if(this.childrenRendered){
33396 if(this.childNodes.length < 1){
33397 this.collapse(false, false);
33399 this.ui.updateExpandIcon();
33401 if(!this.firstChild) {
33402 this.childrenRendered = false;
33407 // private override
33408 insertBefore : function(node, refNode){
33409 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
33410 if(newNode && refNode && this.childrenRendered){
33413 this.ui.updateExpandIcon();
33418 * Sets the text for this node
33419 * @param {String} text
33421 setText : function(text){
33422 var oldText = this.text;
33424 this.attributes.text = text;
33425 if(this.rendered){ // event without subscribing
33426 this.ui.onTextChange(this, text, oldText);
33428 this.fireEvent("textchange", this, text, oldText);
33432 * Triggers selection of this node
33434 select : function(){
33435 this.getOwnerTree().getSelectionModel().select(this);
33439 * Triggers deselection of this node
33441 unselect : function(){
33442 this.getOwnerTree().getSelectionModel().unselect(this);
33446 * Returns true if this node is selected
33447 * @return {Boolean}
33449 isSelected : function(){
33450 return this.getOwnerTree().getSelectionModel().isSelected(this);
33454 * Expand this node.
33455 * @param {Boolean} deep (optional) True to expand all children as well
33456 * @param {Boolean} anim (optional) false to cancel the default animation
33457 * @param {Function} callback (optional) A callback to be called when
33458 * expanding this node completes (does not wait for deep expand to complete).
33459 * Called with 1 parameter, this node.
33461 expand : function(deep, anim, callback){
33462 if(!this.expanded){
33463 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
33466 if(!this.childrenRendered){
33467 this.renderChildren();
33469 this.expanded = true;
33470 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
33471 this.ui.animExpand(function(){
33472 this.fireEvent("expand", this);
33473 if(typeof callback == "function"){
33477 this.expandChildNodes(true);
33479 }.createDelegate(this));
33483 this.fireEvent("expand", this);
33484 if(typeof callback == "function"){
33489 if(typeof callback == "function"){
33494 this.expandChildNodes(true);
33498 isHiddenRoot : function(){
33499 return this.isRoot && !this.getOwnerTree().rootVisible;
33503 * Collapse this node.
33504 * @param {Boolean} deep (optional) True to collapse all children as well
33505 * @param {Boolean} anim (optional) false to cancel the default animation
33507 collapse : function(deep, anim){
33508 if(this.expanded && !this.isHiddenRoot()){
33509 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
33512 this.expanded = false;
33513 if((this.getOwnerTree().animate && anim !== false) || anim){
33514 this.ui.animCollapse(function(){
33515 this.fireEvent("collapse", this);
33517 this.collapseChildNodes(true);
33519 }.createDelegate(this));
33522 this.ui.collapse();
33523 this.fireEvent("collapse", this);
33527 var cs = this.childNodes;
33528 for(var i = 0, len = cs.length; i < len; i++) {
33529 cs[i].collapse(true, false);
33535 delayedExpand : function(delay){
33536 if(!this.expandProcId){
33537 this.expandProcId = this.expand.defer(delay, this);
33542 cancelExpand : function(){
33543 if(this.expandProcId){
33544 clearTimeout(this.expandProcId);
33546 this.expandProcId = false;
33550 * Toggles expanded/collapsed state of the node
33552 toggle : function(){
33561 * Ensures all parent nodes are expanded
33563 ensureVisible : function(callback){
33564 var tree = this.getOwnerTree();
33565 tree.expandPath(this.parentNode.getPath(), false, function(){
33566 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
33567 Roo.callback(callback);
33568 }.createDelegate(this));
33572 * Expand all child nodes
33573 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
33575 expandChildNodes : function(deep){
33576 var cs = this.childNodes;
33577 for(var i = 0, len = cs.length; i < len; i++) {
33578 cs[i].expand(deep);
33583 * Collapse all child nodes
33584 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
33586 collapseChildNodes : function(deep){
33587 var cs = this.childNodes;
33588 for(var i = 0, len = cs.length; i < len; i++) {
33589 cs[i].collapse(deep);
33594 * Disables this node
33596 disable : function(){
33597 this.disabled = true;
33599 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33600 this.ui.onDisableChange(this, true);
33602 this.fireEvent("disabledchange", this, true);
33606 * Enables this node
33608 enable : function(){
33609 this.disabled = false;
33610 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
33611 this.ui.onDisableChange(this, false);
33613 this.fireEvent("disabledchange", this, false);
33617 renderChildren : function(suppressEvent){
33618 if(suppressEvent !== false){
33619 this.fireEvent("beforechildrenrendered", this);
33621 var cs = this.childNodes;
33622 for(var i = 0, len = cs.length; i < len; i++){
33623 cs[i].render(true);
33625 this.childrenRendered = true;
33629 sort : function(fn, scope){
33630 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
33631 if(this.childrenRendered){
33632 var cs = this.childNodes;
33633 for(var i = 0, len = cs.length; i < len; i++){
33634 cs[i].render(true);
33640 render : function(bulkRender){
33641 this.ui.render(bulkRender);
33642 if(!this.rendered){
33643 this.rendered = true;
33645 this.expanded = false;
33646 this.expand(false, false);
33652 renderIndent : function(deep, refresh){
33654 this.ui.childIndent = null;
33656 this.ui.renderIndent();
33657 if(deep === true && this.childrenRendered){
33658 var cs = this.childNodes;
33659 for(var i = 0, len = cs.length; i < len; i++){
33660 cs[i].renderIndent(true, refresh);
33666 * Ext JS Library 1.1.1
33667 * Copyright(c) 2006-2007, Ext JS, LLC.
33669 * Originally Released Under LGPL - original licence link has changed is not relivant.
33672 * <script type="text/javascript">
33676 * @class Roo.tree.AsyncTreeNode
33677 * @extends Roo.tree.TreeNode
33678 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
33680 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
33682 Roo.tree.AsyncTreeNode = function(config){
33683 this.loaded = false;
33684 this.loading = false;
33685 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
33687 * @event beforeload
33688 * Fires before this node is loaded, return false to cancel
33689 * @param {Node} this This node
33691 this.addEvents({'beforeload':true, 'load': true});
33694 * Fires when this node is loaded
33695 * @param {Node} this This node
33698 * The loader used by this node (defaults to using the tree's defined loader)
33703 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
33704 expand : function(deep, anim, callback){
33705 if(this.loading){ // if an async load is already running, waiting til it's done
33707 var f = function(){
33708 if(!this.loading){ // done loading
33709 clearInterval(timer);
33710 this.expand(deep, anim, callback);
33712 }.createDelegate(this);
33713 timer = setInterval(f, 200);
33717 if(this.fireEvent("beforeload", this) === false){
33720 this.loading = true;
33721 this.ui.beforeLoad(this);
33722 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
33724 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
33728 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
33732 * Returns true if this node is currently loading
33733 * @return {Boolean}
33735 isLoading : function(){
33736 return this.loading;
33739 loadComplete : function(deep, anim, callback){
33740 this.loading = false;
33741 this.loaded = true;
33742 this.ui.afterLoad(this);
33743 this.fireEvent("load", this);
33744 this.expand(deep, anim, callback);
33748 * Returns true if this node has been loaded
33749 * @return {Boolean}
33751 isLoaded : function(){
33752 return this.loaded;
33755 hasChildNodes : function(){
33756 if(!this.isLeaf() && !this.loaded){
33759 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
33764 * Trigger a reload for this node
33765 * @param {Function} callback
33767 reload : function(callback){
33768 this.collapse(false, false);
33769 while(this.firstChild){
33770 this.removeChild(this.firstChild);
33772 this.childrenRendered = false;
33773 this.loaded = false;
33774 if(this.isHiddenRoot()){
33775 this.expanded = false;
33777 this.expand(false, false, callback);
33781 * Ext JS Library 1.1.1
33782 * Copyright(c) 2006-2007, Ext JS, LLC.
33784 * Originally Released Under LGPL - original licence link has changed is not relivant.
33787 * <script type="text/javascript">
33791 * @class Roo.tree.TreeNodeUI
33793 * @param {Object} node The node to render
33794 * The TreeNode UI implementation is separate from the
33795 * tree implementation. Unless you are customizing the tree UI,
33796 * you should never have to use this directly.
33798 Roo.tree.TreeNodeUI = function(node){
33800 this.rendered = false;
33801 this.animating = false;
33802 this.emptyIcon = Roo.BLANK_IMAGE_URL;
33805 Roo.tree.TreeNodeUI.prototype = {
33806 removeChild : function(node){
33808 this.ctNode.removeChild(node.ui.getEl());
33812 beforeLoad : function(){
33813 this.addClass("x-tree-node-loading");
33816 afterLoad : function(){
33817 this.removeClass("x-tree-node-loading");
33820 onTextChange : function(node, text, oldText){
33822 this.textNode.innerHTML = text;
33826 onDisableChange : function(node, state){
33827 this.disabled = state;
33829 this.addClass("x-tree-node-disabled");
33831 this.removeClass("x-tree-node-disabled");
33835 onSelectedChange : function(state){
33838 this.addClass("x-tree-selected");
33841 this.removeClass("x-tree-selected");
33845 onMove : function(tree, node, oldParent, newParent, index, refNode){
33846 this.childIndent = null;
33848 var targetNode = newParent.ui.getContainer();
33849 if(!targetNode){//target not rendered
33850 this.holder = document.createElement("div");
33851 this.holder.appendChild(this.wrap);
33854 var insertBefore = refNode ? refNode.ui.getEl() : null;
33856 targetNode.insertBefore(this.wrap, insertBefore);
33858 targetNode.appendChild(this.wrap);
33860 this.node.renderIndent(true);
33864 addClass : function(cls){
33866 Roo.fly(this.elNode).addClass(cls);
33870 removeClass : function(cls){
33872 Roo.fly(this.elNode).removeClass(cls);
33876 remove : function(){
33878 this.holder = document.createElement("div");
33879 this.holder.appendChild(this.wrap);
33883 fireEvent : function(){
33884 return this.node.fireEvent.apply(this.node, arguments);
33887 initEvents : function(){
33888 this.node.on("move", this.onMove, this);
33889 var E = Roo.EventManager;
33890 var a = this.anchor;
33892 var el = Roo.fly(a, '_treeui');
33894 if(Roo.isOpera){ // opera render bug ignores the CSS
33895 el.setStyle("text-decoration", "none");
33898 el.on("click", this.onClick, this);
33899 el.on("dblclick", this.onDblClick, this);
33902 Roo.EventManager.on(this.checkbox,
33903 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
33906 el.on("contextmenu", this.onContextMenu, this);
33908 var icon = Roo.fly(this.iconNode);
33909 icon.on("click", this.onClick, this);
33910 icon.on("dblclick", this.onDblClick, this);
33911 icon.on("contextmenu", this.onContextMenu, this);
33912 E.on(this.ecNode, "click", this.ecClick, this, true);
33914 if(this.node.disabled){
33915 this.addClass("x-tree-node-disabled");
33917 if(this.node.hidden){
33918 this.addClass("x-tree-node-disabled");
33920 var ot = this.node.getOwnerTree();
33921 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
33922 if(dd && (!this.node.isRoot || ot.rootVisible)){
33923 Roo.dd.Registry.register(this.elNode, {
33925 handles: this.getDDHandles(),
33931 getDDHandles : function(){
33932 return [this.iconNode, this.textNode];
33937 this.wrap.style.display = "none";
33943 this.wrap.style.display = "";
33947 onContextMenu : function(e){
33948 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
33949 e.preventDefault();
33951 this.fireEvent("contextmenu", this.node, e);
33955 onClick : function(e){
33960 if(this.fireEvent("beforeclick", this.node, e) !== false){
33961 if(!this.disabled && this.node.attributes.href){
33962 this.fireEvent("click", this.node, e);
33965 e.preventDefault();
33970 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
33971 this.node.toggle();
33974 this.fireEvent("click", this.node, e);
33980 onDblClick : function(e){
33981 e.preventDefault();
33986 this.toggleCheck();
33988 if(!this.animating && this.node.hasChildNodes()){
33989 this.node.toggle();
33991 this.fireEvent("dblclick", this.node, e);
33994 onCheckChange : function(){
33995 var checked = this.checkbox.checked;
33996 this.node.attributes.checked = checked;
33997 this.fireEvent('checkchange', this.node, checked);
34000 ecClick : function(e){
34001 if(!this.animating && this.node.hasChildNodes()){
34002 this.node.toggle();
34006 startDrop : function(){
34007 this.dropping = true;
34010 // delayed drop so the click event doesn't get fired on a drop
34011 endDrop : function(){
34012 setTimeout(function(){
34013 this.dropping = false;
34014 }.createDelegate(this), 50);
34017 expand : function(){
34018 this.updateExpandIcon();
34019 this.ctNode.style.display = "";
34022 focus : function(){
34023 if(!this.node.preventHScroll){
34024 try{this.anchor.focus();
34026 }else if(!Roo.isIE){
34028 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
34029 var l = noscroll.scrollLeft;
34030 this.anchor.focus();
34031 noscroll.scrollLeft = l;
34036 toggleCheck : function(value){
34037 var cb = this.checkbox;
34039 cb.checked = (value === undefined ? !cb.checked : value);
34045 this.anchor.blur();
34049 animExpand : function(callback){
34050 var ct = Roo.get(this.ctNode);
34052 if(!this.node.hasChildNodes()){
34053 this.updateExpandIcon();
34054 this.ctNode.style.display = "";
34055 Roo.callback(callback);
34058 this.animating = true;
34059 this.updateExpandIcon();
34062 callback : function(){
34063 this.animating = false;
34064 Roo.callback(callback);
34067 duration: this.node.ownerTree.duration || .25
34071 highlight : function(){
34072 var tree = this.node.getOwnerTree();
34073 Roo.fly(this.wrap).highlight(
34074 tree.hlColor || "C3DAF9",
34075 {endColor: tree.hlBaseColor}
34079 collapse : function(){
34080 this.updateExpandIcon();
34081 this.ctNode.style.display = "none";
34084 animCollapse : function(callback){
34085 var ct = Roo.get(this.ctNode);
34086 ct.enableDisplayMode('block');
34089 this.animating = true;
34090 this.updateExpandIcon();
34093 callback : function(){
34094 this.animating = false;
34095 Roo.callback(callback);
34098 duration: this.node.ownerTree.duration || .25
34102 getContainer : function(){
34103 return this.ctNode;
34106 getEl : function(){
34110 appendDDGhost : function(ghostNode){
34111 ghostNode.appendChild(this.elNode.cloneNode(true));
34114 getDDRepairXY : function(){
34115 return Roo.lib.Dom.getXY(this.iconNode);
34118 onRender : function(){
34122 render : function(bulkRender){
34123 var n = this.node, a = n.attributes;
34124 var targetNode = n.parentNode ?
34125 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
34127 if(!this.rendered){
34128 this.rendered = true;
34130 this.renderElements(n, a, targetNode, bulkRender);
34133 if(this.textNode.setAttributeNS){
34134 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
34136 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
34139 this.textNode.setAttribute("ext:qtip", a.qtip);
34141 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
34144 }else if(a.qtipCfg){
34145 a.qtipCfg.target = Roo.id(this.textNode);
34146 Roo.QuickTips.register(a.qtipCfg);
34149 if(!this.node.expanded){
34150 this.updateExpandIcon();
34153 if(bulkRender === true) {
34154 targetNode.appendChild(this.wrap);
34159 renderElements : function(n, a, targetNode, bulkRender)
34161 // add some indent caching, this helps performance when rendering a large tree
34162 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
34163 var t = n.getOwnerTree();
34164 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
34165 if (typeof(n.attributes.html) != 'undefined') {
34166 txt = n.attributes.html;
34168 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
34169 var cb = typeof a.checked == 'boolean';
34170 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
34171 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
34172 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
34173 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
34174 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
34175 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
34176 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
34177 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
34178 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
34179 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
34182 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
34183 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
34184 n.nextSibling.ui.getEl(), buf.join(""));
34186 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
34189 this.elNode = this.wrap.childNodes[0];
34190 this.ctNode = this.wrap.childNodes[1];
34191 var cs = this.elNode.childNodes;
34192 this.indentNode = cs[0];
34193 this.ecNode = cs[1];
34194 this.iconNode = cs[2];
34197 this.checkbox = cs[3];
34200 this.anchor = cs[index];
34201 this.textNode = cs[index].firstChild;
34204 getAnchor : function(){
34205 return this.anchor;
34208 getTextEl : function(){
34209 return this.textNode;
34212 getIconEl : function(){
34213 return this.iconNode;
34216 isChecked : function(){
34217 return this.checkbox ? this.checkbox.checked : false;
34220 updateExpandIcon : function(){
34222 var n = this.node, c1, c2;
34223 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
34224 var hasChild = n.hasChildNodes();
34228 c1 = "x-tree-node-collapsed";
34229 c2 = "x-tree-node-expanded";
34232 c1 = "x-tree-node-expanded";
34233 c2 = "x-tree-node-collapsed";
34236 this.removeClass("x-tree-node-leaf");
34237 this.wasLeaf = false;
34239 if(this.c1 != c1 || this.c2 != c2){
34240 Roo.fly(this.elNode).replaceClass(c1, c2);
34241 this.c1 = c1; this.c2 = c2;
34244 // this changes non-leafs into leafs if they have no children.
34245 // it's not very rational behaviour..
34247 if(!this.wasLeaf && this.node.leaf){
34248 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
34251 this.wasLeaf = true;
34254 var ecc = "x-tree-ec-icon "+cls;
34255 if(this.ecc != ecc){
34256 this.ecNode.className = ecc;
34262 getChildIndent : function(){
34263 if(!this.childIndent){
34267 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
34269 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
34271 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
34276 this.childIndent = buf.join("");
34278 return this.childIndent;
34281 renderIndent : function(){
34284 var p = this.node.parentNode;
34286 indent = p.ui.getChildIndent();
34288 if(this.indentMarkup != indent){ // don't rerender if not required
34289 this.indentNode.innerHTML = indent;
34290 this.indentMarkup = indent;
34292 this.updateExpandIcon();
34297 Roo.tree.RootTreeNodeUI = function(){
34298 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
34300 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
34301 render : function(){
34302 if(!this.rendered){
34303 var targetNode = this.node.ownerTree.innerCt.dom;
34304 this.node.expanded = true;
34305 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
34306 this.wrap = this.ctNode = targetNode.firstChild;
34309 collapse : function(){
34311 expand : function(){
34315 * Ext JS Library 1.1.1
34316 * Copyright(c) 2006-2007, Ext JS, LLC.
34318 * Originally Released Under LGPL - original licence link has changed is not relivant.
34321 * <script type="text/javascript">
34324 * @class Roo.tree.TreeLoader
34325 * @extends Roo.util.Observable
34326 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
34327 * nodes from a specified URL. The response must be a javascript Array definition
34328 * who's elements are node definition objects. eg:
34333 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
34334 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
34341 * The old style respose with just an array is still supported, but not recommended.
34344 * A server request is sent, and child nodes are loaded only when a node is expanded.
34345 * The loading node's id is passed to the server under the parameter name "node" to
34346 * enable the server to produce the correct child nodes.
34348 * To pass extra parameters, an event handler may be attached to the "beforeload"
34349 * event, and the parameters specified in the TreeLoader's baseParams property:
34351 myTreeLoader.on("beforeload", function(treeLoader, node) {
34352 this.baseParams.category = node.attributes.category;
34355 * This would pass an HTTP parameter called "category" to the server containing
34356 * the value of the Node's "category" attribute.
34358 * Creates a new Treeloader.
34359 * @param {Object} config A config object containing config properties.
34361 Roo.tree.TreeLoader = function(config){
34362 this.baseParams = {};
34363 this.requestMethod = "POST";
34364 Roo.apply(this, config);
34369 * @event beforeload
34370 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
34371 * @param {Object} This TreeLoader object.
34372 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34373 * @param {Object} callback The callback function specified in the {@link #load} call.
34378 * Fires when the node has been successfuly loaded.
34379 * @param {Object} This TreeLoader object.
34380 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34381 * @param {Object} response The response object containing the data from the server.
34385 * @event loadexception
34386 * Fires if the network request failed.
34387 * @param {Object} This TreeLoader object.
34388 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
34389 * @param {Object} response The response object containing the data from the server.
34391 loadexception : true,
34394 * Fires before a node is created, enabling you to return custom Node types
34395 * @param {Object} This TreeLoader object.
34396 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
34401 Roo.tree.TreeLoader.superclass.constructor.call(this);
34404 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
34406 * @cfg {String} dataUrl The URL from which to request a Json string which
34407 * specifies an array of node definition object representing the child nodes
34411 * @cfg {String} requestMethod either GET or POST
34412 * defaults to POST (due to BC)
34416 * @cfg {Object} baseParams (optional) An object containing properties which
34417 * specify HTTP parameters to be passed to each request for child nodes.
34420 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
34421 * created by this loader. If the attributes sent by the server have an attribute in this object,
34422 * they take priority.
34425 * @cfg {Object} uiProviders (optional) An object containing properties which
34427 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
34428 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
34429 * <i>uiProvider</i> attribute of a returned child node is a string rather
34430 * than a reference to a TreeNodeUI implementation, this that string value
34431 * is used as a property name in the uiProviders object. You can define the provider named
34432 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
34437 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
34438 * child nodes before loading.
34440 clearOnLoad : true,
34443 * @cfg {String} root (optional) Default to false. Use this to read data from an object
34444 * property on loading, rather than expecting an array. (eg. more compatible to a standard
34445 * Grid query { data : [ .....] }
34450 * @cfg {String} queryParam (optional)
34451 * Name of the query as it will be passed on the querystring (defaults to 'node')
34452 * eg. the request will be ?node=[id]
34459 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
34460 * This is called automatically when a node is expanded, but may be used to reload
34461 * a node (or append new children if the {@link #clearOnLoad} option is false.)
34462 * @param {Roo.tree.TreeNode} node
34463 * @param {Function} callback
34465 load : function(node, callback){
34466 if(this.clearOnLoad){
34467 while(node.firstChild){
34468 node.removeChild(node.firstChild);
34471 if(node.attributes.children){ // preloaded json children
34472 var cs = node.attributes.children;
34473 for(var i = 0, len = cs.length; i < len; i++){
34474 node.appendChild(this.createNode(cs[i]));
34476 if(typeof callback == "function"){
34479 }else if(this.dataUrl){
34480 this.requestData(node, callback);
34484 getParams: function(node){
34485 var buf = [], bp = this.baseParams;
34486 for(var key in bp){
34487 if(typeof bp[key] != "function"){
34488 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
34491 var n = this.queryParam === false ? 'node' : this.queryParam;
34492 buf.push(n + "=", encodeURIComponent(node.id));
34493 return buf.join("");
34496 requestData : function(node, callback){
34497 if(this.fireEvent("beforeload", this, node, callback) !== false){
34498 this.transId = Roo.Ajax.request({
34499 method:this.requestMethod,
34500 url: this.dataUrl||this.url,
34501 success: this.handleResponse,
34502 failure: this.handleFailure,
34504 argument: {callback: callback, node: node},
34505 params: this.getParams(node)
34508 // if the load is cancelled, make sure we notify
34509 // the node that we are done
34510 if(typeof callback == "function"){
34516 isLoading : function(){
34517 return this.transId ? true : false;
34520 abort : function(){
34521 if(this.isLoading()){
34522 Roo.Ajax.abort(this.transId);
34527 createNode : function(attr)
34529 // apply baseAttrs, nice idea Corey!
34530 if(this.baseAttrs){
34531 Roo.applyIf(attr, this.baseAttrs);
34533 if(this.applyLoader !== false){
34534 attr.loader = this;
34536 // uiProvider = depreciated..
34538 if(typeof(attr.uiProvider) == 'string'){
34539 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
34540 /** eval:var:attr */ eval(attr.uiProvider);
34542 if(typeof(this.uiProviders['default']) != 'undefined') {
34543 attr.uiProvider = this.uiProviders['default'];
34546 this.fireEvent('create', this, attr);
34548 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
34550 new Roo.tree.TreeNode(attr) :
34551 new Roo.tree.AsyncTreeNode(attr));
34554 processResponse : function(response, node, callback)
34556 var json = response.responseText;
34559 var o = Roo.decode(json);
34561 if (this.root === false && typeof(o.success) != undefined) {
34562 this.root = 'data'; // the default behaviour for list like data..
34565 if (this.root !== false && !o.success) {
34566 // it's a failure condition.
34567 var a = response.argument;
34568 this.fireEvent("loadexception", this, a.node, response);
34569 Roo.log("Load failed - should have a handler really");
34575 if (this.root !== false) {
34579 for(var i = 0, len = o.length; i < len; i++){
34580 var n = this.createNode(o[i]);
34582 node.appendChild(n);
34585 if(typeof callback == "function"){
34586 callback(this, node);
34589 this.handleFailure(response);
34593 handleResponse : function(response){
34594 this.transId = false;
34595 var a = response.argument;
34596 this.processResponse(response, a.node, a.callback);
34597 this.fireEvent("load", this, a.node, response);
34600 handleFailure : function(response)
34602 // should handle failure better..
34603 this.transId = false;
34604 var a = response.argument;
34605 this.fireEvent("loadexception", this, a.node, response);
34606 if(typeof a.callback == "function"){
34607 a.callback(this, a.node);
34612 * Ext JS Library 1.1.1
34613 * Copyright(c) 2006-2007, Ext JS, LLC.
34615 * Originally Released Under LGPL - original licence link has changed is not relivant.
34618 * <script type="text/javascript">
34622 * @class Roo.tree.TreeFilter
34623 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
34624 * @param {TreePanel} tree
34625 * @param {Object} config (optional)
34627 Roo.tree.TreeFilter = function(tree, config){
34629 this.filtered = {};
34630 Roo.apply(this, config);
34633 Roo.tree.TreeFilter.prototype = {
34640 * Filter the data by a specific attribute.
34641 * @param {String/RegExp} value Either string that the attribute value
34642 * should start with or a RegExp to test against the attribute
34643 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
34644 * @param {TreeNode} startNode (optional) The node to start the filter at.
34646 filter : function(value, attr, startNode){
34647 attr = attr || "text";
34649 if(typeof value == "string"){
34650 var vlen = value.length;
34651 // auto clear empty filter
34652 if(vlen == 0 && this.clearBlank){
34656 value = value.toLowerCase();
34658 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
34660 }else if(value.exec){ // regex?
34662 return value.test(n.attributes[attr]);
34665 throw 'Illegal filter type, must be string or regex';
34667 this.filterBy(f, null, startNode);
34671 * Filter by a function. The passed function will be called with each
34672 * node in the tree (or from the startNode). If the function returns true, the node is kept
34673 * otherwise it is filtered. If a node is filtered, its children are also filtered.
34674 * @param {Function} fn The filter function
34675 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
34677 filterBy : function(fn, scope, startNode){
34678 startNode = startNode || this.tree.root;
34679 if(this.autoClear){
34682 var af = this.filtered, rv = this.reverse;
34683 var f = function(n){
34684 if(n == startNode){
34690 var m = fn.call(scope || n, n);
34698 startNode.cascade(f);
34701 if(typeof id != "function"){
34703 if(n && n.parentNode){
34704 n.parentNode.removeChild(n);
34712 * Clears the current filter. Note: with the "remove" option
34713 * set a filter cannot be cleared.
34715 clear : function(){
34717 var af = this.filtered;
34719 if(typeof id != "function"){
34726 this.filtered = {};
34731 * Ext JS Library 1.1.1
34732 * Copyright(c) 2006-2007, Ext JS, LLC.
34734 * Originally Released Under LGPL - original licence link has changed is not relivant.
34737 * <script type="text/javascript">
34742 * @class Roo.tree.TreeSorter
34743 * Provides sorting of nodes in a TreePanel
34745 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
34746 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
34747 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
34748 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
34749 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
34750 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
34752 * @param {TreePanel} tree
34753 * @param {Object} config
34755 Roo.tree.TreeSorter = function(tree, config){
34756 Roo.apply(this, config);
34757 tree.on("beforechildrenrendered", this.doSort, this);
34758 tree.on("append", this.updateSort, this);
34759 tree.on("insert", this.updateSort, this);
34761 var dsc = this.dir && this.dir.toLowerCase() == "desc";
34762 var p = this.property || "text";
34763 var sortType = this.sortType;
34764 var fs = this.folderSort;
34765 var cs = this.caseSensitive === true;
34766 var leafAttr = this.leafAttr || 'leaf';
34768 this.sortFn = function(n1, n2){
34770 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
34773 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
34777 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
34778 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
34780 return dsc ? +1 : -1;
34782 return dsc ? -1 : +1;
34789 Roo.tree.TreeSorter.prototype = {
34790 doSort : function(node){
34791 node.sort(this.sortFn);
34794 compareNodes : function(n1, n2){
34795 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
34798 updateSort : function(tree, node){
34799 if(node.childrenRendered){
34800 this.doSort.defer(1, this, [node]);
34805 * Ext JS Library 1.1.1
34806 * Copyright(c) 2006-2007, Ext JS, LLC.
34808 * Originally Released Under LGPL - original licence link has changed is not relivant.
34811 * <script type="text/javascript">
34814 if(Roo.dd.DropZone){
34816 Roo.tree.TreeDropZone = function(tree, config){
34817 this.allowParentInsert = false;
34818 this.allowContainerDrop = false;
34819 this.appendOnly = false;
34820 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
34822 this.lastInsertClass = "x-tree-no-status";
34823 this.dragOverData = {};
34826 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
34827 ddGroup : "TreeDD",
34830 expandDelay : 1000,
34832 expandNode : function(node){
34833 if(node.hasChildNodes() && !node.isExpanded()){
34834 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
34838 queueExpand : function(node){
34839 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
34842 cancelExpand : function(){
34843 if(this.expandProcId){
34844 clearTimeout(this.expandProcId);
34845 this.expandProcId = false;
34849 isValidDropPoint : function(n, pt, dd, e, data){
34850 if(!n || !data){ return false; }
34851 var targetNode = n.node;
34852 var dropNode = data.node;
34853 // default drop rules
34854 if(!(targetNode && targetNode.isTarget && pt)){
34857 if(pt == "append" && targetNode.allowChildren === false){
34860 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
34863 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
34866 // reuse the object
34867 var overEvent = this.dragOverData;
34868 overEvent.tree = this.tree;
34869 overEvent.target = targetNode;
34870 overEvent.data = data;
34871 overEvent.point = pt;
34872 overEvent.source = dd;
34873 overEvent.rawEvent = e;
34874 overEvent.dropNode = dropNode;
34875 overEvent.cancel = false;
34876 var result = this.tree.fireEvent("nodedragover", overEvent);
34877 return overEvent.cancel === false && result !== false;
34880 getDropPoint : function(e, n, dd)
34884 return tn.allowChildren !== false ? "append" : false; // always append for root
34886 var dragEl = n.ddel;
34887 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
34888 var y = Roo.lib.Event.getPageY(e);
34889 //var noAppend = tn.allowChildren === false || tn.isLeaf();
34891 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
34892 var noAppend = tn.allowChildren === false;
34893 if(this.appendOnly || tn.parentNode.allowChildren === false){
34894 return noAppend ? false : "append";
34896 var noBelow = false;
34897 if(!this.allowParentInsert){
34898 noBelow = tn.hasChildNodes() && tn.isExpanded();
34900 var q = (b - t) / (noAppend ? 2 : 3);
34901 if(y >= t && y < (t + q)){
34903 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
34910 onNodeEnter : function(n, dd, e, data)
34912 this.cancelExpand();
34915 onNodeOver : function(n, dd, e, data)
34918 var pt = this.getDropPoint(e, n, dd);
34921 // auto node expand check
34922 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
34923 this.queueExpand(node);
34924 }else if(pt != "append"){
34925 this.cancelExpand();
34928 // set the insert point style on the target node
34929 var returnCls = this.dropNotAllowed;
34930 if(this.isValidDropPoint(n, pt, dd, e, data)){
34935 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
34936 cls = "x-tree-drag-insert-above";
34937 }else if(pt == "below"){
34938 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
34939 cls = "x-tree-drag-insert-below";
34941 returnCls = "x-tree-drop-ok-append";
34942 cls = "x-tree-drag-append";
34944 if(this.lastInsertClass != cls){
34945 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
34946 this.lastInsertClass = cls;
34953 onNodeOut : function(n, dd, e, data){
34955 this.cancelExpand();
34956 this.removeDropIndicators(n);
34959 onNodeDrop : function(n, dd, e, data){
34960 var point = this.getDropPoint(e, n, dd);
34961 var targetNode = n.node;
34962 targetNode.ui.startDrop();
34963 if(!this.isValidDropPoint(n, point, dd, e, data)){
34964 targetNode.ui.endDrop();
34967 // first try to find the drop node
34968 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
34971 target: targetNode,
34976 dropNode: dropNode,
34979 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
34980 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
34981 targetNode.ui.endDrop();
34984 // allow target changing
34985 targetNode = dropEvent.target;
34986 if(point == "append" && !targetNode.isExpanded()){
34987 targetNode.expand(false, null, function(){
34988 this.completeDrop(dropEvent);
34989 }.createDelegate(this));
34991 this.completeDrop(dropEvent);
34996 completeDrop : function(de){
34997 var ns = de.dropNode, p = de.point, t = de.target;
34998 if(!(ns instanceof Array)){
35002 for(var i = 0, len = ns.length; i < len; i++){
35005 t.parentNode.insertBefore(n, t);
35006 }else if(p == "below"){
35007 t.parentNode.insertBefore(n, t.nextSibling);
35013 if(this.tree.hlDrop){
35017 this.tree.fireEvent("nodedrop", de);
35020 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
35021 if(this.tree.hlDrop){
35022 dropNode.ui.focus();
35023 dropNode.ui.highlight();
35025 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
35028 getTree : function(){
35032 removeDropIndicators : function(n){
35035 Roo.fly(el).removeClass([
35036 "x-tree-drag-insert-above",
35037 "x-tree-drag-insert-below",
35038 "x-tree-drag-append"]);
35039 this.lastInsertClass = "_noclass";
35043 beforeDragDrop : function(target, e, id){
35044 this.cancelExpand();
35048 afterRepair : function(data){
35049 if(data && Roo.enableFx){
35050 data.node.ui.highlight();
35060 * Ext JS Library 1.1.1
35061 * Copyright(c) 2006-2007, Ext JS, LLC.
35063 * Originally Released Under LGPL - original licence link has changed is not relivant.
35066 * <script type="text/javascript">
35070 if(Roo.dd.DragZone){
35071 Roo.tree.TreeDragZone = function(tree, config){
35072 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
35076 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
35077 ddGroup : "TreeDD",
35079 onBeforeDrag : function(data, e){
35081 return n && n.draggable && !n.disabled;
35085 onInitDrag : function(e){
35086 var data = this.dragData;
35087 this.tree.getSelectionModel().select(data.node);
35088 this.proxy.update("");
35089 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
35090 this.tree.fireEvent("startdrag", this.tree, data.node, e);
35093 getRepairXY : function(e, data){
35094 return data.node.ui.getDDRepairXY();
35097 onEndDrag : function(data, e){
35098 this.tree.fireEvent("enddrag", this.tree, data.node, e);
35103 onValidDrop : function(dd, e, id){
35104 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
35108 beforeInvalidDrop : function(e, id){
35109 // this scrolls the original position back into view
35110 var sm = this.tree.getSelectionModel();
35111 sm.clearSelections();
35112 sm.select(this.dragData.node);
35117 * Ext JS Library 1.1.1
35118 * Copyright(c) 2006-2007, Ext JS, LLC.
35120 * Originally Released Under LGPL - original licence link has changed is not relivant.
35123 * <script type="text/javascript">
35126 * @class Roo.tree.TreeEditor
35127 * @extends Roo.Editor
35128 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
35129 * as the editor field.
35131 * @param {Object} config (used to be the tree panel.)
35132 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
35134 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
35135 * @cfg {Roo.form.TextField|Object} field The field configuration
35139 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
35142 if (oldconfig) { // old style..
35143 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
35146 tree = config.tree;
35147 config.field = config.field || {};
35148 config.field.xtype = 'TextField';
35149 field = Roo.factory(config.field, Roo.form);
35151 config = config || {};
35156 * @event beforenodeedit
35157 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
35158 * false from the handler of this event.
35159 * @param {Editor} this
35160 * @param {Roo.tree.Node} node
35162 "beforenodeedit" : true
35166 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
35170 tree.on('beforeclick', this.beforeNodeClick, this);
35171 tree.getTreeEl().on('mousedown', this.hide, this);
35172 this.on('complete', this.updateNode, this);
35173 this.on('beforestartedit', this.fitToTree, this);
35174 this.on('startedit', this.bindScroll, this, {delay:10});
35175 this.on('specialkey', this.onSpecialKey, this);
35178 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
35180 * @cfg {String} alignment
35181 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
35187 * @cfg {Boolean} hideEl
35188 * True to hide the bound element while the editor is displayed (defaults to false)
35192 * @cfg {String} cls
35193 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
35195 cls: "x-small-editor x-tree-editor",
35197 * @cfg {Boolean} shim
35198 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
35204 * @cfg {Number} maxWidth
35205 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
35206 * the containing tree element's size, it will be automatically limited for you to the container width, taking
35207 * scroll and client offsets into account prior to each edit.
35214 fitToTree : function(ed, el){
35215 var td = this.tree.getTreeEl().dom, nd = el.dom;
35216 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
35217 td.scrollLeft = nd.offsetLeft;
35221 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
35222 this.setSize(w, '');
35224 return this.fireEvent('beforenodeedit', this, this.editNode);
35229 triggerEdit : function(node){
35230 this.completeEdit();
35231 this.editNode = node;
35232 this.startEdit(node.ui.textNode, node.text);
35236 bindScroll : function(){
35237 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
35241 beforeNodeClick : function(node, e){
35242 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
35243 this.lastClick = new Date();
35244 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
35246 this.triggerEdit(node);
35253 updateNode : function(ed, value){
35254 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
35255 this.editNode.setText(value);
35259 onHide : function(){
35260 Roo.tree.TreeEditor.superclass.onHide.call(this);
35262 this.editNode.ui.focus();
35267 onSpecialKey : function(field, e){
35268 var k = e.getKey();
35272 }else if(k == e.ENTER && !e.hasModifier()){
35274 this.completeEdit();
35277 });//<Script type="text/javascript">
35280 * Ext JS Library 1.1.1
35281 * Copyright(c) 2006-2007, Ext JS, LLC.
35283 * Originally Released Under LGPL - original licence link has changed is not relivant.
35286 * <script type="text/javascript">
35290 * Not documented??? - probably should be...
35293 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
35294 //focus: Roo.emptyFn, // prevent odd scrolling behavior
35296 renderElements : function(n, a, targetNode, bulkRender){
35297 //consel.log("renderElements?");
35298 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35300 var t = n.getOwnerTree();
35301 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
35303 var cols = t.columns;
35304 var bw = t.borderWidth;
35306 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35307 var cb = typeof a.checked == "boolean";
35308 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35309 var colcls = 'x-t-' + tid + '-c0';
35311 '<li class="x-tree-node">',
35314 '<div class="x-tree-node-el ', a.cls,'">',
35316 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
35319 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
35320 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
35321 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
35322 (a.icon ? ' x-tree-node-inline-icon' : ''),
35323 (a.iconCls ? ' '+a.iconCls : ''),
35324 '" unselectable="on" />',
35325 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
35326 (a.checked ? 'checked="checked" />' : ' />')) : ''),
35328 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35329 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
35330 '<span unselectable="on" qtip="' + tx + '">',
35334 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
35335 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
35337 for(var i = 1, len = cols.length; i < len; i++){
35339 colcls = 'x-t-' + tid + '-c' +i;
35340 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
35341 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
35342 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
35348 '<div class="x-clear"></div></div>',
35349 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35352 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35353 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35354 n.nextSibling.ui.getEl(), buf.join(""));
35356 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35358 var el = this.wrap.firstChild;
35360 this.elNode = el.firstChild;
35361 this.ranchor = el.childNodes[1];
35362 this.ctNode = this.wrap.childNodes[1];
35363 var cs = el.firstChild.childNodes;
35364 this.indentNode = cs[0];
35365 this.ecNode = cs[1];
35366 this.iconNode = cs[2];
35369 this.checkbox = cs[3];
35372 this.anchor = cs[index];
35374 this.textNode = cs[index].firstChild;
35376 //el.on("click", this.onClick, this);
35377 //el.on("dblclick", this.onDblClick, this);
35380 // console.log(this);
35382 initEvents : function(){
35383 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
35386 var a = this.ranchor;
35388 var el = Roo.get(a);
35390 if(Roo.isOpera){ // opera render bug ignores the CSS
35391 el.setStyle("text-decoration", "none");
35394 el.on("click", this.onClick, this);
35395 el.on("dblclick", this.onDblClick, this);
35396 el.on("contextmenu", this.onContextMenu, this);
35400 /*onSelectedChange : function(state){
35403 this.addClass("x-tree-selected");
35406 this.removeClass("x-tree-selected");
35409 addClass : function(cls){
35411 Roo.fly(this.elRow).addClass(cls);
35417 removeClass : function(cls){
35419 Roo.fly(this.elRow).removeClass(cls);
35425 });//<Script type="text/javascript">
35429 * Ext JS Library 1.1.1
35430 * Copyright(c) 2006-2007, Ext JS, LLC.
35432 * Originally Released Under LGPL - original licence link has changed is not relivant.
35435 * <script type="text/javascript">
35440 * @class Roo.tree.ColumnTree
35441 * @extends Roo.data.TreePanel
35442 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
35443 * @cfg {int} borderWidth compined right/left border allowance
35445 * @param {String/HTMLElement/Element} el The container element
35446 * @param {Object} config
35448 Roo.tree.ColumnTree = function(el, config)
35450 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
35454 * Fire this event on a container when it resizes
35455 * @param {int} w Width
35456 * @param {int} h Height
35460 this.on('resize', this.onResize, this);
35463 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
35467 borderWidth: Roo.isBorderBox ? 0 : 2,
35470 render : function(){
35471 // add the header.....
35473 Roo.tree.ColumnTree.superclass.render.apply(this);
35475 this.el.addClass('x-column-tree');
35477 this.headers = this.el.createChild(
35478 {cls:'x-tree-headers'},this.innerCt.dom);
35480 var cols = this.columns, c;
35481 var totalWidth = 0;
35483 var len = cols.length;
35484 for(var i = 0; i < len; i++){
35486 totalWidth += c.width;
35487 this.headEls.push(this.headers.createChild({
35488 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
35490 cls:'x-tree-hd-text',
35493 style:'width:'+(c.width-this.borderWidth)+'px;'
35496 this.headers.createChild({cls:'x-clear'});
35497 // prevent floats from wrapping when clipped
35498 this.headers.setWidth(totalWidth);
35499 //this.innerCt.setWidth(totalWidth);
35500 this.innerCt.setStyle({ overflow: 'auto' });
35501 this.onResize(this.width, this.height);
35505 onResize : function(w,h)
35510 this.innerCt.setWidth(this.width);
35511 this.innerCt.setHeight(this.height-20);
35514 var cols = this.columns, c;
35515 var totalWidth = 0;
35517 var len = cols.length;
35518 for(var i = 0; i < len; i++){
35520 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
35521 // it's the expander..
35522 expEl = this.headEls[i];
35525 totalWidth += c.width;
35529 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
35531 this.headers.setWidth(w-20);
35540 * Ext JS Library 1.1.1
35541 * Copyright(c) 2006-2007, Ext JS, LLC.
35543 * Originally Released Under LGPL - original licence link has changed is not relivant.
35546 * <script type="text/javascript">
35550 * @class Roo.menu.Menu
35551 * @extends Roo.util.Observable
35552 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
35553 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
35555 * Creates a new Menu
35556 * @param {Object} config Configuration options
35558 Roo.menu.Menu = function(config){
35559 Roo.apply(this, config);
35560 this.id = this.id || Roo.id();
35563 * @event beforeshow
35564 * Fires before this menu is displayed
35565 * @param {Roo.menu.Menu} this
35569 * @event beforehide
35570 * Fires before this menu is hidden
35571 * @param {Roo.menu.Menu} this
35576 * Fires after this menu is displayed
35577 * @param {Roo.menu.Menu} this
35582 * Fires after this menu is hidden
35583 * @param {Roo.menu.Menu} this
35588 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
35589 * @param {Roo.menu.Menu} this
35590 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35591 * @param {Roo.EventObject} e
35596 * Fires when the mouse is hovering over this menu
35597 * @param {Roo.menu.Menu} this
35598 * @param {Roo.EventObject} e
35599 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35604 * Fires when the mouse exits this menu
35605 * @param {Roo.menu.Menu} this
35606 * @param {Roo.EventObject} e
35607 * @param {Roo.menu.Item} menuItem The menu item that was clicked
35612 * Fires when a menu item contained in this menu is clicked
35613 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
35614 * @param {Roo.EventObject} e
35618 if (this.registerMenu) {
35619 Roo.menu.MenuMgr.register(this);
35622 var mis = this.items;
35623 this.items = new Roo.util.MixedCollection();
35625 this.add.apply(this, mis);
35629 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
35631 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
35635 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
35636 * for bottom-right shadow (defaults to "sides")
35640 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
35641 * this menu (defaults to "tl-tr?")
35643 subMenuAlign : "tl-tr?",
35645 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
35646 * relative to its element of origin (defaults to "tl-bl?")
35648 defaultAlign : "tl-bl?",
35650 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
35652 allowOtherMenus : false,
35654 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
35656 registerMenu : true,
35661 render : function(){
35665 var el = this.el = new Roo.Layer({
35667 shadow:this.shadow,
35669 parentEl: this.parentEl || document.body,
35673 this.keyNav = new Roo.menu.MenuNav(this);
35676 el.addClass("x-menu-plain");
35679 el.addClass(this.cls);
35681 // generic focus element
35682 this.focusEl = el.createChild({
35683 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
35685 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
35686 ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
35688 ul.on("mouseover", this.onMouseOver, this);
35689 ul.on("mouseout", this.onMouseOut, this);
35690 this.items.each(function(item){
35695 var li = document.createElement("li");
35696 li.className = "x-menu-list-item";
35697 ul.dom.appendChild(li);
35698 item.render(li, this);
35705 autoWidth : function(){
35706 var el = this.el, ul = this.ul;
35710 var w = this.width;
35713 }else if(Roo.isIE){
35714 el.setWidth(this.minWidth);
35715 var t = el.dom.offsetWidth; // force recalc
35716 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
35721 delayAutoWidth : function(){
35724 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
35726 this.awTask.delay(20);
35731 findTargetItem : function(e){
35732 var t = e.getTarget(".x-menu-list-item", this.ul, true);
35733 if(t && t.menuItemId){
35734 return this.items.get(t.menuItemId);
35739 onClick : function(e){
35740 Roo.log("menu.onClick");
35741 var t = this.findTargetItem(e);
35746 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
35747 if(t == this.activeItem && t.shouldDeactivate(e)){
35748 this.activeItem.deactivate();
35749 delete this.activeItem;
35753 this.setActiveItem(t, true);
35761 this.fireEvent("click", this, t, e);
35765 setActiveItem : function(item, autoExpand){
35766 if(item != this.activeItem){
35767 if(this.activeItem){
35768 this.activeItem.deactivate();
35770 this.activeItem = item;
35771 item.activate(autoExpand);
35772 }else if(autoExpand){
35778 tryActivate : function(start, step){
35779 var items = this.items;
35780 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
35781 var item = items.get(i);
35782 if(!item.disabled && item.canActivate){
35783 this.setActiveItem(item, false);
35791 onMouseOver : function(e){
35793 if(t = this.findTargetItem(e)){
35794 if(t.canActivate && !t.disabled){
35795 this.setActiveItem(t, true);
35798 this.fireEvent("mouseover", this, e, t);
35802 onMouseOut : function(e){
35804 if(t = this.findTargetItem(e)){
35805 if(t == this.activeItem && t.shouldDeactivate(e)){
35806 this.activeItem.deactivate();
35807 delete this.activeItem;
35810 this.fireEvent("mouseout", this, e, t);
35814 * Read-only. Returns true if the menu is currently displayed, else false.
35817 isVisible : function(){
35818 return this.el && !this.hidden;
35822 * Displays this menu relative to another element
35823 * @param {String/HTMLElement/Roo.Element} element The element to align to
35824 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
35825 * the element (defaults to this.defaultAlign)
35826 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35828 show : function(el, pos, parentMenu){
35829 this.parentMenu = parentMenu;
35833 this.fireEvent("beforeshow", this);
35834 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
35838 * Displays this menu at a specific xy position
35839 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
35840 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
35842 showAt : function(xy, parentMenu, /* private: */_e){
35843 this.parentMenu = parentMenu;
35848 this.fireEvent("beforeshow", this);
35849 xy = this.el.adjustForConstraints(xy);
35853 this.hidden = false;
35855 this.fireEvent("show", this);
35858 focus : function(){
35860 this.doFocus.defer(50, this);
35864 doFocus : function(){
35866 this.focusEl.focus();
35871 * Hides this menu and optionally all parent menus
35872 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
35874 hide : function(deep){
35875 if(this.el && this.isVisible()){
35876 this.fireEvent("beforehide", this);
35877 if(this.activeItem){
35878 this.activeItem.deactivate();
35879 this.activeItem = null;
35882 this.hidden = true;
35883 this.fireEvent("hide", this);
35885 if(deep === true && this.parentMenu){
35886 this.parentMenu.hide(true);
35891 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
35892 * Any of the following are valid:
35894 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
35895 * <li>An HTMLElement object which will be converted to a menu item</li>
35896 * <li>A menu item config object that will be created as a new menu item</li>
35897 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
35898 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
35903 var menu = new Roo.menu.Menu();
35905 // Create a menu item to add by reference
35906 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
35908 // Add a bunch of items at once using different methods.
35909 // Only the last item added will be returned.
35910 var item = menu.add(
35911 menuItem, // add existing item by ref
35912 'Dynamic Item', // new TextItem
35913 '-', // new separator
35914 { text: 'Config Item' } // new item by config
35917 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
35918 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
35921 var a = arguments, l = a.length, item;
35922 for(var i = 0; i < l; i++){
35924 if ((typeof(el) == "object") && el.xtype && el.xns) {
35925 el = Roo.factory(el, Roo.menu);
35928 if(el.render){ // some kind of Item
35929 item = this.addItem(el);
35930 }else if(typeof el == "string"){ // string
35931 if(el == "separator" || el == "-"){
35932 item = this.addSeparator();
35934 item = this.addText(el);
35936 }else if(el.tagName || el.el){ // element
35937 item = this.addElement(el);
35938 }else if(typeof el == "object"){ // must be menu item config?
35939 item = this.addMenuItem(el);
35946 * Returns this menu's underlying {@link Roo.Element} object
35947 * @return {Roo.Element} The element
35949 getEl : function(){
35957 * Adds a separator bar to the menu
35958 * @return {Roo.menu.Item} The menu item that was added
35960 addSeparator : function(){
35961 return this.addItem(new Roo.menu.Separator());
35965 * Adds an {@link Roo.Element} object to the menu
35966 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
35967 * @return {Roo.menu.Item} The menu item that was added
35969 addElement : function(el){
35970 return this.addItem(new Roo.menu.BaseItem(el));
35974 * Adds an existing object based on {@link Roo.menu.Item} to the menu
35975 * @param {Roo.menu.Item} item The menu item to add
35976 * @return {Roo.menu.Item} The menu item that was added
35978 addItem : function(item){
35979 this.items.add(item);
35981 var li = document.createElement("li");
35982 li.className = "x-menu-list-item";
35983 this.ul.dom.appendChild(li);
35984 item.render(li, this);
35985 this.delayAutoWidth();
35991 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
35992 * @param {Object} config A MenuItem config object
35993 * @return {Roo.menu.Item} The menu item that was added
35995 addMenuItem : function(config){
35996 if(!(config instanceof Roo.menu.Item)){
35997 if(typeof config.checked == "boolean"){ // must be check menu item config?
35998 config = new Roo.menu.CheckItem(config);
36000 config = new Roo.menu.Item(config);
36003 return this.addItem(config);
36007 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
36008 * @param {String} text The text to display in the menu item
36009 * @return {Roo.menu.Item} The menu item that was added
36011 addText : function(text){
36012 return this.addItem(new Roo.menu.TextItem({ text : text }));
36016 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
36017 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
36018 * @param {Roo.menu.Item} item The menu item to add
36019 * @return {Roo.menu.Item} The menu item that was added
36021 insert : function(index, item){
36022 this.items.insert(index, item);
36024 var li = document.createElement("li");
36025 li.className = "x-menu-list-item";
36026 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
36027 item.render(li, this);
36028 this.delayAutoWidth();
36034 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
36035 * @param {Roo.menu.Item} item The menu item to remove
36037 remove : function(item){
36038 this.items.removeKey(item.id);
36043 * Removes and destroys all items in the menu
36045 removeAll : function(){
36047 while(f = this.items.first()){
36053 // MenuNav is a private utility class used internally by the Menu
36054 Roo.menu.MenuNav = function(menu){
36055 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
36056 this.scope = this.menu = menu;
36059 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
36060 doRelay : function(e, h){
36061 var k = e.getKey();
36062 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
36063 this.menu.tryActivate(0, 1);
36066 return h.call(this.scope || this, e, this.menu);
36069 up : function(e, m){
36070 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
36071 m.tryActivate(m.items.length-1, -1);
36075 down : function(e, m){
36076 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
36077 m.tryActivate(0, 1);
36081 right : function(e, m){
36083 m.activeItem.expandMenu(true);
36087 left : function(e, m){
36089 if(m.parentMenu && m.parentMenu.activeItem){
36090 m.parentMenu.activeItem.activate();
36094 enter : function(e, m){
36096 e.stopPropagation();
36097 m.activeItem.onClick(e);
36098 m.fireEvent("click", this, m.activeItem);
36104 * Ext JS Library 1.1.1
36105 * Copyright(c) 2006-2007, Ext JS, LLC.
36107 * Originally Released Under LGPL - original licence link has changed is not relivant.
36110 * <script type="text/javascript">
36114 * @class Roo.menu.MenuMgr
36115 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
36118 Roo.menu.MenuMgr = function(){
36119 var menus, active, groups = {}, attached = false, lastShow = new Date();
36121 // private - called when first menu is created
36124 active = new Roo.util.MixedCollection();
36125 Roo.get(document).addKeyListener(27, function(){
36126 if(active.length > 0){
36133 function hideAll(){
36134 if(active && active.length > 0){
36135 var c = active.clone();
36136 c.each(function(m){
36143 function onHide(m){
36145 if(active.length < 1){
36146 Roo.get(document).un("mousedown", onMouseDown);
36152 function onShow(m){
36153 var last = active.last();
36154 lastShow = new Date();
36157 Roo.get(document).on("mousedown", onMouseDown);
36161 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
36162 m.parentMenu.activeChild = m;
36163 }else if(last && last.isVisible()){
36164 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
36169 function onBeforeHide(m){
36171 m.activeChild.hide();
36173 if(m.autoHideTimer){
36174 clearTimeout(m.autoHideTimer);
36175 delete m.autoHideTimer;
36180 function onBeforeShow(m){
36181 var pm = m.parentMenu;
36182 if(!pm && !m.allowOtherMenus){
36184 }else if(pm && pm.activeChild && active != m){
36185 pm.activeChild.hide();
36190 function onMouseDown(e){
36191 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
36197 function onBeforeCheck(mi, state){
36199 var g = groups[mi.group];
36200 for(var i = 0, l = g.length; i < l; i++){
36202 g[i].setChecked(false);
36211 * Hides all menus that are currently visible
36213 hideAll : function(){
36218 register : function(menu){
36222 menus[menu.id] = menu;
36223 menu.on("beforehide", onBeforeHide);
36224 menu.on("hide", onHide);
36225 menu.on("beforeshow", onBeforeShow);
36226 menu.on("show", onShow);
36227 var g = menu.group;
36228 if(g && menu.events["checkchange"]){
36232 groups[g].push(menu);
36233 menu.on("checkchange", onCheck);
36238 * Returns a {@link Roo.menu.Menu} object
36239 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
36240 * be used to generate and return a new Menu instance.
36242 get : function(menu){
36243 if(typeof menu == "string"){ // menu id
36244 return menus[menu];
36245 }else if(menu.events){ // menu instance
36247 }else if(typeof menu.length == 'number'){ // array of menu items?
36248 return new Roo.menu.Menu({items:menu});
36249 }else{ // otherwise, must be a config
36250 return new Roo.menu.Menu(menu);
36255 unregister : function(menu){
36256 delete menus[menu.id];
36257 menu.un("beforehide", onBeforeHide);
36258 menu.un("hide", onHide);
36259 menu.un("beforeshow", onBeforeShow);
36260 menu.un("show", onShow);
36261 var g = menu.group;
36262 if(g && menu.events["checkchange"]){
36263 groups[g].remove(menu);
36264 menu.un("checkchange", onCheck);
36269 registerCheckable : function(menuItem){
36270 var g = menuItem.group;
36275 groups[g].push(menuItem);
36276 menuItem.on("beforecheckchange", onBeforeCheck);
36281 unregisterCheckable : function(menuItem){
36282 var g = menuItem.group;
36284 groups[g].remove(menuItem);
36285 menuItem.un("beforecheckchange", onBeforeCheck);
36291 * Ext JS Library 1.1.1
36292 * Copyright(c) 2006-2007, Ext JS, LLC.
36294 * Originally Released Under LGPL - original licence link has changed is not relivant.
36297 * <script type="text/javascript">
36302 * @class Roo.menu.BaseItem
36303 * @extends Roo.Component
36304 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
36305 * management and base configuration options shared by all menu components.
36307 * Creates a new BaseItem
36308 * @param {Object} config Configuration options
36310 Roo.menu.BaseItem = function(config){
36311 Roo.menu.BaseItem.superclass.constructor.call(this, config);
36316 * Fires when this item is clicked
36317 * @param {Roo.menu.BaseItem} this
36318 * @param {Roo.EventObject} e
36323 * Fires when this item is activated
36324 * @param {Roo.menu.BaseItem} this
36328 * @event deactivate
36329 * Fires when this item is deactivated
36330 * @param {Roo.menu.BaseItem} this
36336 this.on("click", this.handler, this.scope, true);
36340 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
36342 * @cfg {Function} handler
36343 * A function that will handle the click event of this menu item (defaults to undefined)
36346 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
36348 canActivate : false,
36351 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
36356 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
36358 activeClass : "x-menu-item-active",
36360 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
36362 hideOnClick : true,
36364 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
36369 ctype: "Roo.menu.BaseItem",
36372 actionMode : "container",
36375 render : function(container, parentMenu){
36376 this.parentMenu = parentMenu;
36377 Roo.menu.BaseItem.superclass.render.call(this, container);
36378 this.container.menuItemId = this.id;
36382 onRender : function(container, position){
36383 this.el = Roo.get(this.el);
36384 container.dom.appendChild(this.el.dom);
36388 onClick : function(e){
36389 if(!this.disabled && this.fireEvent("click", this, e) !== false
36390 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
36391 this.handleClick(e);
36398 activate : function(){
36402 var li = this.container;
36403 li.addClass(this.activeClass);
36404 this.region = li.getRegion().adjust(2, 2, -2, -2);
36405 this.fireEvent("activate", this);
36410 deactivate : function(){
36411 this.container.removeClass(this.activeClass);
36412 this.fireEvent("deactivate", this);
36416 shouldDeactivate : function(e){
36417 return !this.region || !this.region.contains(e.getPoint());
36421 handleClick : function(e){
36422 if(this.hideOnClick){
36423 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
36428 expandMenu : function(autoActivate){
36433 hideMenu : function(){
36438 * Ext JS Library 1.1.1
36439 * Copyright(c) 2006-2007, Ext JS, LLC.
36441 * Originally Released Under LGPL - original licence link has changed is not relivant.
36444 * <script type="text/javascript">
36448 * @class Roo.menu.Adapter
36449 * @extends Roo.menu.BaseItem
36450 * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
36451 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
36453 * Creates a new Adapter
36454 * @param {Object} config Configuration options
36456 Roo.menu.Adapter = function(component, config){
36457 Roo.menu.Adapter.superclass.constructor.call(this, config);
36458 this.component = component;
36460 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
36462 canActivate : true,
36465 onRender : function(container, position){
36466 this.component.render(container);
36467 this.el = this.component.getEl();
36471 activate : function(){
36475 this.component.focus();
36476 this.fireEvent("activate", this);
36481 deactivate : function(){
36482 this.fireEvent("deactivate", this);
36486 disable : function(){
36487 this.component.disable();
36488 Roo.menu.Adapter.superclass.disable.call(this);
36492 enable : function(){
36493 this.component.enable();
36494 Roo.menu.Adapter.superclass.enable.call(this);
36498 * Ext JS Library 1.1.1
36499 * Copyright(c) 2006-2007, Ext JS, LLC.
36501 * Originally Released Under LGPL - original licence link has changed is not relivant.
36504 * <script type="text/javascript">
36508 * @class Roo.menu.TextItem
36509 * @extends Roo.menu.BaseItem
36510 * Adds a static text string to a menu, usually used as either a heading or group separator.
36511 * Note: old style constructor with text is still supported.
36514 * Creates a new TextItem
36515 * @param {Object} cfg Configuration
36517 Roo.menu.TextItem = function(cfg){
36518 if (typeof(cfg) == 'string') {
36521 Roo.apply(this,cfg);
36524 Roo.menu.TextItem.superclass.constructor.call(this);
36527 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
36529 * @cfg {Boolean} text Text to show on item.
36534 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36536 hideOnClick : false,
36538 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
36540 itemCls : "x-menu-text",
36543 onRender : function(){
36544 var s = document.createElement("span");
36545 s.className = this.itemCls;
36546 s.innerHTML = this.text;
36548 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
36552 * Ext JS Library 1.1.1
36553 * Copyright(c) 2006-2007, Ext JS, LLC.
36555 * Originally Released Under LGPL - original licence link has changed is not relivant.
36558 * <script type="text/javascript">
36562 * @class Roo.menu.Separator
36563 * @extends Roo.menu.BaseItem
36564 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
36565 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
36567 * @param {Object} config Configuration options
36569 Roo.menu.Separator = function(config){
36570 Roo.menu.Separator.superclass.constructor.call(this, config);
36573 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
36575 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
36577 itemCls : "x-menu-sep",
36579 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
36581 hideOnClick : false,
36584 onRender : function(li){
36585 var s = document.createElement("span");
36586 s.className = this.itemCls;
36587 s.innerHTML = " ";
36589 li.addClass("x-menu-sep-li");
36590 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
36594 * Ext JS Library 1.1.1
36595 * Copyright(c) 2006-2007, Ext JS, LLC.
36597 * Originally Released Under LGPL - original licence link has changed is not relivant.
36600 * <script type="text/javascript">
36603 * @class Roo.menu.Item
36604 * @extends Roo.menu.BaseItem
36605 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
36606 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
36607 * activation and click handling.
36609 * Creates a new Item
36610 * @param {Object} config Configuration options
36612 Roo.menu.Item = function(config){
36613 Roo.menu.Item.superclass.constructor.call(this, config);
36615 this.menu = Roo.menu.MenuMgr.get(this.menu);
36618 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
36621 * @cfg {String} text
36622 * The text to show on the menu item.
36626 * @cfg {String} HTML to render in menu
36627 * The text to show on the menu item (HTML version).
36631 * @cfg {String} icon
36632 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
36636 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
36638 itemCls : "x-menu-item",
36640 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
36642 canActivate : true,
36644 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
36647 // doc'd in BaseItem
36651 ctype: "Roo.menu.Item",
36654 onRender : function(container, position){
36655 var el = document.createElement("a");
36656 el.hideFocus = true;
36657 el.unselectable = "on";
36658 el.href = this.href || "#";
36659 if(this.hrefTarget){
36660 el.target = this.hrefTarget;
36662 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
36664 var html = this.html.length ? this.html : String.format('{0}',this.text);
36666 el.innerHTML = String.format(
36667 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
36668 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
36670 Roo.menu.Item.superclass.onRender.call(this, container, position);
36674 * Sets the text to display in this menu item
36675 * @param {String} text The text to display
36676 * @param {Boolean} isHTML true to indicate text is pure html.
36678 setText : function(text, isHTML){
36686 var html = this.html.length ? this.html : String.format('{0}',this.text);
36688 this.el.update(String.format(
36689 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
36690 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
36691 this.parentMenu.autoWidth();
36696 handleClick : function(e){
36697 if(!this.href){ // if no link defined, stop the event automatically
36700 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
36704 activate : function(autoExpand){
36705 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
36715 shouldDeactivate : function(e){
36716 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
36717 if(this.menu && this.menu.isVisible()){
36718 return !this.menu.getEl().getRegion().contains(e.getPoint());
36726 deactivate : function(){
36727 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
36732 expandMenu : function(autoActivate){
36733 if(!this.disabled && this.menu){
36734 clearTimeout(this.hideTimer);
36735 delete this.hideTimer;
36736 if(!this.menu.isVisible() && !this.showTimer){
36737 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
36738 }else if (this.menu.isVisible() && autoActivate){
36739 this.menu.tryActivate(0, 1);
36745 deferExpand : function(autoActivate){
36746 delete this.showTimer;
36747 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
36749 this.menu.tryActivate(0, 1);
36754 hideMenu : function(){
36755 clearTimeout(this.showTimer);
36756 delete this.showTimer;
36757 if(!this.hideTimer && this.menu && this.menu.isVisible()){
36758 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
36763 deferHide : function(){
36764 delete this.hideTimer;
36769 * Ext JS Library 1.1.1
36770 * Copyright(c) 2006-2007, Ext JS, LLC.
36772 * Originally Released Under LGPL - original licence link has changed is not relivant.
36775 * <script type="text/javascript">
36779 * @class Roo.menu.CheckItem
36780 * @extends Roo.menu.Item
36781 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
36783 * Creates a new CheckItem
36784 * @param {Object} config Configuration options
36786 Roo.menu.CheckItem = function(config){
36787 Roo.menu.CheckItem.superclass.constructor.call(this, config);
36790 * @event beforecheckchange
36791 * Fires before the checked value is set, providing an opportunity to cancel if needed
36792 * @param {Roo.menu.CheckItem} this
36793 * @param {Boolean} checked The new checked value that will be set
36795 "beforecheckchange" : true,
36797 * @event checkchange
36798 * Fires after the checked value has been set
36799 * @param {Roo.menu.CheckItem} this
36800 * @param {Boolean} checked The checked value that was set
36802 "checkchange" : true
36804 if(this.checkHandler){
36805 this.on('checkchange', this.checkHandler, this.scope);
36808 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
36810 * @cfg {String} group
36811 * All check items with the same group name will automatically be grouped into a single-select
36812 * radio button group (defaults to '')
36815 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
36817 itemCls : "x-menu-item x-menu-check-item",
36819 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
36821 groupClass : "x-menu-group-item",
36824 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
36825 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
36826 * initialized with checked = true will be rendered as checked.
36831 ctype: "Roo.menu.CheckItem",
36834 onRender : function(c){
36835 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
36837 this.el.addClass(this.groupClass);
36839 Roo.menu.MenuMgr.registerCheckable(this);
36841 this.checked = false;
36842 this.setChecked(true, true);
36847 destroy : function(){
36849 Roo.menu.MenuMgr.unregisterCheckable(this);
36851 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
36855 * Set the checked state of this item
36856 * @param {Boolean} checked The new checked value
36857 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
36859 setChecked : function(state, suppressEvent){
36860 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
36861 if(this.container){
36862 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
36864 this.checked = state;
36865 if(suppressEvent !== true){
36866 this.fireEvent("checkchange", this, state);
36872 handleClick : function(e){
36873 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
36874 this.setChecked(!this.checked);
36876 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
36880 * Ext JS Library 1.1.1
36881 * Copyright(c) 2006-2007, Ext JS, LLC.
36883 * Originally Released Under LGPL - original licence link has changed is not relivant.
36886 * <script type="text/javascript">
36890 * @class Roo.menu.DateItem
36891 * @extends Roo.menu.Adapter
36892 * A menu item that wraps the {@link Roo.DatPicker} component.
36894 * Creates a new DateItem
36895 * @param {Object} config Configuration options
36897 Roo.menu.DateItem = function(config){
36898 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
36899 /** The Roo.DatePicker object @type Roo.DatePicker */
36900 this.picker = this.component;
36901 this.addEvents({select: true});
36903 this.picker.on("render", function(picker){
36904 picker.getEl().swallowEvent("click");
36905 picker.container.addClass("x-menu-date-item");
36908 this.picker.on("select", this.onSelect, this);
36911 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
36913 onSelect : function(picker, date){
36914 this.fireEvent("select", this, date, picker);
36915 Roo.menu.DateItem.superclass.handleClick.call(this);
36919 * Ext JS Library 1.1.1
36920 * Copyright(c) 2006-2007, Ext JS, LLC.
36922 * Originally Released Under LGPL - original licence link has changed is not relivant.
36925 * <script type="text/javascript">
36929 * @class Roo.menu.ColorItem
36930 * @extends Roo.menu.Adapter
36931 * A menu item that wraps the {@link Roo.ColorPalette} component.
36933 * Creates a new ColorItem
36934 * @param {Object} config Configuration options
36936 Roo.menu.ColorItem = function(config){
36937 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
36938 /** The Roo.ColorPalette object @type Roo.ColorPalette */
36939 this.palette = this.component;
36940 this.relayEvents(this.palette, ["select"]);
36941 if(this.selectHandler){
36942 this.on('select', this.selectHandler, this.scope);
36945 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
36947 * Ext JS Library 1.1.1
36948 * Copyright(c) 2006-2007, Ext JS, LLC.
36950 * Originally Released Under LGPL - original licence link has changed is not relivant.
36953 * <script type="text/javascript">
36958 * @class Roo.menu.DateMenu
36959 * @extends Roo.menu.Menu
36960 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
36962 * Creates a new DateMenu
36963 * @param {Object} config Configuration options
36965 Roo.menu.DateMenu = function(config){
36966 Roo.menu.DateMenu.superclass.constructor.call(this, config);
36968 var di = new Roo.menu.DateItem(config);
36971 * The {@link Roo.DatePicker} instance for this DateMenu
36974 this.picker = di.picker;
36977 * @param {DatePicker} picker
36978 * @param {Date} date
36980 this.relayEvents(di, ["select"]);
36981 this.on('beforeshow', function(){
36983 this.picker.hideMonthPicker(false);
36987 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
36991 * Ext JS Library 1.1.1
36992 * Copyright(c) 2006-2007, Ext JS, LLC.
36994 * Originally Released Under LGPL - original licence link has changed is not relivant.
36997 * <script type="text/javascript">
37002 * @class Roo.menu.ColorMenu
37003 * @extends Roo.menu.Menu
37004 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
37006 * Creates a new ColorMenu
37007 * @param {Object} config Configuration options
37009 Roo.menu.ColorMenu = function(config){
37010 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
37012 var ci = new Roo.menu.ColorItem(config);
37015 * The {@link Roo.ColorPalette} instance for this ColorMenu
37016 * @type ColorPalette
37018 this.palette = ci.palette;
37021 * @param {ColorPalette} palette
37022 * @param {String} color
37024 this.relayEvents(ci, ["select"]);
37026 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
37028 * Ext JS Library 1.1.1
37029 * Copyright(c) 2006-2007, Ext JS, LLC.
37031 * Originally Released Under LGPL - original licence link has changed is not relivant.
37034 * <script type="text/javascript">
37038 * @class Roo.form.Field
37039 * @extends Roo.BoxComponent
37040 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
37042 * Creates a new Field
37043 * @param {Object} config Configuration options
37045 Roo.form.Field = function(config){
37046 Roo.form.Field.superclass.constructor.call(this, config);
37049 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
37051 * @cfg {String} fieldLabel Label to use when rendering a form.
37054 * @cfg {String} qtip Mouse over tip
37058 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
37060 invalidClass : "x-form-invalid",
37062 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided (defaults to "The value in this field is invalid")
37064 invalidText : "The value in this field is invalid",
37066 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
37068 focusClass : "x-form-focus",
37070 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
37071 automatic validation (defaults to "keyup").
37073 validationEvent : "keyup",
37075 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
37077 validateOnBlur : true,
37079 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
37081 validationDelay : 250,
37083 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37084 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
37086 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
37088 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
37090 fieldClass : "x-form-field",
37092 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
37095 ----------- ----------------------------------------------------------------------
37096 qtip Display a quick tip when the user hovers over the field
37097 title Display a default browser title attribute popup
37098 under Add a block div beneath the field containing the error text
37099 side Add an error icon to the right of the field with a popup on hover
37100 [element id] Add the error text directly to the innerHTML of the specified element
37103 msgTarget : 'qtip',
37105 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
37110 * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only sets the element's readOnly DOM attribute.
37115 * @cfg {Boolean} disabled True to disable the field (defaults to false).
37120 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
37122 inputType : undefined,
37125 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via applyTo (defaults to undefined).
37127 tabIndex : undefined,
37130 isFormField : true,
37135 * @property {Roo.Element} fieldEl
37136 * Element Containing the rendered Field (with label etc.)
37139 * @cfg {Mixed} value A value to initialize this field with.
37144 * @cfg {String} name The field's HTML name attribute.
37147 * @cfg {String} cls A CSS class to apply to the field's underlying element.
37151 initComponent : function(){
37152 Roo.form.Field.superclass.initComponent.call(this);
37156 * Fires when this field receives input focus.
37157 * @param {Roo.form.Field} this
37162 * Fires when this field loses input focus.
37163 * @param {Roo.form.Field} this
37167 * @event specialkey
37168 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
37169 * {@link Roo.EventObject#getKey} to determine which key was pressed.
37170 * @param {Roo.form.Field} this
37171 * @param {Roo.EventObject} e The event object
37176 * Fires just before the field blurs if the field value has changed.
37177 * @param {Roo.form.Field} this
37178 * @param {Mixed} newValue The new value
37179 * @param {Mixed} oldValue The original value
37184 * Fires after the field has been marked as invalid.
37185 * @param {Roo.form.Field} this
37186 * @param {String} msg The validation message
37191 * Fires after the field has been validated with no errors.
37192 * @param {Roo.form.Field} this
37197 * Fires after the key up
37198 * @param {Roo.form.Field} this
37199 * @param {Roo.EventObject} e The event Object
37206 * Returns the name attribute of the field if available
37207 * @return {String} name The field name
37209 getName: function(){
37210 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
37214 onRender : function(ct, position){
37215 Roo.form.Field.superclass.onRender.call(this, ct, position);
37217 var cfg = this.getAutoCreate();
37219 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
37221 if (!cfg.name.length) {
37224 if(this.inputType){
37225 cfg.type = this.inputType;
37227 this.el = ct.createChild(cfg, position);
37229 var type = this.el.dom.type;
37231 if(type == 'password'){
37234 this.el.addClass('x-form-'+type);
37237 this.el.dom.readOnly = true;
37239 if(this.tabIndex !== undefined){
37240 this.el.dom.setAttribute('tabIndex', this.tabIndex);
37243 this.el.addClass([this.fieldClass, this.cls]);
37248 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
37249 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
37250 * @return {Roo.form.Field} this
37252 applyTo : function(target){
37253 this.allowDomMove = false;
37254 this.el = Roo.get(target);
37255 this.render(this.el.dom.parentNode);
37260 initValue : function(){
37261 if(this.value !== undefined){
37262 this.setValue(this.value);
37263 }else if(this.el.dom.value.length > 0){
37264 this.setValue(this.el.dom.value);
37269 * Returns true if this field has been changed since it was originally loaded and is not disabled.
37271 isDirty : function() {
37272 if(this.disabled) {
37275 return String(this.getValue()) !== String(this.originalValue);
37279 afterRender : function(){
37280 Roo.form.Field.superclass.afterRender.call(this);
37285 fireKey : function(e){
37286 //Roo.log('field ' + e.getKey());
37287 if(e.isNavKeyPress()){
37288 this.fireEvent("specialkey", this, e);
37293 * Resets the current field value to the originally loaded value and clears any validation messages
37295 reset : function(){
37296 this.setValue(this.resetValue);
37297 this.clearInvalid();
37301 initEvents : function(){
37302 // safari killled keypress - so keydown is now used..
37303 this.el.on("keydown" , this.fireKey, this);
37304 this.el.on("focus", this.onFocus, this);
37305 this.el.on("blur", this.onBlur, this);
37306 this.el.relayEvent('keyup', this);
37308 // reference to original value for reset
37309 this.originalValue = this.getValue();
37310 this.resetValue = this.getValue();
37314 onFocus : function(){
37315 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37316 this.el.addClass(this.focusClass);
37318 if(!this.hasFocus){
37319 this.hasFocus = true;
37320 this.startValue = this.getValue();
37321 this.fireEvent("focus", this);
37325 beforeBlur : Roo.emptyFn,
37328 onBlur : function(){
37330 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
37331 this.el.removeClass(this.focusClass);
37333 this.hasFocus = false;
37334 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
37337 var v = this.getValue();
37338 if(String(v) !== String(this.startValue)){
37339 this.fireEvent('change', this, v, this.startValue);
37341 this.fireEvent("blur", this);
37345 * Returns whether or not the field value is currently valid
37346 * @param {Boolean} preventMark True to disable marking the field invalid
37347 * @return {Boolean} True if the value is valid, else false
37349 isValid : function(preventMark){
37353 var restore = this.preventMark;
37354 this.preventMark = preventMark === true;
37355 var v = this.validateValue(this.processValue(this.getRawValue()));
37356 this.preventMark = restore;
37361 * Validates the field value
37362 * @return {Boolean} True if the value is valid, else false
37364 validate : function(){
37365 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
37366 this.clearInvalid();
37372 processValue : function(value){
37377 // Subclasses should provide the validation implementation by overriding this
37378 validateValue : function(value){
37383 * Mark this field as invalid
37384 * @param {String} msg The validation message
37386 markInvalid : function(msg){
37387 if(!this.rendered || this.preventMark){ // not rendered
37391 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37393 obj.el.addClass(this.invalidClass);
37394 msg = msg || this.invalidText;
37395 switch(this.msgTarget){
37397 obj.el.dom.qtip = msg;
37398 obj.el.dom.qclass = 'x-form-invalid-tip';
37399 if(Roo.QuickTips){ // fix for floating editors interacting with DND
37400 Roo.QuickTips.enable();
37404 this.el.dom.title = msg;
37408 var elp = this.el.findParent('.x-form-element', 5, true);
37409 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
37410 this.errorEl.setWidth(elp.getWidth(true)-20);
37412 this.errorEl.update(msg);
37413 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
37416 if(!this.errorIcon){
37417 var elp = this.el.findParent('.x-form-element', 5, true);
37418 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
37420 this.alignErrorIcon();
37421 this.errorIcon.dom.qtip = msg;
37422 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
37423 this.errorIcon.show();
37424 this.on('resize', this.alignErrorIcon, this);
37427 var t = Roo.getDom(this.msgTarget);
37429 t.style.display = this.msgDisplay;
37432 this.fireEvent('invalid', this, msg);
37436 alignErrorIcon : function(){
37437 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
37441 * Clear any invalid styles/messages for this field
37443 clearInvalid : function(){
37444 if(!this.rendered || this.preventMark){ // not rendered
37447 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
37449 obj.el.removeClass(this.invalidClass);
37450 switch(this.msgTarget){
37452 obj.el.dom.qtip = '';
37455 this.el.dom.title = '';
37459 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
37463 if(this.errorIcon){
37464 this.errorIcon.dom.qtip = '';
37465 this.errorIcon.hide();
37466 this.un('resize', this.alignErrorIcon, this);
37470 var t = Roo.getDom(this.msgTarget);
37472 t.style.display = 'none';
37475 this.fireEvent('valid', this);
37479 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
37480 * @return {Mixed} value The field value
37482 getRawValue : function(){
37483 var v = this.el.getValue();
37489 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
37490 * @return {Mixed} value The field value
37492 getValue : function(){
37493 var v = this.el.getValue();
37499 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
37500 * @param {Mixed} value The value to set
37502 setRawValue : function(v){
37503 return this.el.dom.value = (v === null || v === undefined ? '' : v);
37507 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
37508 * @param {Mixed} value The value to set
37510 setValue : function(v){
37513 this.el.dom.value = (v === null || v === undefined ? '' : v);
37518 adjustSize : function(w, h){
37519 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
37520 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
37524 adjustWidth : function(tag, w){
37525 tag = tag.toLowerCase();
37526 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
37527 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
37528 if(tag == 'input'){
37531 if(tag == 'textarea'){
37534 }else if(Roo.isOpera){
37535 if(tag == 'input'){
37538 if(tag == 'textarea'){
37548 // anything other than normal should be considered experimental
37549 Roo.form.Field.msgFx = {
37551 show: function(msgEl, f){
37552 msgEl.setDisplayed('block');
37555 hide : function(msgEl, f){
37556 msgEl.setDisplayed(false).update('');
37561 show: function(msgEl, f){
37562 msgEl.slideIn('t', {stopFx:true});
37565 hide : function(msgEl, f){
37566 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
37571 show: function(msgEl, f){
37572 msgEl.fixDisplay();
37573 msgEl.alignTo(f.el, 'tl-tr');
37574 msgEl.slideIn('l', {stopFx:true});
37577 hide : function(msgEl, f){
37578 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
37583 * Ext JS Library 1.1.1
37584 * Copyright(c) 2006-2007, Ext JS, LLC.
37586 * Originally Released Under LGPL - original licence link has changed is not relivant.
37589 * <script type="text/javascript">
37594 * @class Roo.form.TextField
37595 * @extends Roo.form.Field
37596 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
37597 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
37599 * Creates a new TextField
37600 * @param {Object} config Configuration options
37602 Roo.form.TextField = function(config){
37603 Roo.form.TextField.superclass.constructor.call(this, config);
37607 * Fires when the autosize function is triggered. The field may or may not have actually changed size
37608 * according to the default logic, but this event provides a hook for the developer to apply additional
37609 * logic at runtime to resize the field if needed.
37610 * @param {Roo.form.Field} this This text field
37611 * @param {Number} width The new field width
37617 Roo.extend(Roo.form.TextField, Roo.form.Field, {
37619 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
37623 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
37627 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
37631 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
37635 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
37639 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
37641 disableKeyFilter : false,
37643 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
37647 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
37651 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
37653 maxLength : Number.MAX_VALUE,
37655 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
37657 minLengthText : "The minimum length for this field is {0}",
37659 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
37661 maxLengthText : "The maximum length for this field is {0}",
37663 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
37665 selectOnFocus : false,
37667 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
37669 blankText : "This field is required",
37671 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
37672 * If available, this function will be called only after the basic validators all return true, and will be passed the
37673 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
37677 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
37678 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
37679 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
37683 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
37687 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
37693 initEvents : function()
37695 if (this.emptyText) {
37696 this.el.attr('placeholder', this.emptyText);
37699 Roo.form.TextField.superclass.initEvents.call(this);
37700 if(this.validationEvent == 'keyup'){
37701 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
37702 this.el.on('keyup', this.filterValidation, this);
37704 else if(this.validationEvent !== false){
37705 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
37708 if(this.selectOnFocus){
37709 this.on("focus", this.preFocus, this);
37712 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
37713 this.el.on("keypress", this.filterKeys, this);
37716 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
37717 this.el.on("click", this.autoSize, this);
37719 if(this.el.is('input[type=password]') && Roo.isSafari){
37720 this.el.on('keydown', this.SafariOnKeyDown, this);
37724 processValue : function(value){
37725 if(this.stripCharsRe){
37726 var newValue = value.replace(this.stripCharsRe, '');
37727 if(newValue !== value){
37728 this.setRawValue(newValue);
37735 filterValidation : function(e){
37736 if(!e.isNavKeyPress()){
37737 this.validationTask.delay(this.validationDelay);
37742 onKeyUp : function(e){
37743 if(!e.isNavKeyPress()){
37749 * Resets the current field value to the originally-loaded value and clears any validation messages.
37752 reset : function(){
37753 Roo.form.TextField.superclass.reset.call(this);
37759 preFocus : function(){
37761 if(this.selectOnFocus){
37762 this.el.dom.select();
37768 filterKeys : function(e){
37769 var k = e.getKey();
37770 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
37773 var c = e.getCharCode(), cc = String.fromCharCode(c);
37774 if(Roo.isIE && (e.isSpecialKey() || !cc)){
37777 if(!this.maskRe.test(cc)){
37782 setValue : function(v){
37784 Roo.form.TextField.superclass.setValue.apply(this, arguments);
37790 * Validates a value according to the field's validation rules and marks the field as invalid
37791 * if the validation fails
37792 * @param {Mixed} value The value to validate
37793 * @return {Boolean} True if the value is valid, else false
37795 validateValue : function(value){
37796 if(value.length < 1) { // if it's blank
37797 if(this.allowBlank){
37798 this.clearInvalid();
37801 this.markInvalid(this.blankText);
37805 if(value.length < this.minLength){
37806 this.markInvalid(String.format(this.minLengthText, this.minLength));
37809 if(value.length > this.maxLength){
37810 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
37814 var vt = Roo.form.VTypes;
37815 if(!vt[this.vtype](value, this)){
37816 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
37820 if(typeof this.validator == "function"){
37821 var msg = this.validator(value);
37823 this.markInvalid(msg);
37827 if(this.regex && !this.regex.test(value)){
37828 this.markInvalid(this.regexText);
37835 * Selects text in this field
37836 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
37837 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
37839 selectText : function(start, end){
37840 var v = this.getRawValue();
37842 start = start === undefined ? 0 : start;
37843 end = end === undefined ? v.length : end;
37844 var d = this.el.dom;
37845 if(d.setSelectionRange){
37846 d.setSelectionRange(start, end);
37847 }else if(d.createTextRange){
37848 var range = d.createTextRange();
37849 range.moveStart("character", start);
37850 range.moveEnd("character", v.length-end);
37857 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
37858 * This only takes effect if grow = true, and fires the autosize event.
37860 autoSize : function(){
37861 if(!this.grow || !this.rendered){
37865 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
37868 var v = el.dom.value;
37869 var d = document.createElement('div');
37870 d.appendChild(document.createTextNode(v));
37874 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
37875 this.el.setWidth(w);
37876 this.fireEvent("autosize", this, w);
37880 SafariOnKeyDown : function(event)
37882 // this is a workaround for a password hang bug on chrome/ webkit.
37884 var isSelectAll = false;
37886 if(this.el.dom.selectionEnd > 0){
37887 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
37889 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
37890 event.preventDefault();
37895 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
37897 event.preventDefault();
37898 // this is very hacky as keydown always get's upper case.
37900 var cc = String.fromCharCode(event.getCharCode());
37903 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
37911 * Ext JS Library 1.1.1
37912 * Copyright(c) 2006-2007, Ext JS, LLC.
37914 * Originally Released Under LGPL - original licence link has changed is not relivant.
37917 * <script type="text/javascript">
37921 * @class Roo.form.Hidden
37922 * @extends Roo.form.TextField
37923 * Simple Hidden element used on forms
37925 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
37928 * Creates a new Hidden form element.
37929 * @param {Object} config Configuration options
37934 // easy hidden field...
37935 Roo.form.Hidden = function(config){
37936 Roo.form.Hidden.superclass.constructor.call(this, config);
37939 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
37941 inputType: 'hidden',
37944 labelSeparator: '',
37946 itemCls : 'x-form-item-display-none'
37954 * Ext JS Library 1.1.1
37955 * Copyright(c) 2006-2007, Ext JS, LLC.
37957 * Originally Released Under LGPL - original licence link has changed is not relivant.
37960 * <script type="text/javascript">
37964 * @class Roo.form.TriggerField
37965 * @extends Roo.form.TextField
37966 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
37967 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
37968 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
37969 * for which you can provide a custom implementation. For example:
37971 var trigger = new Roo.form.TriggerField();
37972 trigger.onTriggerClick = myTriggerFn;
37973 trigger.applyTo('my-field');
37976 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
37977 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
37978 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
37979 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
37981 * Create a new TriggerField.
37982 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
37983 * to the base TextField)
37985 Roo.form.TriggerField = function(config){
37986 this.mimicing = false;
37987 Roo.form.TriggerField.superclass.constructor.call(this, config);
37990 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
37992 * @cfg {String} triggerClass A CSS class to apply to the trigger
37995 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
37996 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
37998 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
38000 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
38004 /** @cfg {Boolean} grow @hide */
38005 /** @cfg {Number} growMin @hide */
38006 /** @cfg {Number} growMax @hide */
38012 autoSize: Roo.emptyFn,
38016 deferHeight : true,
38019 actionMode : 'wrap',
38021 onResize : function(w, h){
38022 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
38023 if(typeof w == 'number'){
38024 var x = w - this.trigger.getWidth();
38025 this.el.setWidth(this.adjustWidth('input', x));
38026 this.trigger.setStyle('left', x+'px');
38031 adjustSize : Roo.BoxComponent.prototype.adjustSize,
38034 getResizeEl : function(){
38039 getPositionEl : function(){
38044 alignErrorIcon : function(){
38045 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
38049 onRender : function(ct, position){
38050 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
38051 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
38052 this.trigger = this.wrap.createChild(this.triggerConfig ||
38053 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
38054 if(this.hideTrigger){
38055 this.trigger.setDisplayed(false);
38057 this.initTrigger();
38059 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
38064 initTrigger : function(){
38065 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
38066 this.trigger.addClassOnOver('x-form-trigger-over');
38067 this.trigger.addClassOnClick('x-form-trigger-click');
38071 onDestroy : function(){
38073 this.trigger.removeAllListeners();
38074 this.trigger.remove();
38077 this.wrap.remove();
38079 Roo.form.TriggerField.superclass.onDestroy.call(this);
38083 onFocus : function(){
38084 Roo.form.TriggerField.superclass.onFocus.call(this);
38085 if(!this.mimicing){
38086 this.wrap.addClass('x-trigger-wrap-focus');
38087 this.mimicing = true;
38088 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
38089 if(this.monitorTab){
38090 this.el.on("keydown", this.checkTab, this);
38096 checkTab : function(e){
38097 if(e.getKey() == e.TAB){
38098 this.triggerBlur();
38103 onBlur : function(){
38108 mimicBlur : function(e, t){
38109 if(!this.wrap.contains(t) && this.validateBlur()){
38110 this.triggerBlur();
38115 triggerBlur : function(){
38116 this.mimicing = false;
38117 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
38118 if(this.monitorTab){
38119 this.el.un("keydown", this.checkTab, this);
38121 this.wrap.removeClass('x-trigger-wrap-focus');
38122 Roo.form.TriggerField.superclass.onBlur.call(this);
38126 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
38127 validateBlur : function(e, t){
38132 onDisable : function(){
38133 Roo.form.TriggerField.superclass.onDisable.call(this);
38135 this.wrap.addClass('x-item-disabled');
38140 onEnable : function(){
38141 Roo.form.TriggerField.superclass.onEnable.call(this);
38143 this.wrap.removeClass('x-item-disabled');
38148 onShow : function(){
38149 var ae = this.getActionEl();
38152 ae.dom.style.display = '';
38153 ae.dom.style.visibility = 'visible';
38159 onHide : function(){
38160 var ae = this.getActionEl();
38161 ae.dom.style.display = 'none';
38165 * The function that should handle the trigger's click event. This method does nothing by default until overridden
38166 * by an implementing function.
38168 * @param {EventObject} e
38170 onTriggerClick : Roo.emptyFn
38173 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
38174 // to be extended by an implementing class. For an example of implementing this class, see the custom
38175 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
38176 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
38177 initComponent : function(){
38178 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
38180 this.triggerConfig = {
38181 tag:'span', cls:'x-form-twin-triggers', cn:[
38182 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
38183 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
38187 getTrigger : function(index){
38188 return this.triggers[index];
38191 initTrigger : function(){
38192 var ts = this.trigger.select('.x-form-trigger', true);
38193 this.wrap.setStyle('overflow', 'hidden');
38194 var triggerField = this;
38195 ts.each(function(t, all, index){
38196 t.hide = function(){
38197 var w = triggerField.wrap.getWidth();
38198 this.dom.style.display = 'none';
38199 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38201 t.show = function(){
38202 var w = triggerField.wrap.getWidth();
38203 this.dom.style.display = '';
38204 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
38206 var triggerIndex = 'Trigger'+(index+1);
38208 if(this['hide'+triggerIndex]){
38209 t.dom.style.display = 'none';
38211 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
38212 t.addClassOnOver('x-form-trigger-over');
38213 t.addClassOnClick('x-form-trigger-click');
38215 this.triggers = ts.elements;
38218 onTrigger1Click : Roo.emptyFn,
38219 onTrigger2Click : Roo.emptyFn
38222 * Ext JS Library 1.1.1
38223 * Copyright(c) 2006-2007, Ext JS, LLC.
38225 * Originally Released Under LGPL - original licence link has changed is not relivant.
38228 * <script type="text/javascript">
38232 * @class Roo.form.TextArea
38233 * @extends Roo.form.TextField
38234 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
38235 * support for auto-sizing.
38237 * Creates a new TextArea
38238 * @param {Object} config Configuration options
38240 Roo.form.TextArea = function(config){
38241 Roo.form.TextArea.superclass.constructor.call(this, config);
38242 // these are provided exchanges for backwards compat
38243 // minHeight/maxHeight were replaced by growMin/growMax to be
38244 // compatible with TextField growing config values
38245 if(this.minHeight !== undefined){
38246 this.growMin = this.minHeight;
38248 if(this.maxHeight !== undefined){
38249 this.growMax = this.maxHeight;
38253 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
38255 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
38259 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
38263 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
38264 * in the field (equivalent to setting overflow: hidden, defaults to false)
38266 preventScrollbars: false,
38268 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38269 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
38273 onRender : function(ct, position){
38275 this.defaultAutoCreate = {
38277 style:"width:300px;height:60px;",
38278 autocomplete: "new-password"
38281 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
38283 this.textSizeEl = Roo.DomHelper.append(document.body, {
38284 tag: "pre", cls: "x-form-grow-sizer"
38286 if(this.preventScrollbars){
38287 this.el.setStyle("overflow", "hidden");
38289 this.el.setHeight(this.growMin);
38293 onDestroy : function(){
38294 if(this.textSizeEl){
38295 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
38297 Roo.form.TextArea.superclass.onDestroy.call(this);
38301 onKeyUp : function(e){
38302 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
38308 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
38309 * This only takes effect if grow = true, and fires the autosize event if the height changes.
38311 autoSize : function(){
38312 if(!this.grow || !this.textSizeEl){
38316 var v = el.dom.value;
38317 var ts = this.textSizeEl;
38320 ts.appendChild(document.createTextNode(v));
38323 Roo.fly(ts).setWidth(this.el.getWidth());
38325 v = "  ";
38328 v = v.replace(/\n/g, '<p> </p>');
38330 v += " \n ";
38333 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
38334 if(h != this.lastHeight){
38335 this.lastHeight = h;
38336 this.el.setHeight(h);
38337 this.fireEvent("autosize", this, h);
38342 * Ext JS Library 1.1.1
38343 * Copyright(c) 2006-2007, Ext JS, LLC.
38345 * Originally Released Under LGPL - original licence link has changed is not relivant.
38348 * <script type="text/javascript">
38353 * @class Roo.form.NumberField
38354 * @extends Roo.form.TextField
38355 * Numeric text field that provides automatic keystroke filtering and numeric validation.
38357 * Creates a new NumberField
38358 * @param {Object} config Configuration options
38360 Roo.form.NumberField = function(config){
38361 Roo.form.NumberField.superclass.constructor.call(this, config);
38364 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
38366 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
38368 fieldClass: "x-form-field x-form-num-field",
38370 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
38372 allowDecimals : true,
38374 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
38376 decimalSeparator : ".",
38378 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
38380 decimalPrecision : 2,
38382 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
38384 allowNegative : true,
38386 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
38388 minValue : Number.NEGATIVE_INFINITY,
38390 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
38392 maxValue : Number.MAX_VALUE,
38394 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
38396 minText : "The minimum value for this field is {0}",
38398 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
38400 maxText : "The maximum value for this field is {0}",
38402 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
38403 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
38405 nanText : "{0} is not a valid number",
38408 initEvents : function(){
38409 Roo.form.NumberField.superclass.initEvents.call(this);
38410 var allowed = "0123456789";
38411 if(this.allowDecimals){
38412 allowed += this.decimalSeparator;
38414 if(this.allowNegative){
38417 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
38418 var keyPress = function(e){
38419 var k = e.getKey();
38420 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
38423 var c = e.getCharCode();
38424 if(allowed.indexOf(String.fromCharCode(c)) === -1){
38428 this.el.on("keypress", keyPress, this);
38432 validateValue : function(value){
38433 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
38436 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38439 var num = this.parseValue(value);
38441 this.markInvalid(String.format(this.nanText, value));
38444 if(num < this.minValue){
38445 this.markInvalid(String.format(this.minText, this.minValue));
38448 if(num > this.maxValue){
38449 this.markInvalid(String.format(this.maxText, this.maxValue));
38455 getValue : function(){
38456 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
38460 parseValue : function(value){
38461 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
38462 return isNaN(value) ? '' : value;
38466 fixPrecision : function(value){
38467 var nan = isNaN(value);
38468 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
38469 return nan ? '' : value;
38471 return parseFloat(value).toFixed(this.decimalPrecision);
38474 setValue : function(v){
38475 v = this.fixPrecision(v);
38476 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
38480 decimalPrecisionFcn : function(v){
38481 return Math.floor(v);
38484 beforeBlur : function(){
38485 var v = this.parseValue(this.getRawValue());
38492 * Ext JS Library 1.1.1
38493 * Copyright(c) 2006-2007, Ext JS, LLC.
38495 * Originally Released Under LGPL - original licence link has changed is not relivant.
38498 * <script type="text/javascript">
38502 * @class Roo.form.DateField
38503 * @extends Roo.form.TriggerField
38504 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38506 * Create a new DateField
38507 * @param {Object} config
38509 Roo.form.DateField = function(config){
38510 Roo.form.DateField.superclass.constructor.call(this, config);
38516 * Fires when a date is selected
38517 * @param {Roo.form.DateField} combo This combo box
38518 * @param {Date} date The date selected
38525 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38526 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38527 this.ddMatch = null;
38528 if(this.disabledDates){
38529 var dd = this.disabledDates;
38531 for(var i = 0; i < dd.length; i++){
38533 if(i != dd.length-1) re += "|";
38535 this.ddMatch = new RegExp(re + ")");
38539 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
38541 * @cfg {String} format
38542 * The default date format string which can be overriden for localization support. The format must be
38543 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38547 * @cfg {String} altFormats
38548 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38549 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38551 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
38553 * @cfg {Array} disabledDays
38554 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38556 disabledDays : null,
38558 * @cfg {String} disabledDaysText
38559 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38561 disabledDaysText : "Disabled",
38563 * @cfg {Array} disabledDates
38564 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38565 * expression so they are very powerful. Some examples:
38567 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38568 * <li>["03/08", "09/16"] would disable those days for every year</li>
38569 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38570 * <li>["03/../2006"] would disable every day in March 2006</li>
38571 * <li>["^03"] would disable every day in every March</li>
38573 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38574 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38576 disabledDates : null,
38578 * @cfg {String} disabledDatesText
38579 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38581 disabledDatesText : "Disabled",
38583 * @cfg {Date/String} minValue
38584 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38585 * valid format (defaults to null).
38589 * @cfg {Date/String} maxValue
38590 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38591 * valid format (defaults to null).
38595 * @cfg {String} minText
38596 * The error text to display when the date in the cell is before minValue (defaults to
38597 * 'The date in this field must be after {minValue}').
38599 minText : "The date in this field must be equal to or after {0}",
38601 * @cfg {String} maxText
38602 * The error text to display when the date in the cell is after maxValue (defaults to
38603 * 'The date in this field must be before {maxValue}').
38605 maxText : "The date in this field must be equal to or before {0}",
38607 * @cfg {String} invalidText
38608 * The error text to display when the date in the field is invalid (defaults to
38609 * '{value} is not a valid date - it must be in the format {format}').
38611 invalidText : "{0} is not a valid date - it must be in the format {1}",
38613 * @cfg {String} triggerClass
38614 * An additional CSS class used to style the trigger button. The trigger will always get the
38615 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38616 * which displays a calendar icon).
38618 triggerClass : 'x-form-date-trigger',
38622 * @cfg {Boolean} useIso
38623 * if enabled, then the date field will use a hidden field to store the
38624 * real value as iso formated date. default (false)
38628 * @cfg {String/Object} autoCreate
38629 * A DomHelper element spec, or true for a default element spec (defaults to
38630 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38633 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
38636 hiddenField: false,
38638 onRender : function(ct, position)
38640 Roo.form.DateField.superclass.onRender.call(this, ct, position);
38642 //this.el.dom.removeAttribute('name');
38643 Roo.log("Changing name?");
38644 this.el.dom.setAttribute('name', this.name + '____hidden___' );
38645 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
38647 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
38648 // prevent input submission
38649 this.hiddenName = this.name;
38656 validateValue : function(value)
38658 value = this.formatDate(value);
38659 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
38660 Roo.log('super failed');
38663 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
38666 var svalue = value;
38667 value = this.parseDate(value);
38669 Roo.log('parse date failed' + svalue);
38670 this.markInvalid(String.format(this.invalidText, svalue, this.format));
38673 var time = value.getTime();
38674 if(this.minValue && time < this.minValue.getTime()){
38675 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
38678 if(this.maxValue && time > this.maxValue.getTime()){
38679 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
38682 if(this.disabledDays){
38683 var day = value.getDay();
38684 for(var i = 0; i < this.disabledDays.length; i++) {
38685 if(day === this.disabledDays[i]){
38686 this.markInvalid(this.disabledDaysText);
38691 var fvalue = this.formatDate(value);
38692 if(this.ddMatch && this.ddMatch.test(fvalue)){
38693 this.markInvalid(String.format(this.disabledDatesText, fvalue));
38700 // Provides logic to override the default TriggerField.validateBlur which just returns true
38701 validateBlur : function(){
38702 return !this.menu || !this.menu.isVisible();
38705 getName: function()
38707 // returns hidden if it's set..
38708 if (!this.rendered) {return ''};
38709 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38714 * Returns the current date value of the date field.
38715 * @return {Date} The date value
38717 getValue : function(){
38719 return this.hiddenField ?
38720 this.hiddenField.value :
38721 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
38725 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
38726 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
38727 * (the default format used is "m/d/y").
38730 //All of these calls set the same date value (May 4, 2006)
38732 //Pass a date object:
38733 var dt = new Date('5/4/06');
38734 dateField.setValue(dt);
38736 //Pass a date string (default format):
38737 dateField.setValue('5/4/06');
38739 //Pass a date string (custom format):
38740 dateField.format = 'Y-m-d';
38741 dateField.setValue('2006-5-4');
38743 * @param {String/Date} date The date or valid date string
38745 setValue : function(date){
38746 if (this.hiddenField) {
38747 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
38749 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
38750 // make sure the value field is always stored as a date..
38751 this.value = this.parseDate(date);
38757 parseDate : function(value){
38758 if(!value || value instanceof Date){
38761 var v = Date.parseDate(value, this.format);
38762 if (!v && this.useIso) {
38763 v = Date.parseDate(value, 'Y-m-d');
38765 if(!v && this.altFormats){
38766 if(!this.altFormatsArray){
38767 this.altFormatsArray = this.altFormats.split("|");
38769 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
38770 v = Date.parseDate(value, this.altFormatsArray[i]);
38777 formatDate : function(date, fmt){
38778 return (!date || !(date instanceof Date)) ?
38779 date : date.dateFormat(fmt || this.format);
38784 select: function(m, d){
38787 this.fireEvent('select', this, d);
38789 show : function(){ // retain focus styling
38793 this.focus.defer(10, this);
38794 var ml = this.menuListeners;
38795 this.menu.un("select", ml.select, this);
38796 this.menu.un("show", ml.show, this);
38797 this.menu.un("hide", ml.hide, this);
38802 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
38803 onTriggerClick : function(){
38807 if(this.menu == null){
38808 this.menu = new Roo.menu.DateMenu();
38810 Roo.apply(this.menu.picker, {
38811 showClear: this.allowBlank,
38812 minDate : this.minValue,
38813 maxDate : this.maxValue,
38814 disabledDatesRE : this.ddMatch,
38815 disabledDatesText : this.disabledDatesText,
38816 disabledDays : this.disabledDays,
38817 disabledDaysText : this.disabledDaysText,
38818 format : this.useIso ? 'Y-m-d' : this.format,
38819 minText : String.format(this.minText, this.formatDate(this.minValue)),
38820 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
38822 this.menu.on(Roo.apply({}, this.menuListeners, {
38825 this.menu.picker.setValue(this.getValue() || new Date());
38826 this.menu.show(this.el, "tl-bl?");
38829 beforeBlur : function(){
38830 var v = this.parseDate(this.getRawValue());
38840 isDirty : function() {
38841 if(this.disabled) {
38845 if(typeof(this.startValue) === 'undefined'){
38849 return String(this.getValue()) !== String(this.startValue);
38854 * Ext JS Library 1.1.1
38855 * Copyright(c) 2006-2007, Ext JS, LLC.
38857 * Originally Released Under LGPL - original licence link has changed is not relivant.
38860 * <script type="text/javascript">
38864 * @class Roo.form.MonthField
38865 * @extends Roo.form.TriggerField
38866 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
38868 * Create a new MonthField
38869 * @param {Object} config
38871 Roo.form.MonthField = function(config){
38873 Roo.form.MonthField.superclass.constructor.call(this, config);
38879 * Fires when a date is selected
38880 * @param {Roo.form.MonthFieeld} combo This combo box
38881 * @param {Date} date The date selected
38888 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
38889 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
38890 this.ddMatch = null;
38891 if(this.disabledDates){
38892 var dd = this.disabledDates;
38894 for(var i = 0; i < dd.length; i++){
38896 if(i != dd.length-1) re += "|";
38898 this.ddMatch = new RegExp(re + ")");
38902 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
38904 * @cfg {String} format
38905 * The default date format string which can be overriden for localization support. The format must be
38906 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
38910 * @cfg {String} altFormats
38911 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
38912 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
38914 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
38916 * @cfg {Array} disabledDays
38917 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
38919 disabledDays : [0,1,2,3,4,5,6],
38921 * @cfg {String} disabledDaysText
38922 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
38924 disabledDaysText : "Disabled",
38926 * @cfg {Array} disabledDates
38927 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
38928 * expression so they are very powerful. Some examples:
38930 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
38931 * <li>["03/08", "09/16"] would disable those days for every year</li>
38932 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
38933 * <li>["03/../2006"] would disable every day in March 2006</li>
38934 * <li>["^03"] would disable every day in every March</li>
38936 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
38937 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
38939 disabledDates : null,
38941 * @cfg {String} disabledDatesText
38942 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
38944 disabledDatesText : "Disabled",
38946 * @cfg {Date/String} minValue
38947 * The minimum allowed date. Can be either a Javascript date object or a string date in a
38948 * valid format (defaults to null).
38952 * @cfg {Date/String} maxValue
38953 * The maximum allowed date. Can be either a Javascript date object or a string date in a
38954 * valid format (defaults to null).
38958 * @cfg {String} minText
38959 * The error text to display when the date in the cell is before minValue (defaults to
38960 * 'The date in this field must be after {minValue}').
38962 minText : "The date in this field must be equal to or after {0}",
38964 * @cfg {String} maxTextf
38965 * The error text to display when the date in the cell is after maxValue (defaults to
38966 * 'The date in this field must be before {maxValue}').
38968 maxText : "The date in this field must be equal to or before {0}",
38970 * @cfg {String} invalidText
38971 * The error text to display when the date in the field is invalid (defaults to
38972 * '{value} is not a valid date - it must be in the format {format}').
38974 invalidText : "{0} is not a valid date - it must be in the format {1}",
38976 * @cfg {String} triggerClass
38977 * An additional CSS class used to style the trigger button. The trigger will always get the
38978 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
38979 * which displays a calendar icon).
38981 triggerClass : 'x-form-date-trigger',
38985 * @cfg {Boolean} useIso
38986 * if enabled, then the date field will use a hidden field to store the
38987 * real value as iso formated date. default (true)
38991 * @cfg {String/Object} autoCreate
38992 * A DomHelper element spec, or true for a default element spec (defaults to
38993 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
38996 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
38999 hiddenField: false,
39001 hideMonthPicker : false,
39003 onRender : function(ct, position)
39005 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
39007 this.el.dom.removeAttribute('name');
39008 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
39010 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
39011 // prevent input submission
39012 this.hiddenName = this.name;
39019 validateValue : function(value)
39021 value = this.formatDate(value);
39022 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
39025 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
39028 var svalue = value;
39029 value = this.parseDate(value);
39031 this.markInvalid(String.format(this.invalidText, svalue, this.format));
39034 var time = value.getTime();
39035 if(this.minValue && time < this.minValue.getTime()){
39036 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
39039 if(this.maxValue && time > this.maxValue.getTime()){
39040 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
39043 /*if(this.disabledDays){
39044 var day = value.getDay();
39045 for(var i = 0; i < this.disabledDays.length; i++) {
39046 if(day === this.disabledDays[i]){
39047 this.markInvalid(this.disabledDaysText);
39053 var fvalue = this.formatDate(value);
39054 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
39055 this.markInvalid(String.format(this.disabledDatesText, fvalue));
39063 // Provides logic to override the default TriggerField.validateBlur which just returns true
39064 validateBlur : function(){
39065 return !this.menu || !this.menu.isVisible();
39069 * Returns the current date value of the date field.
39070 * @return {Date} The date value
39072 getValue : function(){
39076 return this.hiddenField ?
39077 this.hiddenField.value :
39078 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
39082 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
39083 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
39084 * (the default format used is "m/d/y").
39087 //All of these calls set the same date value (May 4, 2006)
39089 //Pass a date object:
39090 var dt = new Date('5/4/06');
39091 monthField.setValue(dt);
39093 //Pass a date string (default format):
39094 monthField.setValue('5/4/06');
39096 //Pass a date string (custom format):
39097 monthField.format = 'Y-m-d';
39098 monthField.setValue('2006-5-4');
39100 * @param {String/Date} date The date or valid date string
39102 setValue : function(date){
39103 Roo.log('month setValue' + date);
39104 // can only be first of month..
39106 var val = this.parseDate(date);
39108 if (this.hiddenField) {
39109 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
39111 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
39112 this.value = this.parseDate(date);
39116 parseDate : function(value){
39117 if(!value || value instanceof Date){
39118 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
39121 var v = Date.parseDate(value, this.format);
39122 if (!v && this.useIso) {
39123 v = Date.parseDate(value, 'Y-m-d');
39127 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
39131 if(!v && this.altFormats){
39132 if(!this.altFormatsArray){
39133 this.altFormatsArray = this.altFormats.split("|");
39135 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
39136 v = Date.parseDate(value, this.altFormatsArray[i]);
39143 formatDate : function(date, fmt){
39144 return (!date || !(date instanceof Date)) ?
39145 date : date.dateFormat(fmt || this.format);
39150 select: function(m, d){
39152 this.fireEvent('select', this, d);
39154 show : function(){ // retain focus styling
39158 this.focus.defer(10, this);
39159 var ml = this.menuListeners;
39160 this.menu.un("select", ml.select, this);
39161 this.menu.un("show", ml.show, this);
39162 this.menu.un("hide", ml.hide, this);
39166 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
39167 onTriggerClick : function(){
39171 if(this.menu == null){
39172 this.menu = new Roo.menu.DateMenu();
39176 Roo.apply(this.menu.picker, {
39178 showClear: this.allowBlank,
39179 minDate : this.minValue,
39180 maxDate : this.maxValue,
39181 disabledDatesRE : this.ddMatch,
39182 disabledDatesText : this.disabledDatesText,
39184 format : this.useIso ? 'Y-m-d' : this.format,
39185 minText : String.format(this.minText, this.formatDate(this.minValue)),
39186 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
39189 this.menu.on(Roo.apply({}, this.menuListeners, {
39197 // hide month picker get's called when we called by 'before hide';
39199 var ignorehide = true;
39200 p.hideMonthPicker = function(disableAnim){
39204 if(this.monthPicker){
39205 Roo.log("hideMonthPicker called");
39206 if(disableAnim === true){
39207 this.monthPicker.hide();
39209 this.monthPicker.slideOut('t', {duration:.2});
39210 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
39211 p.fireEvent("select", this, this.value);
39217 Roo.log('picker set value');
39218 Roo.log(this.getValue());
39219 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
39220 m.show(this.el, 'tl-bl?');
39221 ignorehide = false;
39222 // this will trigger hideMonthPicker..
39225 // hidden the day picker
39226 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
39232 p.showMonthPicker.defer(100, p);
39238 beforeBlur : function(){
39239 var v = this.parseDate(this.getRawValue());
39245 /** @cfg {Boolean} grow @hide */
39246 /** @cfg {Number} growMin @hide */
39247 /** @cfg {Number} growMax @hide */
39254 * Ext JS Library 1.1.1
39255 * Copyright(c) 2006-2007, Ext JS, LLC.
39257 * Originally Released Under LGPL - original licence link has changed is not relivant.
39260 * <script type="text/javascript">
39265 * @class Roo.form.ComboBox
39266 * @extends Roo.form.TriggerField
39267 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
39269 * Create a new ComboBox.
39270 * @param {Object} config Configuration options
39272 Roo.form.ComboBox = function(config){
39273 Roo.form.ComboBox.superclass.constructor.call(this, config);
39277 * Fires when the dropdown list is expanded
39278 * @param {Roo.form.ComboBox} combo This combo box
39283 * Fires when the dropdown list is collapsed
39284 * @param {Roo.form.ComboBox} combo This combo box
39288 * @event beforeselect
39289 * Fires before a list item is selected. Return false to cancel the selection.
39290 * @param {Roo.form.ComboBox} combo This combo box
39291 * @param {Roo.data.Record} record The data record returned from the underlying store
39292 * @param {Number} index The index of the selected item in the dropdown list
39294 'beforeselect' : true,
39297 * Fires when a list item is selected
39298 * @param {Roo.form.ComboBox} combo This combo box
39299 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
39300 * @param {Number} index The index of the selected item in the dropdown list
39304 * @event beforequery
39305 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
39306 * The event object passed has these properties:
39307 * @param {Roo.form.ComboBox} combo This combo box
39308 * @param {String} query The query
39309 * @param {Boolean} forceAll true to force "all" query
39310 * @param {Boolean} cancel true to cancel the query
39311 * @param {Object} e The query event object
39313 'beforequery': true,
39316 * Fires when the 'add' icon is pressed (add a listener to enable add button)
39317 * @param {Roo.form.ComboBox} combo This combo box
39322 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
39323 * @param {Roo.form.ComboBox} combo This combo box
39324 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
39330 if(this.transform){
39331 this.allowDomMove = false;
39332 var s = Roo.getDom(this.transform);
39333 if(!this.hiddenName){
39334 this.hiddenName = s.name;
39337 this.mode = 'local';
39338 var d = [], opts = s.options;
39339 for(var i = 0, len = opts.length;i < len; i++){
39341 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
39343 this.value = value;
39345 d.push([value, o.text]);
39347 this.store = new Roo.data.SimpleStore({
39349 fields: ['value', 'text'],
39352 this.valueField = 'value';
39353 this.displayField = 'text';
39355 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
39356 if(!this.lazyRender){
39357 this.target = true;
39358 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
39359 s.parentNode.removeChild(s); // remove it
39360 this.render(this.el.parentNode);
39362 s.parentNode.removeChild(s); // remove it
39367 this.store = Roo.factory(this.store, Roo.data);
39370 this.selectedIndex = -1;
39371 if(this.mode == 'local'){
39372 if(config.queryDelay === undefined){
39373 this.queryDelay = 10;
39375 if(config.minChars === undefined){
39381 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
39383 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
39386 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
39387 * rendering into an Roo.Editor, defaults to false)
39390 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
39391 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
39394 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
39397 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
39398 * the dropdown list (defaults to undefined, with no header element)
39402 * @cfg {String/Roo.Template} tpl The template to use to render the output
39406 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
39408 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
39410 listWidth: undefined,
39412 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
39413 * mode = 'remote' or 'text' if mode = 'local')
39415 displayField: undefined,
39417 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
39418 * mode = 'remote' or 'value' if mode = 'local').
39419 * Note: use of a valueField requires the user make a selection
39420 * in order for a value to be mapped.
39422 valueField: undefined,
39426 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
39427 * field's data value (defaults to the underlying DOM element's name)
39429 hiddenName: undefined,
39431 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
39435 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
39437 selectedClass: 'x-combo-selected',
39439 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39440 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
39441 * which displays a downward arrow icon).
39443 triggerClass : 'x-form-arrow-trigger',
39445 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
39449 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
39450 * anchor positions (defaults to 'tl-bl')
39452 listAlign: 'tl-bl?',
39454 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
39458 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
39459 * query specified by the allQuery config option (defaults to 'query')
39461 triggerAction: 'query',
39463 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
39464 * (defaults to 4, does not apply if editable = false)
39468 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
39469 * delay (typeAheadDelay) if it matches a known value (defaults to false)
39473 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
39474 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
39478 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
39479 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
39483 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
39484 * when editable = true (defaults to false)
39486 selectOnFocus:false,
39488 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
39490 queryParam: 'query',
39492 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
39493 * when mode = 'remote' (defaults to 'Loading...')
39495 loadingText: 'Loading...',
39497 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
39501 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
39505 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
39506 * traditional select (defaults to true)
39510 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
39514 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
39518 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
39519 * listWidth has a higher value)
39523 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
39524 * allow the user to set arbitrary text into the field (defaults to false)
39526 forceSelection:false,
39528 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
39529 * if typeAhead = true (defaults to 250)
39531 typeAheadDelay : 250,
39533 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
39534 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
39536 valueNotFoundText : undefined,
39538 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
39540 blockFocus : false,
39543 * @cfg {Boolean} disableClear Disable showing of clear button.
39545 disableClear : false,
39547 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
39549 alwaysQuery : false,
39555 // element that contains real text value.. (when hidden is used..)
39558 onRender : function(ct, position){
39559 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
39560 if(this.hiddenName){
39561 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
39563 this.hiddenField.value =
39564 this.hiddenValue !== undefined ? this.hiddenValue :
39565 this.value !== undefined ? this.value : '';
39567 // prevent input submission
39568 this.el.dom.removeAttribute('name');
39573 this.el.dom.setAttribute('autocomplete', 'off');
39576 var cls = 'x-combo-list';
39578 this.list = new Roo.Layer({
39579 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
39582 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
39583 this.list.setWidth(lw);
39584 this.list.swallowEvent('mousewheel');
39585 this.assetHeight = 0;
39588 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
39589 this.assetHeight += this.header.getHeight();
39592 this.innerList = this.list.createChild({cls:cls+'-inner'});
39593 this.innerList.on('mouseover', this.onViewOver, this);
39594 this.innerList.on('mousemove', this.onViewMove, this);
39595 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39597 if(this.allowBlank && !this.pageSize && !this.disableClear){
39598 this.footer = this.list.createChild({cls:cls+'-ft'});
39599 this.pageTb = new Roo.Toolbar(this.footer);
39603 this.footer = this.list.createChild({cls:cls+'-ft'});
39604 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
39605 {pageSize: this.pageSize});
39609 if (this.pageTb && this.allowBlank && !this.disableClear) {
39611 this.pageTb.add(new Roo.Toolbar.Fill(), {
39612 cls: 'x-btn-icon x-btn-clear',
39614 handler: function()
39617 _this.clearValue();
39618 _this.onSelect(false, -1);
39623 this.assetHeight += this.footer.getHeight();
39628 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
39631 this.view = new Roo.View(this.innerList, this.tpl, {
39632 singleSelect:true, store: this.store, selectedClass: this.selectedClass
39635 this.view.on('click', this.onViewClick, this);
39637 this.store.on('beforeload', this.onBeforeLoad, this);
39638 this.store.on('load', this.onLoad, this);
39639 this.store.on('loadexception', this.onLoadException, this);
39641 if(this.resizable){
39642 this.resizer = new Roo.Resizable(this.list, {
39643 pinned:true, handles:'se'
39645 this.resizer.on('resize', function(r, w, h){
39646 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
39647 this.listWidth = w;
39648 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
39649 this.restrictHeight();
39651 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
39653 if(!this.editable){
39654 this.editable = true;
39655 this.setEditable(false);
39659 if (typeof(this.events.add.listeners) != 'undefined') {
39661 this.addicon = this.wrap.createChild(
39662 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
39664 this.addicon.on('click', function(e) {
39665 this.fireEvent('add', this);
39668 if (typeof(this.events.edit.listeners) != 'undefined') {
39670 this.editicon = this.wrap.createChild(
39671 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
39672 if (this.addicon) {
39673 this.editicon.setStyle('margin-left', '40px');
39675 this.editicon.on('click', function(e) {
39677 // we fire even if inothing is selected..
39678 this.fireEvent('edit', this, this.lastData );
39688 initEvents : function(){
39689 Roo.form.ComboBox.superclass.initEvents.call(this);
39691 this.keyNav = new Roo.KeyNav(this.el, {
39692 "up" : function(e){
39693 this.inKeyMode = true;
39697 "down" : function(e){
39698 if(!this.isExpanded()){
39699 this.onTriggerClick();
39701 this.inKeyMode = true;
39706 "enter" : function(e){
39707 this.onViewClick();
39711 "esc" : function(e){
39715 "tab" : function(e){
39716 this.onViewClick(false);
39717 this.fireEvent("specialkey", this, e);
39723 doRelay : function(foo, bar, hname){
39724 if(hname == 'down' || this.scope.isExpanded()){
39725 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
39732 this.queryDelay = Math.max(this.queryDelay || 10,
39733 this.mode == 'local' ? 10 : 250);
39734 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
39735 if(this.typeAhead){
39736 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
39738 if(this.editable !== false){
39739 this.el.on("keyup", this.onKeyUp, this);
39741 if(this.forceSelection){
39742 this.on('blur', this.doForce, this);
39746 onDestroy : function(){
39748 this.view.setStore(null);
39749 this.view.el.removeAllListeners();
39750 this.view.el.remove();
39751 this.view.purgeListeners();
39754 this.list.destroy();
39757 this.store.un('beforeload', this.onBeforeLoad, this);
39758 this.store.un('load', this.onLoad, this);
39759 this.store.un('loadexception', this.onLoadException, this);
39761 Roo.form.ComboBox.superclass.onDestroy.call(this);
39765 fireKey : function(e){
39766 if(e.isNavKeyPress() && !this.list.isVisible()){
39767 this.fireEvent("specialkey", this, e);
39772 onResize: function(w, h){
39773 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
39775 if(typeof w != 'number'){
39776 // we do not handle it!?!?
39779 var tw = this.trigger.getWidth();
39780 tw += this.addicon ? this.addicon.getWidth() : 0;
39781 tw += this.editicon ? this.editicon.getWidth() : 0;
39783 this.el.setWidth( this.adjustWidth('input', x));
39785 this.trigger.setStyle('left', x+'px');
39787 if(this.list && this.listWidth === undefined){
39788 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
39789 this.list.setWidth(lw);
39790 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
39798 * Allow or prevent the user from directly editing the field text. If false is passed,
39799 * the user will only be able to select from the items defined in the dropdown list. This method
39800 * is the runtime equivalent of setting the 'editable' config option at config time.
39801 * @param {Boolean} value True to allow the user to directly edit the field text
39803 setEditable : function(value){
39804 if(value == this.editable){
39807 this.editable = value;
39809 this.el.dom.setAttribute('readOnly', true);
39810 this.el.on('mousedown', this.onTriggerClick, this);
39811 this.el.addClass('x-combo-noedit');
39813 this.el.dom.setAttribute('readOnly', false);
39814 this.el.un('mousedown', this.onTriggerClick, this);
39815 this.el.removeClass('x-combo-noedit');
39820 onBeforeLoad : function(){
39821 if(!this.hasFocus){
39824 this.innerList.update(this.loadingText ?
39825 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
39826 this.restrictHeight();
39827 this.selectedIndex = -1;
39831 onLoad : function(){
39832 if(!this.hasFocus){
39835 if(this.store.getCount() > 0){
39837 this.restrictHeight();
39838 if(this.lastQuery == this.allQuery){
39840 this.el.dom.select();
39842 if(!this.selectByValue(this.value, true)){
39843 this.select(0, true);
39847 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
39848 this.taTask.delay(this.typeAheadDelay);
39852 this.onEmptyResults();
39857 onLoadException : function()
39860 Roo.log(this.store.reader.jsonData);
39861 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
39862 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
39868 onTypeAhead : function(){
39869 if(this.store.getCount() > 0){
39870 var r = this.store.getAt(0);
39871 var newValue = r.data[this.displayField];
39872 var len = newValue.length;
39873 var selStart = this.getRawValue().length;
39874 if(selStart != len){
39875 this.setRawValue(newValue);
39876 this.selectText(selStart, newValue.length);
39882 onSelect : function(record, index){
39883 if(this.fireEvent('beforeselect', this, record, index) !== false){
39884 this.setFromData(index > -1 ? record.data : false);
39886 this.fireEvent('select', this, record, index);
39891 * Returns the currently selected field value or empty string if no value is set.
39892 * @return {String} value The selected value
39894 getValue : function(){
39895 if(this.valueField){
39896 return typeof this.value != 'undefined' ? this.value : '';
39898 return Roo.form.ComboBox.superclass.getValue.call(this);
39902 * Clears any text/value currently set in the field
39904 clearValue : function(){
39905 if(this.hiddenField){
39906 this.hiddenField.value = '';
39909 this.setRawValue('');
39910 this.lastSelectionText = '';
39915 * Sets the specified value into the field. If the value finds a match, the corresponding record text
39916 * will be displayed in the field. If the value does not match the data value of an existing item,
39917 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
39918 * Otherwise the field will be blank (although the value will still be set).
39919 * @param {String} value The value to match
39921 setValue : function(v){
39923 if(this.valueField){
39924 var r = this.findRecord(this.valueField, v);
39926 text = r.data[this.displayField];
39927 }else if(this.valueNotFoundText !== undefined){
39928 text = this.valueNotFoundText;
39931 this.lastSelectionText = text;
39932 if(this.hiddenField){
39933 this.hiddenField.value = v;
39935 Roo.form.ComboBox.superclass.setValue.call(this, text);
39939 * @property {Object} the last set data for the element
39944 * Sets the value of the field based on a object which is related to the record format for the store.
39945 * @param {Object} value the value to set as. or false on reset?
39947 setFromData : function(o){
39948 var dv = ''; // display value
39949 var vv = ''; // value value..
39951 if (this.displayField) {
39952 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
39954 // this is an error condition!!!
39955 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
39958 if(this.valueField){
39959 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
39961 if(this.hiddenField){
39962 this.hiddenField.value = vv;
39964 this.lastSelectionText = dv;
39965 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39969 // no hidden field.. - we store the value in 'value', but still display
39970 // display field!!!!
39971 this.lastSelectionText = dv;
39972 Roo.form.ComboBox.superclass.setValue.call(this, dv);
39978 reset : function(){
39979 // overridden so that last data is reset..
39980 this.setValue(this.resetValue);
39981 this.clearInvalid();
39982 this.lastData = false;
39984 this.view.clearSelections();
39988 findRecord : function(prop, value){
39990 if(this.store.getCount() > 0){
39991 this.store.each(function(r){
39992 if(r.data[prop] == value){
40002 getName: function()
40004 // returns hidden if it's set..
40005 if (!this.rendered) {return ''};
40006 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40010 onViewMove : function(e, t){
40011 this.inKeyMode = false;
40015 onViewOver : function(e, t){
40016 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
40019 var item = this.view.findItemFromChild(t);
40021 var index = this.view.indexOf(item);
40022 this.select(index, false);
40027 onViewClick : function(doFocus)
40029 var index = this.view.getSelectedIndexes()[0];
40030 var r = this.store.getAt(index);
40032 this.onSelect(r, index);
40034 if(doFocus !== false && !this.blockFocus){
40040 restrictHeight : function(){
40041 this.innerList.dom.style.height = '';
40042 var inner = this.innerList.dom;
40043 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
40044 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
40045 this.list.beginUpdate();
40046 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
40047 this.list.alignTo(this.el, this.listAlign);
40048 this.list.endUpdate();
40052 onEmptyResults : function(){
40057 * Returns true if the dropdown list is expanded, else false.
40059 isExpanded : function(){
40060 return this.list.isVisible();
40064 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
40065 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40066 * @param {String} value The data value of the item to select
40067 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40068 * selected item if it is not currently in view (defaults to true)
40069 * @return {Boolean} True if the value matched an item in the list, else false
40071 selectByValue : function(v, scrollIntoView){
40072 if(v !== undefined && v !== null){
40073 var r = this.findRecord(this.valueField || this.displayField, v);
40075 this.select(this.store.indexOf(r), scrollIntoView);
40083 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
40084 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
40085 * @param {Number} index The zero-based index of the list item to select
40086 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
40087 * selected item if it is not currently in view (defaults to true)
40089 select : function(index, scrollIntoView){
40090 this.selectedIndex = index;
40091 this.view.select(index);
40092 if(scrollIntoView !== false){
40093 var el = this.view.getNode(index);
40095 this.innerList.scrollChildIntoView(el, false);
40101 selectNext : function(){
40102 var ct = this.store.getCount();
40104 if(this.selectedIndex == -1){
40106 }else if(this.selectedIndex < ct-1){
40107 this.select(this.selectedIndex+1);
40113 selectPrev : function(){
40114 var ct = this.store.getCount();
40116 if(this.selectedIndex == -1){
40118 }else if(this.selectedIndex != 0){
40119 this.select(this.selectedIndex-1);
40125 onKeyUp : function(e){
40126 if(this.editable !== false && !e.isSpecialKey()){
40127 this.lastKey = e.getKey();
40128 this.dqTask.delay(this.queryDelay);
40133 validateBlur : function(){
40134 return !this.list || !this.list.isVisible();
40138 initQuery : function(){
40139 this.doQuery(this.getRawValue());
40143 doForce : function(){
40144 if(this.el.dom.value.length > 0){
40145 this.el.dom.value =
40146 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
40152 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
40153 * query allowing the query action to be canceled if needed.
40154 * @param {String} query The SQL query to execute
40155 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
40156 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
40157 * saved in the current store (defaults to false)
40159 doQuery : function(q, forceAll){
40160 if(q === undefined || q === null){
40165 forceAll: forceAll,
40169 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
40173 forceAll = qe.forceAll;
40174 if(forceAll === true || (q.length >= this.minChars)){
40175 if(this.lastQuery != q || this.alwaysQuery){
40176 this.lastQuery = q;
40177 if(this.mode == 'local'){
40178 this.selectedIndex = -1;
40180 this.store.clearFilter();
40182 this.store.filter(this.displayField, q);
40186 this.store.baseParams[this.queryParam] = q;
40188 params: this.getParams(q)
40193 this.selectedIndex = -1;
40200 getParams : function(q){
40202 //p[this.queryParam] = q;
40205 p.limit = this.pageSize;
40211 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
40213 collapse : function(){
40214 if(!this.isExpanded()){
40218 Roo.get(document).un('mousedown', this.collapseIf, this);
40219 Roo.get(document).un('mousewheel', this.collapseIf, this);
40220 if (!this.editable) {
40221 Roo.get(document).un('keydown', this.listKeyPress, this);
40223 this.fireEvent('collapse', this);
40227 collapseIf : function(e){
40228 if(!e.within(this.wrap) && !e.within(this.list)){
40234 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
40236 expand : function(){
40237 if(this.isExpanded() || !this.hasFocus){
40240 this.list.alignTo(this.el, this.listAlign);
40242 Roo.get(document).on('mousedown', this.collapseIf, this);
40243 Roo.get(document).on('mousewheel', this.collapseIf, this);
40244 if (!this.editable) {
40245 Roo.get(document).on('keydown', this.listKeyPress, this);
40248 this.fireEvent('expand', this);
40252 // Implements the default empty TriggerField.onTriggerClick function
40253 onTriggerClick : function(){
40257 if(this.isExpanded()){
40259 if (!this.blockFocus) {
40264 this.hasFocus = true;
40265 if(this.triggerAction == 'all') {
40266 this.doQuery(this.allQuery, true);
40268 this.doQuery(this.getRawValue());
40270 if (!this.blockFocus) {
40275 listKeyPress : function(e)
40277 //Roo.log('listkeypress');
40278 // scroll to first matching element based on key pres..
40279 if (e.isSpecialKey()) {
40282 var k = String.fromCharCode(e.getKey()).toUpperCase();
40285 var csel = this.view.getSelectedNodes();
40286 var cselitem = false;
40288 var ix = this.view.indexOf(csel[0]);
40289 cselitem = this.store.getAt(ix);
40290 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
40296 this.store.each(function(v) {
40298 // start at existing selection.
40299 if (cselitem.id == v.id) {
40305 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
40306 match = this.store.indexOf(v);
40311 if (match === false) {
40312 return true; // no more action?
40315 this.view.select(match);
40316 var sn = Roo.get(this.view.getSelectedNodes()[0])
40317 sn.scrollIntoView(sn.dom.parentNode, false);
40321 * @cfg {Boolean} grow
40325 * @cfg {Number} growMin
40329 * @cfg {Number} growMax
40337 * Copyright(c) 2010-2012, Roo J Solutions Limited
40344 * @class Roo.form.ComboBoxArray
40345 * @extends Roo.form.TextField
40346 * A facebook style adder... for lists of email / people / countries etc...
40347 * pick multiple items from a combo box, and shows each one.
40349 * Fred [x] Brian [x] [Pick another |v]
40352 * For this to work: it needs various extra information
40353 * - normal combo problay has
40355 * + displayField, valueField
40357 * For our purpose...
40360 * If we change from 'extends' to wrapping...
40367 * Create a new ComboBoxArray.
40368 * @param {Object} config Configuration options
40372 Roo.form.ComboBoxArray = function(config)
40376 * @event beforeremove
40377 * Fires before remove the value from the list
40378 * @param {Roo.form.ComboBoxArray} _self This combo box array
40379 * @param {Roo.form.ComboBoxArray.Item} item removed item
40381 'beforeremove' : true,
40384 * Fires when remove the value from the list
40385 * @param {Roo.form.ComboBoxArray} _self This combo box array
40386 * @param {Roo.form.ComboBoxArray.Item} item removed item
40393 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
40395 this.items = new Roo.util.MixedCollection(false);
40397 // construct the child combo...
40407 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
40410 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
40415 // behavies liek a hiddne field
40416 inputType: 'hidden',
40418 * @cfg {Number} width The width of the box that displays the selected element
40425 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
40429 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
40431 hiddenName : false,
40434 // private the array of items that are displayed..
40436 // private - the hidden field el.
40438 // private - the filed el..
40441 //validateValue : function() { return true; }, // all values are ok!
40442 //onAddClick: function() { },
40444 onRender : function(ct, position)
40447 // create the standard hidden element
40448 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
40451 // give fake names to child combo;
40452 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
40453 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
40455 this.combo = Roo.factory(this.combo, Roo.form);
40456 this.combo.onRender(ct, position);
40457 if (typeof(this.combo.width) != 'undefined') {
40458 this.combo.onResize(this.combo.width,0);
40461 this.combo.initEvents();
40463 // assigned so form know we need to do this..
40464 this.store = this.combo.store;
40465 this.valueField = this.combo.valueField;
40466 this.displayField = this.combo.displayField ;
40469 this.combo.wrap.addClass('x-cbarray-grp');
40471 var cbwrap = this.combo.wrap.createChild(
40472 {tag: 'div', cls: 'x-cbarray-cb'},
40477 this.hiddenEl = this.combo.wrap.createChild({
40478 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
40480 this.el = this.combo.wrap.createChild({
40481 tag: 'input', type:'hidden' , name: this.name, value : ''
40483 // this.el.dom.removeAttribute("name");
40486 this.outerWrap = this.combo.wrap;
40487 this.wrap = cbwrap;
40489 this.outerWrap.setWidth(this.width);
40490 this.outerWrap.dom.removeChild(this.el.dom);
40492 this.wrap.dom.appendChild(this.el.dom);
40493 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
40494 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
40496 this.combo.trigger.setStyle('position','relative');
40497 this.combo.trigger.setStyle('left', '0px');
40498 this.combo.trigger.setStyle('top', '2px');
40500 this.combo.el.setStyle('vertical-align', 'text-bottom');
40502 //this.trigger.setStyle('vertical-align', 'top');
40504 // this should use the code from combo really... on('add' ....)
40508 this.adder = this.outerWrap.createChild(
40509 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
40511 this.adder.on('click', function(e) {
40512 _t.fireEvent('adderclick', this, e);
40516 //this.adder.on('click', this.onAddClick, _t);
40519 this.combo.on('select', function(cb, rec, ix) {
40520 this.addItem(rec.data);
40523 cb.el.dom.value = '';
40524 //cb.lastData = rec.data;
40533 getName: function()
40535 // returns hidden if it's set..
40536 if (!this.rendered) {return ''};
40537 return this.hiddenName ? this.hiddenName : this.name;
40542 onResize: function(w, h){
40545 // not sure if this is needed..
40546 //this.combo.onResize(w,h);
40548 if(typeof w != 'number'){
40549 // we do not handle it!?!?
40552 var tw = this.combo.trigger.getWidth();
40553 tw += this.addicon ? this.addicon.getWidth() : 0;
40554 tw += this.editicon ? this.editicon.getWidth() : 0;
40556 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
40558 this.combo.trigger.setStyle('left', '0px');
40560 if(this.list && this.listWidth === undefined){
40561 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
40562 this.list.setWidth(lw);
40563 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
40570 addItem: function(rec)
40572 var valueField = this.combo.valueField;
40573 var displayField = this.combo.displayField;
40574 if (this.items.indexOfKey(rec[valueField]) > -1) {
40575 //console.log("GOT " + rec.data.id);
40579 var x = new Roo.form.ComboBoxArray.Item({
40580 //id : rec[this.idField],
40582 displayField : displayField ,
40583 tipField : displayField ,
40587 this.items.add(rec[valueField],x);
40588 // add it before the element..
40589 this.updateHiddenEl();
40590 x.render(this.outerWrap, this.wrap.dom);
40591 // add the image handler..
40594 updateHiddenEl : function()
40597 if (!this.hiddenEl) {
40601 var idField = this.combo.valueField;
40603 this.items.each(function(f) {
40604 ar.push(f.data[idField]);
40607 this.hiddenEl.dom.value = ar.join(',');
40613 //Roo.form.ComboBoxArray.superclass.reset.call(this);
40614 this.items.each(function(f) {
40617 this.el.dom.value = '';
40618 if (this.hiddenEl) {
40619 this.hiddenEl.dom.value = '';
40623 getValue: function()
40625 return this.hiddenEl ? this.hiddenEl.dom.value : '';
40627 setValue: function(v) // not a valid action - must use addItems..
40634 if (this.store.isLocal && (typeof(v) == 'string')) {
40635 // then we can use the store to find the values..
40636 // comma seperated at present.. this needs to allow JSON based encoding..
40637 this.hiddenEl.value = v;
40639 Roo.each(v.split(','), function(k) {
40640 Roo.log("CHECK " + this.valueField + ',' + k);
40641 var li = this.store.query(this.valueField, k);
40646 add[this.valueField] = k;
40647 add[this.displayField] = li.item(0).data[this.displayField];
40653 if (typeof(v) == 'object' ) {
40654 // then let's assume it's an array of objects..
40655 Roo.each(v, function(l) {
40663 setFromData: function(v)
40665 // this recieves an object, if setValues is called.
40667 this.el.dom.value = v[this.displayField];
40668 this.hiddenEl.dom.value = v[this.valueField];
40669 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
40672 var kv = v[this.valueField];
40673 var dv = v[this.displayField];
40674 kv = typeof(kv) != 'string' ? '' : kv;
40675 dv = typeof(dv) != 'string' ? '' : dv;
40678 var keys = kv.split(',');
40679 var display = dv.split(',');
40680 for (var i = 0 ; i < keys.length; i++) {
40683 add[this.valueField] = keys[i];
40684 add[this.displayField] = display[i];
40692 * Validates the combox array value
40693 * @return {Boolean} True if the value is valid, else false
40695 validate : function(){
40696 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
40697 this.clearInvalid();
40703 validateValue : function(value){
40704 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
40712 isDirty : function() {
40713 if(this.disabled) {
40718 var d = Roo.decode(String(this.originalValue));
40720 return String(this.getValue()) !== String(this.originalValue);
40723 var originalValue = [];
40725 for (var i = 0; i < d.length; i++){
40726 originalValue.push(d[i][this.valueField]);
40729 return String(this.getValue()) !== String(originalValue.join(','));
40738 * @class Roo.form.ComboBoxArray.Item
40739 * @extends Roo.BoxComponent
40740 * A selected item in the list
40741 * Fred [x] Brian [x] [Pick another |v]
40744 * Create a new item.
40745 * @param {Object} config Configuration options
40748 Roo.form.ComboBoxArray.Item = function(config) {
40749 config.id = Roo.id();
40750 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
40753 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
40756 displayField : false,
40760 defaultAutoCreate : {
40762 cls: 'x-cbarray-item',
40769 src : Roo.BLANK_IMAGE_URL ,
40777 onRender : function(ct, position)
40779 Roo.form.Field.superclass.onRender.call(this, ct, position);
40782 var cfg = this.getAutoCreate();
40783 this.el = ct.createChild(cfg, position);
40786 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
40788 this.el.child('div').dom.innerHTML = this.cb.renderer ?
40789 this.cb.renderer(this.data) :
40790 String.format('{0}',this.data[this.displayField]);
40793 this.el.child('div').dom.setAttribute('qtip',
40794 String.format('{0}',this.data[this.tipField])
40797 this.el.child('img').on('click', this.remove, this);
40801 remove : function()
40803 if(this.cb.disabled){
40807 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
40808 this.cb.items.remove(this);
40809 this.el.child('img').un('click', this.remove, this);
40811 this.cb.updateHiddenEl();
40813 this.cb.fireEvent('remove', this.cb, this);
40819 * Ext JS Library 1.1.1
40820 * Copyright(c) 2006-2007, Ext JS, LLC.
40822 * Originally Released Under LGPL - original licence link has changed is not relivant.
40825 * <script type="text/javascript">
40828 * @class Roo.form.Checkbox
40829 * @extends Roo.form.Field
40830 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
40832 * Creates a new Checkbox
40833 * @param {Object} config Configuration options
40835 Roo.form.Checkbox = function(config){
40836 Roo.form.Checkbox.superclass.constructor.call(this, config);
40840 * Fires when the checkbox is checked or unchecked.
40841 * @param {Roo.form.Checkbox} this This checkbox
40842 * @param {Boolean} checked The new checked value
40848 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
40850 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
40852 focusClass : undefined,
40854 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
40856 fieldClass: "x-form-field",
40858 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
40862 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40863 * {tag: "input", type: "checkbox", autocomplete: "off"})
40865 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
40867 * @cfg {String} boxLabel The text that appears beside the checkbox
40871 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
40875 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
40877 valueOff: '0', // value when not checked..
40879 actionMode : 'viewEl',
40882 itemCls : 'x-menu-check-item x-form-item',
40883 groupClass : 'x-menu-group-item',
40884 inputType : 'hidden',
40887 inSetChecked: false, // check that we are not calling self...
40889 inputElement: false, // real input element?
40890 basedOn: false, // ????
40892 isFormField: true, // not sure where this is needed!!!!
40894 onResize : function(){
40895 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
40896 if(!this.boxLabel){
40897 this.el.alignTo(this.wrap, 'c-c');
40901 initEvents : function(){
40902 Roo.form.Checkbox.superclass.initEvents.call(this);
40903 this.el.on("click", this.onClick, this);
40904 this.el.on("change", this.onClick, this);
40908 getResizeEl : function(){
40912 getPositionEl : function(){
40917 onRender : function(ct, position){
40918 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
40920 if(this.inputValue !== undefined){
40921 this.el.dom.value = this.inputValue;
40924 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
40925 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
40926 var viewEl = this.wrap.createChild({
40927 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
40928 this.viewEl = viewEl;
40929 this.wrap.on('click', this.onClick, this);
40931 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
40932 this.el.on('propertychange', this.setFromHidden, this); //ie
40937 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
40938 // viewEl.on('click', this.onClick, this);
40940 //if(this.checked){
40941 this.setChecked(this.checked);
40943 //this.checked = this.el.dom;
40949 initValue : Roo.emptyFn,
40952 * Returns the checked state of the checkbox.
40953 * @return {Boolean} True if checked, else false
40955 getValue : function(){
40957 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
40959 return this.valueOff;
40964 onClick : function(){
40965 if (this.disabled) {
40968 this.setChecked(!this.checked);
40970 //if(this.el.dom.checked != this.checked){
40971 // this.setValue(this.el.dom.checked);
40976 * Sets the checked state of the checkbox.
40977 * On is always based on a string comparison between inputValue and the param.
40978 * @param {Boolean/String} value - the value to set
40979 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
40981 setValue : function(v,suppressEvent){
40984 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
40985 //if(this.el && this.el.dom){
40986 // this.el.dom.checked = this.checked;
40987 // this.el.dom.defaultChecked = this.checked;
40989 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
40990 //this.fireEvent("check", this, this.checked);
40993 setChecked : function(state,suppressEvent)
40995 if (this.inSetChecked) {
40996 this.checked = state;
41002 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
41004 this.checked = state;
41005 if(suppressEvent !== true){
41006 this.fireEvent('check', this, state);
41008 this.inSetChecked = true;
41009 this.el.dom.value = state ? this.inputValue : this.valueOff;
41010 this.inSetChecked = false;
41013 // handle setting of hidden value by some other method!!?!?
41014 setFromHidden: function()
41019 //console.log("SET FROM HIDDEN");
41020 //alert('setFrom hidden');
41021 this.setValue(this.el.dom.value);
41024 onDestroy : function()
41027 Roo.get(this.viewEl).remove();
41030 Roo.form.Checkbox.superclass.onDestroy.call(this);
41035 * Ext JS Library 1.1.1
41036 * Copyright(c) 2006-2007, Ext JS, LLC.
41038 * Originally Released Under LGPL - original licence link has changed is not relivant.
41041 * <script type="text/javascript">
41045 * @class Roo.form.Radio
41046 * @extends Roo.form.Checkbox
41047 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
41048 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
41050 * Creates a new Radio
41051 * @param {Object} config Configuration options
41053 Roo.form.Radio = function(){
41054 Roo.form.Radio.superclass.constructor.apply(this, arguments);
41056 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
41057 inputType: 'radio',
41060 * If this radio is part of a group, it will return the selected value
41063 getGroupValue : function(){
41064 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
41068 onRender : function(ct, position){
41069 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
41071 if(this.inputValue !== undefined){
41072 this.el.dom.value = this.inputValue;
41075 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
41076 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
41077 //var viewEl = this.wrap.createChild({
41078 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
41079 //this.viewEl = viewEl;
41080 //this.wrap.on('click', this.onClick, this);
41082 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
41083 //this.el.on('propertychange', this.setFromHidden, this); //ie
41088 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
41089 // viewEl.on('click', this.onClick, this);
41092 this.el.dom.checked = 'checked' ;
41098 });//<script type="text/javascript">
41101 * Based Ext JS Library 1.1.1
41102 * Copyright(c) 2006-2007, Ext JS, LLC.
41108 * @class Roo.HtmlEditorCore
41109 * @extends Roo.Component
41110 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
41112 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
41115 Roo.HtmlEditorCore = function(config){
41118 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
41123 * @event initialize
41124 * Fires when the editor is fully initialized (including the iframe)
41125 * @param {Roo.HtmlEditorCore} this
41130 * Fires when the editor is first receives the focus. Any insertion must wait
41131 * until after this event.
41132 * @param {Roo.HtmlEditorCore} this
41136 * @event beforesync
41137 * Fires before the textarea is updated with content from the editor iframe. Return false
41138 * to cancel the sync.
41139 * @param {Roo.HtmlEditorCore} this
41140 * @param {String} html
41144 * @event beforepush
41145 * Fires before the iframe editor is updated with content from the textarea. Return false
41146 * to cancel the push.
41147 * @param {Roo.HtmlEditorCore} this
41148 * @param {String} html
41153 * Fires when the textarea is updated with content from the editor iframe.
41154 * @param {Roo.HtmlEditorCore} this
41155 * @param {String} html
41160 * Fires when the iframe editor is updated with content from the textarea.
41161 * @param {Roo.HtmlEditorCore} this
41162 * @param {String} html
41167 * @event editorevent
41168 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
41169 * @param {Roo.HtmlEditorCore} this
41175 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
41177 // defaults : white / black...
41178 this.applyBlacklists();
41185 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
41189 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
41195 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
41200 * @cfg {Number} height (in pixels)
41204 * @cfg {Number} width (in pixels)
41209 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
41212 stylesheets: false,
41217 // private properties
41218 validationEvent : false,
41220 initialized : false,
41222 sourceEditMode : false,
41223 onFocus : Roo.emptyFn,
41225 hideMode:'offsets',
41229 // blacklist + whitelisted elements..
41236 * Protected method that will not generally be called directly. It
41237 * is called when the editor initializes the iframe with HTML contents. Override this method if you
41238 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
41240 getDocMarkup : function(){
41244 // inherit styels from page...??
41245 if (this.stylesheets === false) {
41247 Roo.get(document.head).select('style').each(function(node) {
41248 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41251 Roo.get(document.head).select('link').each(function(node) {
41252 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
41255 } else if (!this.stylesheets.length) {
41257 st = '<style type="text/css">' +
41258 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41264 st += '<style type="text/css">' +
41265 'IMG { cursor: pointer } ' +
41269 return '<html><head>' + st +
41270 //<style type="text/css">' +
41271 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
41273 ' </head><body class="roo-htmleditor-body"></body></html>';
41277 onRender : function(ct, position)
41280 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
41281 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
41284 this.el.dom.style.border = '0 none';
41285 this.el.dom.setAttribute('tabIndex', -1);
41286 this.el.addClass('x-hidden hide');
41290 if(Roo.isIE){ // fix IE 1px bogus margin
41291 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
41295 this.frameId = Roo.id();
41299 var iframe = this.owner.wrap.createChild({
41301 cls: 'form-control', // bootstrap..
41303 name: this.frameId,
41304 frameBorder : 'no',
41305 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
41310 this.iframe = iframe.dom;
41312 this.assignDocWin();
41314 this.doc.designMode = 'on';
41317 this.doc.write(this.getDocMarkup());
41321 var task = { // must defer to wait for browser to be ready
41323 //console.log("run task?" + this.doc.readyState);
41324 this.assignDocWin();
41325 if(this.doc.body || this.doc.readyState == 'complete'){
41327 this.doc.designMode="on";
41331 Roo.TaskMgr.stop(task);
41332 this.initEditor.defer(10, this);
41339 Roo.TaskMgr.start(task);
41344 onResize : function(w, h)
41346 Roo.log('resize: ' +w + ',' + h );
41347 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
41351 if(typeof w == 'number'){
41353 this.iframe.style.width = w + 'px';
41355 if(typeof h == 'number'){
41357 this.iframe.style.height = h + 'px';
41359 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
41366 * Toggles the editor between standard and source edit mode.
41367 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
41369 toggleSourceEdit : function(sourceEditMode){
41371 this.sourceEditMode = sourceEditMode === true;
41373 if(this.sourceEditMode){
41375 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
41378 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
41379 //this.iframe.className = '';
41382 //this.setSize(this.owner.wrap.getSize());
41383 //this.fireEvent('editmodechange', this, this.sourceEditMode);
41390 * Protected method that will not generally be called directly. If you need/want
41391 * custom HTML cleanup, this is the method you should override.
41392 * @param {String} html The HTML to be cleaned
41393 * return {String} The cleaned HTML
41395 cleanHtml : function(html){
41396 html = String(html);
41397 if(html.length > 5){
41398 if(Roo.isSafari){ // strip safari nonsense
41399 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
41402 if(html == ' '){
41409 * HTML Editor -> Textarea
41410 * Protected method that will not generally be called directly. Syncs the contents
41411 * of the editor iframe with the textarea.
41413 syncValue : function(){
41414 if(this.initialized){
41415 var bd = (this.doc.body || this.doc.documentElement);
41416 //this.cleanUpPaste(); -- this is done else where and causes havoc..
41417 var html = bd.innerHTML;
41419 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
41420 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
41422 html = '<div style="'+m[0]+'">' + html + '</div>';
41425 html = this.cleanHtml(html);
41426 // fix up the special chars.. normaly like back quotes in word...
41427 // however we do not want to do this with chinese..
41428 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
41429 var cc = b.charCodeAt();
41431 (cc >= 0x4E00 && cc < 0xA000 ) ||
41432 (cc >= 0x3400 && cc < 0x4E00 ) ||
41433 (cc >= 0xf900 && cc < 0xfb00 )
41439 if(this.owner.fireEvent('beforesync', this, html) !== false){
41440 this.el.dom.value = html;
41441 this.owner.fireEvent('sync', this, html);
41447 * Protected method that will not generally be called directly. Pushes the value of the textarea
41448 * into the iframe editor.
41450 pushValue : function(){
41451 if(this.initialized){
41452 var v = this.el.dom.value.trim();
41454 // if(v.length < 1){
41458 if(this.owner.fireEvent('beforepush', this, v) !== false){
41459 var d = (this.doc.body || this.doc.documentElement);
41461 this.cleanUpPaste();
41462 this.el.dom.value = d.innerHTML;
41463 this.owner.fireEvent('push', this, v);
41469 deferFocus : function(){
41470 this.focus.defer(10, this);
41474 focus : function(){
41475 if(this.win && !this.sourceEditMode){
41482 assignDocWin: function()
41484 var iframe = this.iframe;
41487 this.doc = iframe.contentWindow.document;
41488 this.win = iframe.contentWindow;
41490 // if (!Roo.get(this.frameId)) {
41493 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41494 // this.win = Roo.get(this.frameId).dom.contentWindow;
41496 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
41500 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
41501 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
41506 initEditor : function(){
41507 //console.log("INIT EDITOR");
41508 this.assignDocWin();
41512 this.doc.designMode="on";
41514 this.doc.write(this.getDocMarkup());
41517 var dbody = (this.doc.body || this.doc.documentElement);
41518 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
41519 // this copies styles from the containing element into thsi one..
41520 // not sure why we need all of this..
41521 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
41523 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
41524 //ss['background-attachment'] = 'fixed'; // w3c
41525 dbody.bgProperties = 'fixed'; // ie
41526 //Roo.DomHelper.applyStyles(dbody, ss);
41527 Roo.EventManager.on(this.doc, {
41528 //'mousedown': this.onEditorEvent,
41529 'mouseup': this.onEditorEvent,
41530 'dblclick': this.onEditorEvent,
41531 'click': this.onEditorEvent,
41532 'keyup': this.onEditorEvent,
41537 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
41539 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
41540 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
41542 this.initialized = true;
41544 this.owner.fireEvent('initialize', this);
41549 onDestroy : function(){
41555 //for (var i =0; i < this.toolbars.length;i++) {
41556 // // fixme - ask toolbars for heights?
41557 // this.toolbars[i].onDestroy();
41560 //this.wrap.dom.innerHTML = '';
41561 //this.wrap.remove();
41566 onFirstFocus : function(){
41568 this.assignDocWin();
41571 this.activated = true;
41574 if(Roo.isGecko){ // prevent silly gecko errors
41576 var s = this.win.getSelection();
41577 if(!s.focusNode || s.focusNode.nodeType != 3){
41578 var r = s.getRangeAt(0);
41579 r.selectNodeContents((this.doc.body || this.doc.documentElement));
41584 this.execCmd('useCSS', true);
41585 this.execCmd('styleWithCSS', false);
41588 this.owner.fireEvent('activate', this);
41592 adjustFont: function(btn){
41593 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
41594 //if(Roo.isSafari){ // safari
41597 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
41598 if(Roo.isSafari){ // safari
41599 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
41600 v = (v < 10) ? 10 : v;
41601 v = (v > 48) ? 48 : v;
41602 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
41607 v = Math.max(1, v+adjust);
41609 this.execCmd('FontSize', v );
41612 onEditorEvent : function(e){
41613 this.owner.fireEvent('editorevent', this, e);
41614 // this.updateToolbar();
41615 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
41618 insertTag : function(tg)
41620 // could be a bit smarter... -> wrap the current selected tRoo..
41621 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
41623 range = this.createRange(this.getSelection());
41624 var wrappingNode = this.doc.createElement(tg.toLowerCase());
41625 wrappingNode.appendChild(range.extractContents());
41626 range.insertNode(wrappingNode);
41633 this.execCmd("formatblock", tg);
41637 insertText : function(txt)
41641 var range = this.createRange();
41642 range.deleteContents();
41643 //alert(Sender.getAttribute('label'));
41645 range.insertNode(this.doc.createTextNode(txt));
41651 * Executes a Midas editor command on the editor document and performs necessary focus and
41652 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
41653 * @param {String} cmd The Midas command
41654 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41656 relayCmd : function(cmd, value){
41658 this.execCmd(cmd, value);
41659 this.owner.fireEvent('editorevent', this);
41660 //this.updateToolbar();
41661 this.owner.deferFocus();
41665 * Executes a Midas editor command directly on the editor document.
41666 * For visual commands, you should use {@link #relayCmd} instead.
41667 * <b>This should only be called after the editor is initialized.</b>
41668 * @param {String} cmd The Midas command
41669 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
41671 execCmd : function(cmd, value){
41672 this.doc.execCommand(cmd, false, value === undefined ? null : value);
41679 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
41681 * @param {String} text | dom node..
41683 insertAtCursor : function(text)
41688 if(!this.activated){
41694 var r = this.doc.selection.createRange();
41705 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
41709 // from jquery ui (MIT licenced)
41711 var win = this.win;
41713 if (win.getSelection && win.getSelection().getRangeAt) {
41714 range = win.getSelection().getRangeAt(0);
41715 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
41716 range.insertNode(node);
41717 } else if (win.document.selection && win.document.selection.createRange) {
41718 // no firefox support
41719 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41720 win.document.selection.createRange().pasteHTML(txt);
41722 // no firefox support
41723 var txt = typeof(text) == 'string' ? text : text.outerHTML;
41724 this.execCmd('InsertHTML', txt);
41733 mozKeyPress : function(e){
41735 var c = e.getCharCode(), cmd;
41738 c = String.fromCharCode(c).toLowerCase();
41752 this.cleanUpPaste.defer(100, this);
41760 e.preventDefault();
41768 fixKeys : function(){ // load time branching for fastest keydown performance
41770 return function(e){
41771 var k = e.getKey(), r;
41774 r = this.doc.selection.createRange();
41777 r.pasteHTML('    ');
41784 r = this.doc.selection.createRange();
41786 var target = r.parentElement();
41787 if(!target || target.tagName.toLowerCase() != 'li'){
41789 r.pasteHTML('<br />');
41795 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41796 this.cleanUpPaste.defer(100, this);
41802 }else if(Roo.isOpera){
41803 return function(e){
41804 var k = e.getKey();
41808 this.execCmd('InsertHTML','    ');
41811 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41812 this.cleanUpPaste.defer(100, this);
41817 }else if(Roo.isSafari){
41818 return function(e){
41819 var k = e.getKey();
41823 this.execCmd('InsertText','\t');
41827 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
41828 this.cleanUpPaste.defer(100, this);
41836 getAllAncestors: function()
41838 var p = this.getSelectedNode();
41841 a.push(p); // push blank onto stack..
41842 p = this.getParentElement();
41846 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
41850 a.push(this.doc.body);
41854 lastSelNode : false,
41857 getSelection : function()
41859 this.assignDocWin();
41860 return Roo.isIE ? this.doc.selection : this.win.getSelection();
41863 getSelectedNode: function()
41865 // this may only work on Gecko!!!
41867 // should we cache this!!!!
41872 var range = this.createRange(this.getSelection()).cloneRange();
41875 var parent = range.parentElement();
41877 var testRange = range.duplicate();
41878 testRange.moveToElementText(parent);
41879 if (testRange.inRange(range)) {
41882 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
41885 parent = parent.parentElement;
41890 // is ancestor a text element.
41891 var ac = range.commonAncestorContainer;
41892 if (ac.nodeType == 3) {
41893 ac = ac.parentNode;
41896 var ar = ac.childNodes;
41899 var other_nodes = [];
41900 var has_other_nodes = false;
41901 for (var i=0;i<ar.length;i++) {
41902 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
41905 // fullly contained node.
41907 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
41912 // probably selected..
41913 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
41914 other_nodes.push(ar[i]);
41918 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
41923 has_other_nodes = true;
41925 if (!nodes.length && other_nodes.length) {
41926 nodes= other_nodes;
41928 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
41934 createRange: function(sel)
41936 // this has strange effects when using with
41937 // top toolbar - not sure if it's a great idea.
41938 //this.editor.contentWindow.focus();
41939 if (typeof sel != "undefined") {
41941 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
41943 return this.doc.createRange();
41946 return this.doc.createRange();
41949 getParentElement: function()
41952 this.assignDocWin();
41953 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
41955 var range = this.createRange(sel);
41958 var p = range.commonAncestorContainer;
41959 while (p.nodeType == 3) { // text node
41970 * Range intersection.. the hard stuff...
41974 * [ -- selected range --- ]
41978 * if end is before start or hits it. fail.
41979 * if start is after end or hits it fail.
41981 * if either hits (but other is outside. - then it's not
41987 // @see http://www.thismuchiknow.co.uk/?p=64.
41988 rangeIntersectsNode : function(range, node)
41990 var nodeRange = node.ownerDocument.createRange();
41992 nodeRange.selectNode(node);
41994 nodeRange.selectNodeContents(node);
41997 var rangeStartRange = range.cloneRange();
41998 rangeStartRange.collapse(true);
42000 var rangeEndRange = range.cloneRange();
42001 rangeEndRange.collapse(false);
42003 var nodeStartRange = nodeRange.cloneRange();
42004 nodeStartRange.collapse(true);
42006 var nodeEndRange = nodeRange.cloneRange();
42007 nodeEndRange.collapse(false);
42009 return rangeStartRange.compareBoundaryPoints(
42010 Range.START_TO_START, nodeEndRange) == -1 &&
42011 rangeEndRange.compareBoundaryPoints(
42012 Range.START_TO_START, nodeStartRange) == 1;
42016 rangeCompareNode : function(range, node)
42018 var nodeRange = node.ownerDocument.createRange();
42020 nodeRange.selectNode(node);
42022 nodeRange.selectNodeContents(node);
42026 range.collapse(true);
42028 nodeRange.collapse(true);
42030 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
42031 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
42033 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
42035 var nodeIsBefore = ss == 1;
42036 var nodeIsAfter = ee == -1;
42038 if (nodeIsBefore && nodeIsAfter)
42040 if (!nodeIsBefore && nodeIsAfter)
42041 return 1; //right trailed.
42043 if (nodeIsBefore && !nodeIsAfter)
42044 return 2; // left trailed.
42049 // private? - in a new class?
42050 cleanUpPaste : function()
42052 // cleans up the whole document..
42053 Roo.log('cleanuppaste');
42055 this.cleanUpChildren(this.doc.body);
42056 var clean = this.cleanWordChars(this.doc.body.innerHTML);
42057 if (clean != this.doc.body.innerHTML) {
42058 this.doc.body.innerHTML = clean;
42063 cleanWordChars : function(input) {// change the chars to hex code
42064 var he = Roo.HtmlEditorCore;
42066 var output = input;
42067 Roo.each(he.swapCodes, function(sw) {
42068 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
42070 output = output.replace(swapper, sw[1]);
42077 cleanUpChildren : function (n)
42079 if (!n.childNodes.length) {
42082 for (var i = n.childNodes.length-1; i > -1 ; i--) {
42083 this.cleanUpChild(n.childNodes[i]);
42090 cleanUpChild : function (node)
42093 //console.log(node);
42094 if (node.nodeName == "#text") {
42095 // clean up silly Windows -- stuff?
42098 if (node.nodeName == "#comment") {
42099 node.parentNode.removeChild(node);
42100 // clean up silly Windows -- stuff?
42103 var lcname = node.tagName.toLowerCase();
42104 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
42105 // whitelist of tags..
42107 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
42109 node.parentNode.removeChild(node);
42114 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
42116 // remove <a name=....> as rendering on yahoo mailer is borked with this.
42117 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
42119 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
42120 // remove_keep_children = true;
42123 if (remove_keep_children) {
42124 this.cleanUpChildren(node);
42125 // inserts everything just before this node...
42126 while (node.childNodes.length) {
42127 var cn = node.childNodes[0];
42128 node.removeChild(cn);
42129 node.parentNode.insertBefore(cn, node);
42131 node.parentNode.removeChild(node);
42135 if (!node.attributes || !node.attributes.length) {
42136 this.cleanUpChildren(node);
42140 function cleanAttr(n,v)
42143 if (v.match(/^\./) || v.match(/^\//)) {
42146 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
42149 if (v.match(/^#/)) {
42152 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
42153 node.removeAttribute(n);
42157 var cwhite = this.cwhite;
42158 var cblack = this.cblack;
42160 function cleanStyle(n,v)
42162 if (v.match(/expression/)) { //XSS?? should we even bother..
42163 node.removeAttribute(n);
42167 var parts = v.split(/;/);
42170 Roo.each(parts, function(p) {
42171 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
42175 var l = p.split(':').shift().replace(/\s+/g,'');
42176 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
42178 if ( cwhite.length && cblack.indexOf(l) > -1) {
42179 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42180 //node.removeAttribute(n);
42184 // only allow 'c whitelisted system attributes'
42185 if ( cwhite.length && cwhite.indexOf(l) < 0) {
42186 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
42187 //node.removeAttribute(n);
42197 if (clean.length) {
42198 node.setAttribute(n, clean.join(';'));
42200 node.removeAttribute(n);
42206 for (var i = node.attributes.length-1; i > -1 ; i--) {
42207 var a = node.attributes[i];
42210 if (a.name.toLowerCase().substr(0,2)=='on') {
42211 node.removeAttribute(a.name);
42214 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
42215 node.removeAttribute(a.name);
42218 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
42219 cleanAttr(a.name,a.value); // fixme..
42222 if (a.name == 'style') {
42223 cleanStyle(a.name,a.value);
42226 /// clean up MS crap..
42227 // tecnically this should be a list of valid class'es..
42230 if (a.name == 'class') {
42231 if (a.value.match(/^Mso/)) {
42232 node.className = '';
42235 if (a.value.match(/body/)) {
42236 node.className = '';
42247 this.cleanUpChildren(node);
42252 * Clean up MS wordisms...
42254 cleanWord : function(node)
42257 var cleanWordChildren = function()
42259 if (!node.childNodes.length) {
42262 for (var i = node.childNodes.length-1; i > -1 ; i--) {
42263 _t.cleanWord(node.childNodes[i]);
42269 this.cleanWord(this.doc.body);
42272 if (node.nodeName == "#text") {
42273 // clean up silly Windows -- stuff?
42276 if (node.nodeName == "#comment") {
42277 node.parentNode.removeChild(node);
42278 // clean up silly Windows -- stuff?
42282 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
42283 node.parentNode.removeChild(node);
42287 // remove - but keep children..
42288 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
42289 while (node.childNodes.length) {
42290 var cn = node.childNodes[0];
42291 node.removeChild(cn);
42292 node.parentNode.insertBefore(cn, node);
42294 node.parentNode.removeChild(node);
42295 cleanWordChildren();
42299 if (node.className.length) {
42301 var cn = node.className.split(/\W+/);
42303 Roo.each(cn, function(cls) {
42304 if (cls.match(/Mso[a-zA-Z]+/)) {
42309 node.className = cna.length ? cna.join(' ') : '';
42311 node.removeAttribute("class");
42315 if (node.hasAttribute("lang")) {
42316 node.removeAttribute("lang");
42319 if (node.hasAttribute("style")) {
42321 var styles = node.getAttribute("style").split(";");
42323 Roo.each(styles, function(s) {
42324 if (!s.match(/:/)) {
42327 var kv = s.split(":");
42328 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
42331 // what ever is left... we allow.
42334 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
42335 if (!nstyle.length) {
42336 node.removeAttribute('style');
42340 cleanWordChildren();
42344 domToHTML : function(currentElement, depth, nopadtext) {
42346 depth = depth || 0;
42347 nopadtext = nopadtext || false;
42349 if (!currentElement) {
42350 return this.domToHTML(this.doc.body);
42353 //Roo.log(currentElement);
42355 var allText = false;
42356 var nodeName = currentElement.nodeName;
42357 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
42359 if (nodeName == '#text') {
42361 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
42366 if (nodeName != 'BODY') {
42369 // Prints the node tagName, such as <A>, <IMG>, etc
42372 for(i = 0; i < currentElement.attributes.length;i++) {
42374 var aname = currentElement.attributes.item(i).name;
42375 if (!currentElement.attributes.item(i).value.length) {
42378 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
42381 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
42390 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
42393 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
42398 // Traverse the tree
42400 var currentElementChild = currentElement.childNodes.item(i);
42401 var allText = true;
42402 var innerHTML = '';
42404 while (currentElementChild) {
42405 // Formatting code (indent the tree so it looks nice on the screen)
42406 var nopad = nopadtext;
42407 if (lastnode == 'SPAN') {
42411 if (currentElementChild.nodeName == '#text') {
42412 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
42413 toadd = nopadtext ? toadd : toadd.trim();
42414 if (!nopad && toadd.length > 80) {
42415 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
42417 innerHTML += toadd;
42420 currentElementChild = currentElement.childNodes.item(i);
42426 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
42428 // Recursively traverse the tree structure of the child node
42429 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
42430 lastnode = currentElementChild.nodeName;
42432 currentElementChild=currentElement.childNodes.item(i);
42438 // The remaining code is mostly for formatting the tree
42439 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
42444 ret+= "</"+tagName+">";
42450 applyBlacklists : function()
42452 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
42453 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
42457 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
42458 if (b.indexOf(tag) > -1) {
42461 this.white.push(tag);
42465 Roo.each(w, function(tag) {
42466 if (b.indexOf(tag) > -1) {
42469 if (this.white.indexOf(tag) > -1) {
42472 this.white.push(tag);
42477 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
42478 if (w.indexOf(tag) > -1) {
42481 this.black.push(tag);
42485 Roo.each(b, function(tag) {
42486 if (w.indexOf(tag) > -1) {
42489 if (this.black.indexOf(tag) > -1) {
42492 this.black.push(tag);
42497 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
42498 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
42502 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
42503 if (b.indexOf(tag) > -1) {
42506 this.cwhite.push(tag);
42510 Roo.each(w, function(tag) {
42511 if (b.indexOf(tag) > -1) {
42514 if (this.cwhite.indexOf(tag) > -1) {
42517 this.cwhite.push(tag);
42522 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
42523 if (w.indexOf(tag) > -1) {
42526 this.cblack.push(tag);
42530 Roo.each(b, function(tag) {
42531 if (w.indexOf(tag) > -1) {
42534 if (this.cblack.indexOf(tag) > -1) {
42537 this.cblack.push(tag);
42542 setStylesheets : function(stylesheets)
42544 if(typeof(stylesheets) == 'string'){
42545 Roo.get(this.iframe.contentDocument.head).createChild({
42547 rel : 'stylesheet',
42556 Roo.each(stylesheets, function(s) {
42561 Roo.get(_this.iframe.contentDocument.head).createChild({
42563 rel : 'stylesheet',
42572 removeStylesheets : function()
42576 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
42581 // hide stuff that is not compatible
42595 * @event specialkey
42599 * @cfg {String} fieldClass @hide
42602 * @cfg {String} focusClass @hide
42605 * @cfg {String} autoCreate @hide
42608 * @cfg {String} inputType @hide
42611 * @cfg {String} invalidClass @hide
42614 * @cfg {String} invalidText @hide
42617 * @cfg {String} msgFx @hide
42620 * @cfg {String} validateOnBlur @hide
42624 Roo.HtmlEditorCore.white = [
42625 'area', 'br', 'img', 'input', 'hr', 'wbr',
42627 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
42628 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
42629 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
42630 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
42631 'table', 'ul', 'xmp',
42633 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
42636 'dir', 'menu', 'ol', 'ul', 'dl',
42642 Roo.HtmlEditorCore.black = [
42643 // 'embed', 'object', // enable - backend responsiblity to clean thiese
42645 'base', 'basefont', 'bgsound', 'blink', 'body',
42646 'frame', 'frameset', 'head', 'html', 'ilayer',
42647 'iframe', 'layer', 'link', 'meta', 'object',
42648 'script', 'style' ,'title', 'xml' // clean later..
42650 Roo.HtmlEditorCore.clean = [
42651 'script', 'style', 'title', 'xml'
42653 Roo.HtmlEditorCore.remove = [
42658 Roo.HtmlEditorCore.ablack = [
42662 Roo.HtmlEditorCore.aclean = [
42663 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
42667 Roo.HtmlEditorCore.pwhite= [
42668 'http', 'https', 'mailto'
42671 // white listed style attributes.
42672 Roo.HtmlEditorCore.cwhite= [
42673 // 'text-align', /// default is to allow most things..
42679 // black listed style attributes.
42680 Roo.HtmlEditorCore.cblack= [
42681 // 'font-size' -- this can be set by the project
42685 Roo.HtmlEditorCore.swapCodes =[
42696 //<script type="text/javascript">
42699 * Ext JS Library 1.1.1
42700 * Copyright(c) 2006-2007, Ext JS, LLC.
42706 Roo.form.HtmlEditor = function(config){
42710 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
42712 if (!this.toolbars) {
42713 this.toolbars = [];
42715 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
42721 * @class Roo.form.HtmlEditor
42722 * @extends Roo.form.Field
42723 * Provides a lightweight HTML Editor component.
42725 * This has been tested on Fireforx / Chrome.. IE may not be so great..
42727 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
42728 * supported by this editor.</b><br/><br/>
42729 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
42730 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42732 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
42734 * @cfg {Boolean} clearUp
42738 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
42743 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42748 * @cfg {Number} height (in pixels)
42752 * @cfg {Number} width (in pixels)
42757 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42760 stylesheets: false,
42764 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
42769 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
42775 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
42780 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
42788 // private properties
42789 validationEvent : false,
42791 initialized : false,
42794 onFocus : Roo.emptyFn,
42796 hideMode:'offsets',
42798 actionMode : 'container', // defaults to hiding it...
42800 defaultAutoCreate : { // modified by initCompnoent..
42802 style:"width:500px;height:300px;",
42803 autocomplete: "new-password"
42807 initComponent : function(){
42810 * @event initialize
42811 * Fires when the editor is fully initialized (including the iframe)
42812 * @param {HtmlEditor} this
42817 * Fires when the editor is first receives the focus. Any insertion must wait
42818 * until after this event.
42819 * @param {HtmlEditor} this
42823 * @event beforesync
42824 * Fires before the textarea is updated with content from the editor iframe. Return false
42825 * to cancel the sync.
42826 * @param {HtmlEditor} this
42827 * @param {String} html
42831 * @event beforepush
42832 * Fires before the iframe editor is updated with content from the textarea. Return false
42833 * to cancel the push.
42834 * @param {HtmlEditor} this
42835 * @param {String} html
42840 * Fires when the textarea is updated with content from the editor iframe.
42841 * @param {HtmlEditor} this
42842 * @param {String} html
42847 * Fires when the iframe editor is updated with content from the textarea.
42848 * @param {HtmlEditor} this
42849 * @param {String} html
42853 * @event editmodechange
42854 * Fires when the editor switches edit modes
42855 * @param {HtmlEditor} this
42856 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
42858 editmodechange: true,
42860 * @event editorevent
42861 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42862 * @param {HtmlEditor} this
42866 * @event firstfocus
42867 * Fires when on first focus - needed by toolbars..
42868 * @param {HtmlEditor} this
42873 * Auto save the htmlEditor value as a file into Events
42874 * @param {HtmlEditor} this
42878 * @event savedpreview
42879 * preview the saved version of htmlEditor
42880 * @param {HtmlEditor} this
42882 savedpreview: true,
42885 * @event stylesheetsclick
42886 * Fires when press the Sytlesheets button
42887 * @param {Roo.HtmlEditorCore} this
42889 stylesheetsclick: true
42891 this.defaultAutoCreate = {
42893 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
42894 autocomplete: "new-password"
42899 * Protected method that will not generally be called directly. It
42900 * is called when the editor creates its toolbar. Override this method if you need to
42901 * add custom toolbar buttons.
42902 * @param {HtmlEditor} editor
42904 createToolbar : function(editor){
42905 Roo.log("create toolbars");
42906 if (!editor.toolbars || !editor.toolbars.length) {
42907 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
42910 for (var i =0 ; i < editor.toolbars.length;i++) {
42911 editor.toolbars[i] = Roo.factory(
42912 typeof(editor.toolbars[i]) == 'string' ?
42913 { xtype: editor.toolbars[i]} : editor.toolbars[i],
42914 Roo.form.HtmlEditor);
42915 editor.toolbars[i].init(editor);
42923 onRender : function(ct, position)
42926 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
42928 this.wrap = this.el.wrap({
42929 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
42932 this.editorcore.onRender(ct, position);
42934 if (this.resizable) {
42935 this.resizeEl = new Roo.Resizable(this.wrap, {
42939 minHeight : this.height,
42940 height: this.height,
42941 handles : this.resizable,
42944 resize : function(r, w, h) {
42945 _t.onResize(w,h); // -something
42951 this.createToolbar(this);
42955 this.setSize(this.wrap.getSize());
42957 if (this.resizeEl) {
42958 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
42959 // should trigger onReize..
42962 this.keyNav = new Roo.KeyNav(this.el, {
42964 "tab" : function(e){
42965 e.preventDefault();
42967 var value = this.getValue();
42969 var start = this.el.dom.selectionStart;
42970 var end = this.el.dom.selectionEnd;
42974 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
42975 this.el.dom.setSelectionRange(end + 1, end + 1);
42979 var f = value.substring(0, start).split("\t");
42981 if(f.pop().length != 0){
42985 this.setValue(f.join("\t") + value.substring(end));
42986 this.el.dom.setSelectionRange(start - 1, start - 1);
42990 "home" : function(e){
42991 e.preventDefault();
42993 var curr = this.el.dom.selectionStart;
42994 var lines = this.getValue().split("\n");
43001 this.el.dom.setSelectionRange(0, 0);
43007 for (var i = 0; i < lines.length;i++) {
43008 pos += lines[i].length;
43018 pos -= lines[i].length;
43024 this.el.dom.setSelectionRange(pos, pos);
43028 this.el.dom.selectionStart = pos;
43029 this.el.dom.selectionEnd = curr;
43032 "end" : function(e){
43033 e.preventDefault();
43035 var curr = this.el.dom.selectionStart;
43036 var lines = this.getValue().split("\n");
43043 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
43049 for (var i = 0; i < lines.length;i++) {
43051 pos += lines[i].length;
43065 this.el.dom.setSelectionRange(pos, pos);
43069 this.el.dom.selectionStart = curr;
43070 this.el.dom.selectionEnd = pos;
43075 doRelay : function(foo, bar, hname){
43076 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43082 // if(this.autosave && this.w){
43083 // this.autoSaveFn = setInterval(this.autosave, 1000);
43088 onResize : function(w, h)
43090 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
43095 if(typeof w == 'number'){
43096 var aw = w - this.wrap.getFrameWidth('lr');
43097 this.el.setWidth(this.adjustWidth('textarea', aw));
43100 if(typeof h == 'number'){
43102 for (var i =0; i < this.toolbars.length;i++) {
43103 // fixme - ask toolbars for heights?
43104 tbh += this.toolbars[i].tb.el.getHeight();
43105 if (this.toolbars[i].footer) {
43106 tbh += this.toolbars[i].footer.el.getHeight();
43113 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
43114 ah -= 5; // knock a few pixes off for look..
43116 this.el.setHeight(this.adjustWidth('textarea', ah));
43120 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
43121 this.editorcore.onResize(ew,eh);
43126 * Toggles the editor between standard and source edit mode.
43127 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43129 toggleSourceEdit : function(sourceEditMode)
43131 this.editorcore.toggleSourceEdit(sourceEditMode);
43133 if(this.editorcore.sourceEditMode){
43134 Roo.log('editor - showing textarea');
43137 // Roo.log(this.syncValue());
43138 this.editorcore.syncValue();
43139 this.el.removeClass('x-hidden');
43140 this.el.dom.removeAttribute('tabIndex');
43143 for (var i = 0; i < this.toolbars.length; i++) {
43144 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43145 this.toolbars[i].tb.hide();
43146 this.toolbars[i].footer.hide();
43151 Roo.log('editor - hiding textarea');
43153 // Roo.log(this.pushValue());
43154 this.editorcore.pushValue();
43156 this.el.addClass('x-hidden');
43157 this.el.dom.setAttribute('tabIndex', -1);
43159 for (var i = 0; i < this.toolbars.length; i++) {
43160 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
43161 this.toolbars[i].tb.show();
43162 this.toolbars[i].footer.show();
43166 //this.deferFocus();
43169 this.setSize(this.wrap.getSize());
43170 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
43172 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
43175 // private (for BoxComponent)
43176 adjustSize : Roo.BoxComponent.prototype.adjustSize,
43178 // private (for BoxComponent)
43179 getResizeEl : function(){
43183 // private (for BoxComponent)
43184 getPositionEl : function(){
43189 initEvents : function(){
43190 this.originalValue = this.getValue();
43194 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43197 markInvalid : Roo.emptyFn,
43199 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
43202 clearInvalid : Roo.emptyFn,
43204 setValue : function(v){
43205 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
43206 this.editorcore.pushValue();
43211 deferFocus : function(){
43212 this.focus.defer(10, this);
43216 focus : function(){
43217 this.editorcore.focus();
43223 onDestroy : function(){
43229 for (var i =0; i < this.toolbars.length;i++) {
43230 // fixme - ask toolbars for heights?
43231 this.toolbars[i].onDestroy();
43234 this.wrap.dom.innerHTML = '';
43235 this.wrap.remove();
43240 onFirstFocus : function(){
43241 //Roo.log("onFirstFocus");
43242 this.editorcore.onFirstFocus();
43243 for (var i =0; i < this.toolbars.length;i++) {
43244 this.toolbars[i].onFirstFocus();
43250 syncValue : function()
43252 this.editorcore.syncValue();
43255 pushValue : function()
43257 this.editorcore.pushValue();
43260 setStylesheets : function(stylesheets)
43262 this.editorcore.setStylesheets(stylesheets);
43265 removeStylesheets : function()
43267 this.editorcore.removeStylesheets();
43271 // hide stuff that is not compatible
43285 * @event specialkey
43289 * @cfg {String} fieldClass @hide
43292 * @cfg {String} focusClass @hide
43295 * @cfg {String} autoCreate @hide
43298 * @cfg {String} inputType @hide
43301 * @cfg {String} invalidClass @hide
43304 * @cfg {String} invalidText @hide
43307 * @cfg {String} msgFx @hide
43310 * @cfg {String} validateOnBlur @hide
43314 // <script type="text/javascript">
43317 * Ext JS Library 1.1.1
43318 * Copyright(c) 2006-2007, Ext JS, LLC.
43324 * @class Roo.form.HtmlEditorToolbar1
43329 new Roo.form.HtmlEditor({
43332 new Roo.form.HtmlEditorToolbar1({
43333 disable : { fonts: 1 , format: 1, ..., ... , ...],
43339 * @cfg {Object} disable List of elements to disable..
43340 * @cfg {Array} btns List of additional buttons.
43344 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
43347 Roo.form.HtmlEditor.ToolbarStandard = function(config)
43350 Roo.apply(this, config);
43352 // default disabled, based on 'good practice'..
43353 this.disable = this.disable || {};
43354 Roo.applyIf(this.disable, {
43357 specialElements : true
43361 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
43362 // dont call parent... till later.
43365 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
43372 editorcore : false,
43374 * @cfg {Object} disable List of toolbar elements to disable
43381 * @cfg {String} createLinkText The default text for the create link prompt
43383 createLinkText : 'Please enter the URL for the link:',
43385 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
43387 defaultLinkValue : 'http:/'+'/',
43391 * @cfg {Array} fontFamilies An array of available font families
43409 // "á" , ?? a acute?
43414 "°" // , // degrees
43416 // "é" , // e ecute
43417 // "ú" , // u ecute?
43420 specialElements : [
43422 text: "Insert Table",
43425 ihtml : '<table><tr><td>Cell</td></tr></table>'
43429 text: "Insert Image",
43432 ihtml : '<img src="about:blank"/>'
43441 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
43442 "input:submit", "input:button", "select", "textarea", "label" ],
43445 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
43447 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
43455 * @cfg {String} defaultFont default font to use.
43457 defaultFont: 'tahoma',
43459 fontSelect : false,
43462 formatCombo : false,
43464 init : function(editor)
43466 this.editor = editor;
43467 this.editorcore = editor.editorcore ? editor.editorcore : editor;
43468 var editorcore = this.editorcore;
43472 var fid = editorcore.frameId;
43474 function btn(id, toggle, handler){
43475 var xid = fid + '-'+ id ;
43479 cls : 'x-btn-icon x-edit-'+id,
43480 enableToggle:toggle !== false,
43481 scope: _t, // was editor...
43482 handler:handler||_t.relayBtnCmd,
43483 clickEvent:'mousedown',
43484 tooltip: etb.buttonTips[id] || undefined, ///tips ???
43491 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
43493 // stop form submits
43494 tb.el.on('click', function(e){
43495 e.preventDefault(); // what does this do?
43498 if(!this.disable.font) { // && !Roo.isSafari){
43499 /* why no safari for fonts
43500 editor.fontSelect = tb.el.createChild({
43503 cls:'x-font-select',
43504 html: this.createFontOptions()
43507 editor.fontSelect.on('change', function(){
43508 var font = editor.fontSelect.dom.value;
43509 editor.relayCmd('fontname', font);
43510 editor.deferFocus();
43514 editor.fontSelect.dom,
43520 if(!this.disable.formats){
43521 this.formatCombo = new Roo.form.ComboBox({
43522 store: new Roo.data.SimpleStore({
43525 data : this.formats // from states.js
43529 //autoCreate : {tag: "div", size: "20"},
43530 displayField:'tag',
43534 triggerAction: 'all',
43535 emptyText:'Add tag',
43536 selectOnFocus:true,
43539 'select': function(c, r, i) {
43540 editorcore.insertTag(r.get('tag'));
43546 tb.addField(this.formatCombo);
43550 if(!this.disable.format){
43557 if(!this.disable.fontSize){
43562 btn('increasefontsize', false, editorcore.adjustFont),
43563 btn('decreasefontsize', false, editorcore.adjustFont)
43568 if(!this.disable.colors){
43571 id:editorcore.frameId +'-forecolor',
43572 cls:'x-btn-icon x-edit-forecolor',
43573 clickEvent:'mousedown',
43574 tooltip: this.buttonTips['forecolor'] || undefined,
43576 menu : new Roo.menu.ColorMenu({
43577 allowReselect: true,
43578 focus: Roo.emptyFn,
43581 selectHandler: function(cp, color){
43582 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
43583 editor.deferFocus();
43586 clickEvent:'mousedown'
43589 id:editorcore.frameId +'backcolor',
43590 cls:'x-btn-icon x-edit-backcolor',
43591 clickEvent:'mousedown',
43592 tooltip: this.buttonTips['backcolor'] || undefined,
43594 menu : new Roo.menu.ColorMenu({
43595 focus: Roo.emptyFn,
43598 allowReselect: true,
43599 selectHandler: function(cp, color){
43601 editorcore.execCmd('useCSS', false);
43602 editorcore.execCmd('hilitecolor', color);
43603 editorcore.execCmd('useCSS', true);
43604 editor.deferFocus();
43606 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
43607 Roo.isSafari || Roo.isIE ? '#'+color : color);
43608 editor.deferFocus();
43612 clickEvent:'mousedown'
43617 // now add all the items...
43620 if(!this.disable.alignments){
43623 btn('justifyleft'),
43624 btn('justifycenter'),
43625 btn('justifyright')
43629 //if(!Roo.isSafari){
43630 if(!this.disable.links){
43633 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
43637 if(!this.disable.lists){
43640 btn('insertorderedlist'),
43641 btn('insertunorderedlist')
43644 if(!this.disable.sourceEdit){
43647 btn('sourceedit', true, function(btn){
43648 this.toggleSourceEdit(btn.pressed);
43655 // special menu.. - needs to be tidied up..
43656 if (!this.disable.special) {
43659 cls: 'x-edit-none',
43665 for (var i =0; i < this.specialChars.length; i++) {
43666 smenu.menu.items.push({
43668 html: this.specialChars[i],
43669 handler: function(a,b) {
43670 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
43671 //editor.insertAtCursor(a.html);
43685 if (!this.disable.cleanStyles) {
43687 cls: 'x-btn-icon x-btn-clear',
43693 for (var i =0; i < this.cleanStyles.length; i++) {
43694 cmenu.menu.items.push({
43695 actiontype : this.cleanStyles[i],
43696 html: 'Remove ' + this.cleanStyles[i],
43697 handler: function(a,b) {
43700 var c = Roo.get(editorcore.doc.body);
43701 c.select('[style]').each(function(s) {
43702 s.dom.style.removeProperty(a.actiontype);
43704 editorcore.syncValue();
43709 cmenu.menu.items.push({
43710 actiontype : 'word',
43711 html: 'Remove MS Word Formating',
43712 handler: function(a,b) {
43713 editorcore.cleanWord();
43714 editorcore.syncValue();
43719 cmenu.menu.items.push({
43720 actiontype : 'all',
43721 html: 'Remove All Styles',
43722 handler: function(a,b) {
43724 var c = Roo.get(editorcore.doc.body);
43725 c.select('[style]').each(function(s) {
43726 s.dom.removeAttribute('style');
43728 editorcore.syncValue();
43732 cmenu.menu.items.push({
43733 actiontype : 'word',
43734 html: 'Tidy HTML Source',
43735 handler: function(a,b) {
43736 editorcore.doc.body.innerHTML = editorcore.domToHTML();
43737 editorcore.syncValue();
43746 if (!this.disable.specialElements) {
43749 cls: 'x-edit-none',
43754 for (var i =0; i < this.specialElements.length; i++) {
43755 semenu.menu.items.push(
43757 handler: function(a,b) {
43758 editor.insertAtCursor(this.ihtml);
43760 }, this.specialElements[i])
43772 for(var i =0; i< this.btns.length;i++) {
43773 var b = Roo.factory(this.btns[i],Roo.form);
43774 b.cls = 'x-edit-none';
43776 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
43777 b.cls += ' x-init-enable';
43780 b.scope = editorcore;
43788 // disable everything...
43790 this.tb.items.each(function(item){
43793 item.id != editorcore.frameId+ '-sourceedit' &&
43794 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
43800 this.rendered = true;
43802 // the all the btns;
43803 editor.on('editorevent', this.updateToolbar, this);
43804 // other toolbars need to implement this..
43805 //editor.on('editmodechange', this.updateToolbar, this);
43809 relayBtnCmd : function(btn) {
43810 this.editorcore.relayCmd(btn.cmd);
43812 // private used internally
43813 createLink : function(){
43814 Roo.log("create link?");
43815 var url = prompt(this.createLinkText, this.defaultLinkValue);
43816 if(url && url != 'http:/'+'/'){
43817 this.editorcore.relayCmd('createlink', url);
43823 * Protected method that will not generally be called directly. It triggers
43824 * a toolbar update by reading the markup state of the current selection in the editor.
43826 updateToolbar: function(){
43828 if(!this.editorcore.activated){
43829 this.editor.onFirstFocus();
43833 var btns = this.tb.items.map,
43834 doc = this.editorcore.doc,
43835 frameId = this.editorcore.frameId;
43837 if(!this.disable.font && !Roo.isSafari){
43839 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
43840 if(name != this.fontSelect.dom.value){
43841 this.fontSelect.dom.value = name;
43845 if(!this.disable.format){
43846 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
43847 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
43848 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
43850 if(!this.disable.alignments){
43851 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
43852 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
43853 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
43855 if(!Roo.isSafari && !this.disable.lists){
43856 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
43857 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
43860 var ans = this.editorcore.getAllAncestors();
43861 if (this.formatCombo) {
43864 var store = this.formatCombo.store;
43865 this.formatCombo.setValue("");
43866 for (var i =0; i < ans.length;i++) {
43867 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
43869 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
43877 // hides menus... - so this cant be on a menu...
43878 Roo.menu.MenuMgr.hideAll();
43880 //this.editorsyncValue();
43884 createFontOptions : function(){
43885 var buf = [], fs = this.fontFamilies, ff, lc;
43889 for(var i = 0, len = fs.length; i< len; i++){
43891 lc = ff.toLowerCase();
43893 '<option value="',lc,'" style="font-family:',ff,';"',
43894 (this.defaultFont == lc ? ' selected="true">' : '>'),
43899 return buf.join('');
43902 toggleSourceEdit : function(sourceEditMode){
43904 Roo.log("toolbar toogle");
43905 if(sourceEditMode === undefined){
43906 sourceEditMode = !this.sourceEditMode;
43908 this.sourceEditMode = sourceEditMode === true;
43909 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
43910 // just toggle the button?
43911 if(btn.pressed !== this.sourceEditMode){
43912 btn.toggle(this.sourceEditMode);
43916 if(sourceEditMode){
43917 Roo.log("disabling buttons");
43918 this.tb.items.each(function(item){
43919 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
43925 Roo.log("enabling buttons");
43926 if(this.editorcore.initialized){
43927 this.tb.items.each(function(item){
43933 Roo.log("calling toggole on editor");
43934 // tell the editor that it's been pressed..
43935 this.editor.toggleSourceEdit(sourceEditMode);
43939 * Object collection of toolbar tooltips for the buttons in the editor. The key
43940 * is the command id associated with that button and the value is a valid QuickTips object.
43945 title: 'Bold (Ctrl+B)',
43946 text: 'Make the selected text bold.',
43947 cls: 'x-html-editor-tip'
43950 title: 'Italic (Ctrl+I)',
43951 text: 'Make the selected text italic.',
43952 cls: 'x-html-editor-tip'
43960 title: 'Bold (Ctrl+B)',
43961 text: 'Make the selected text bold.',
43962 cls: 'x-html-editor-tip'
43965 title: 'Italic (Ctrl+I)',
43966 text: 'Make the selected text italic.',
43967 cls: 'x-html-editor-tip'
43970 title: 'Underline (Ctrl+U)',
43971 text: 'Underline the selected text.',
43972 cls: 'x-html-editor-tip'
43974 increasefontsize : {
43975 title: 'Grow Text',
43976 text: 'Increase the font size.',
43977 cls: 'x-html-editor-tip'
43979 decreasefontsize : {
43980 title: 'Shrink Text',
43981 text: 'Decrease the font size.',
43982 cls: 'x-html-editor-tip'
43985 title: 'Text Highlight Color',
43986 text: 'Change the background color of the selected text.',
43987 cls: 'x-html-editor-tip'
43990 title: 'Font Color',
43991 text: 'Change the color of the selected text.',
43992 cls: 'x-html-editor-tip'
43995 title: 'Align Text Left',
43996 text: 'Align text to the left.',
43997 cls: 'x-html-editor-tip'
44000 title: 'Center Text',
44001 text: 'Center text in the editor.',
44002 cls: 'x-html-editor-tip'
44005 title: 'Align Text Right',
44006 text: 'Align text to the right.',
44007 cls: 'x-html-editor-tip'
44009 insertunorderedlist : {
44010 title: 'Bullet List',
44011 text: 'Start a bulleted list.',
44012 cls: 'x-html-editor-tip'
44014 insertorderedlist : {
44015 title: 'Numbered List',
44016 text: 'Start a numbered list.',
44017 cls: 'x-html-editor-tip'
44020 title: 'Hyperlink',
44021 text: 'Make the selected text a hyperlink.',
44022 cls: 'x-html-editor-tip'
44025 title: 'Source Edit',
44026 text: 'Switch to source editing mode.',
44027 cls: 'x-html-editor-tip'
44031 onDestroy : function(){
44034 this.tb.items.each(function(item){
44036 item.menu.removeAll();
44038 item.menu.el.destroy();
44046 onFirstFocus: function() {
44047 this.tb.items.each(function(item){
44056 // <script type="text/javascript">
44059 * Ext JS Library 1.1.1
44060 * Copyright(c) 2006-2007, Ext JS, LLC.
44067 * @class Roo.form.HtmlEditor.ToolbarContext
44072 new Roo.form.HtmlEditor({
44075 { xtype: 'ToolbarStandard', styles : {} }
44076 { xtype: 'ToolbarContext', disable : {} }
44082 * @config : {Object} disable List of elements to disable.. (not done yet.)
44083 * @config : {Object} styles Map of styles available.
44087 Roo.form.HtmlEditor.ToolbarContext = function(config)
44090 Roo.apply(this, config);
44091 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
44092 // dont call parent... till later.
44093 this.styles = this.styles || {};
44098 Roo.form.HtmlEditor.ToolbarContext.types = {
44110 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
44176 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
44181 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
44191 style : 'fontFamily',
44192 displayField: 'display',
44193 optname : 'font-family',
44242 // should we really allow this??
44243 // should this just be
44254 style : 'fontFamily',
44255 displayField: 'display',
44256 optname : 'font-family',
44263 style : 'fontFamily',
44264 displayField: 'display',
44265 optname : 'font-family',
44272 style : 'fontFamily',
44273 displayField: 'display',
44274 optname : 'font-family',
44285 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
44286 Roo.form.HtmlEditor.ToolbarContext.stores = false;
44288 Roo.form.HtmlEditor.ToolbarContext.options = {
44290 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
44291 [ 'Courier New', 'Courier New'],
44292 [ 'Tahoma', 'Tahoma'],
44293 [ 'Times New Roman,serif', 'Times'],
44294 [ 'Verdana','Verdana' ]
44298 // fixme - these need to be configurable..
44301 Roo.form.HtmlEditor.ToolbarContext.types
44304 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
44311 editorcore : false,
44313 * @cfg {Object} disable List of toolbar elements to disable
44318 * @cfg {Object} styles List of styles
44319 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
44321 * These must be defined in the page, so they get rendered correctly..
44332 init : function(editor)
44334 this.editor = editor;
44335 this.editorcore = editor.editorcore ? editor.editorcore : editor;
44336 var editorcore = this.editorcore;
44338 var fid = editorcore.frameId;
44340 function btn(id, toggle, handler){
44341 var xid = fid + '-'+ id ;
44345 cls : 'x-btn-icon x-edit-'+id,
44346 enableToggle:toggle !== false,
44347 scope: editorcore, // was editor...
44348 handler:handler||editorcore.relayBtnCmd,
44349 clickEvent:'mousedown',
44350 tooltip: etb.buttonTips[id] || undefined, ///tips ???
44354 // create a new element.
44355 var wdiv = editor.wrap.createChild({
44357 }, editor.wrap.dom.firstChild.nextSibling, true);
44359 // can we do this more than once??
44361 // stop form submits
44364 // disable everything...
44365 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44366 this.toolbars = {};
44368 for (var i in ty) {
44370 this.toolbars[i] = this.buildToolbar(ty[i],i);
44372 this.tb = this.toolbars.BODY;
44374 this.buildFooter();
44375 this.footer.show();
44376 editor.on('hide', function( ) { this.footer.hide() }, this);
44377 editor.on('show', function( ) { this.footer.show() }, this);
44380 this.rendered = true;
44382 // the all the btns;
44383 editor.on('editorevent', this.updateToolbar, this);
44384 // other toolbars need to implement this..
44385 //editor.on('editmodechange', this.updateToolbar, this);
44391 * Protected method that will not generally be called directly. It triggers
44392 * a toolbar update by reading the markup state of the current selection in the editor.
44394 updateToolbar: function(editor,ev,sel){
44397 // capture mouse up - this is handy for selecting images..
44398 // perhaps should go somewhere else...
44399 if(!this.editorcore.activated){
44400 this.editor.onFirstFocus();
44404 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
44405 // selectNode - might want to handle IE?
44407 (ev.type == 'mouseup' || ev.type == 'click' ) &&
44408 ev.target && ev.target.tagName == 'IMG') {
44409 // they have click on an image...
44410 // let's see if we can change the selection...
44413 var nodeRange = sel.ownerDocument.createRange();
44415 nodeRange.selectNode(sel);
44417 nodeRange.selectNodeContents(sel);
44419 //nodeRange.collapse(true);
44420 var s = this.editorcore.win.getSelection();
44421 s.removeAllRanges();
44422 s.addRange(nodeRange);
44426 var updateFooter = sel ? false : true;
44429 var ans = this.editorcore.getAllAncestors();
44432 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
44435 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
44436 sel = sel ? sel : this.editorcore.doc.body;
44437 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
44440 // pick a menu that exists..
44441 var tn = sel.tagName.toUpperCase();
44442 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
44444 tn = sel.tagName.toUpperCase();
44446 var lastSel = this.tb.selectedNode
44448 this.tb.selectedNode = sel;
44450 // if current menu does not match..
44451 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
44454 ///console.log("show: " + tn);
44455 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
44458 this.tb.items.first().el.innerHTML = tn + ': ';
44461 // update attributes
44462 if (this.tb.fields) {
44463 this.tb.fields.each(function(e) {
44465 e.setValue(sel.style[e.stylename]);
44468 e.setValue(sel.getAttribute(e.attrname));
44472 var hasStyles = false;
44473 for(var i in this.styles) {
44480 var st = this.tb.fields.item(0);
44482 st.store.removeAll();
44485 var cn = sel.className.split(/\s+/);
44488 if (this.styles['*']) {
44490 Roo.each(this.styles['*'], function(v) {
44491 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44494 if (this.styles[tn]) {
44495 Roo.each(this.styles[tn], function(v) {
44496 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
44500 st.store.loadData(avs);
44504 // flag our selected Node.
44505 this.tb.selectedNode = sel;
44508 Roo.menu.MenuMgr.hideAll();
44512 if (!updateFooter) {
44513 //this.footDisp.dom.innerHTML = '';
44516 // update the footer
44520 this.footerEls = ans.reverse();
44521 Roo.each(this.footerEls, function(a,i) {
44522 if (!a) { return; }
44523 html += html.length ? ' > ' : '';
44525 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
44530 var sz = this.footDisp.up('td').getSize();
44531 this.footDisp.dom.style.width = (sz.width -10) + 'px';
44532 this.footDisp.dom.style.marginLeft = '5px';
44534 this.footDisp.dom.style.overflow = 'hidden';
44536 this.footDisp.dom.innerHTML = html;
44538 //this.editorsyncValue();
44545 onDestroy : function(){
44548 this.tb.items.each(function(item){
44550 item.menu.removeAll();
44552 item.menu.el.destroy();
44560 onFirstFocus: function() {
44561 // need to do this for all the toolbars..
44562 this.tb.items.each(function(item){
44566 buildToolbar: function(tlist, nm)
44568 var editor = this.editor;
44569 var editorcore = this.editorcore;
44570 // create a new element.
44571 var wdiv = editor.wrap.createChild({
44573 }, editor.wrap.dom.firstChild.nextSibling, true);
44576 var tb = new Roo.Toolbar(wdiv);
44579 tb.add(nm+ ": ");
44582 for(var i in this.styles) {
44587 if (styles && styles.length) {
44589 // this needs a multi-select checkbox...
44590 tb.addField( new Roo.form.ComboBox({
44591 store: new Roo.data.SimpleStore({
44593 fields: ['val', 'selected'],
44596 name : '-roo-edit-className',
44597 attrname : 'className',
44598 displayField: 'val',
44602 triggerAction: 'all',
44603 emptyText:'Select Style',
44604 selectOnFocus:true,
44607 'select': function(c, r, i) {
44608 // initial support only for on class per el..
44609 tb.selectedNode.className = r ? r.get('val') : '';
44610 editorcore.syncValue();
44617 var tbc = Roo.form.HtmlEditor.ToolbarContext;
44618 var tbops = tbc.options;
44620 for (var i in tlist) {
44622 var item = tlist[i];
44623 tb.add(item.title + ": ");
44626 //optname == used so you can configure the options available..
44627 var opts = item.opts ? item.opts : false;
44628 if (item.optname) {
44629 opts = tbops[item.optname];
44634 // opts == pulldown..
44635 tb.addField( new Roo.form.ComboBox({
44636 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
44638 fields: ['val', 'display'],
44641 name : '-roo-edit-' + i,
44643 stylename : item.style ? item.style : false,
44644 displayField: item.displayField ? item.displayField : 'val',
44645 valueField : 'val',
44647 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
44649 triggerAction: 'all',
44650 emptyText:'Select',
44651 selectOnFocus:true,
44652 width: item.width ? item.width : 130,
44654 'select': function(c, r, i) {
44656 tb.selectedNode.style[c.stylename] = r.get('val');
44659 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
44668 tb.addField( new Roo.form.TextField({
44671 //allowBlank:false,
44676 tb.addField( new Roo.form.TextField({
44677 name: '-roo-edit-' + i,
44684 'change' : function(f, nv, ov) {
44685 tb.selectedNode.setAttribute(f.attrname, nv);
44698 text: 'Stylesheets',
44701 click : function ()
44703 _this.editor.fireEvent('stylesheetsclick', _this.editor);
44711 text: 'Remove Tag',
44714 click : function ()
44717 // undo does not work.
44719 var sn = tb.selectedNode;
44721 var pn = sn.parentNode;
44723 var stn = sn.childNodes[0];
44724 var en = sn.childNodes[sn.childNodes.length - 1 ];
44725 while (sn.childNodes.length) {
44726 var node = sn.childNodes[0];
44727 sn.removeChild(node);
44729 pn.insertBefore(node, sn);
44732 pn.removeChild(sn);
44733 var range = editorcore.createRange();
44735 range.setStart(stn,0);
44736 range.setEnd(en,0); //????
44737 //range.selectNode(sel);
44740 var selection = editorcore.getSelection();
44741 selection.removeAllRanges();
44742 selection.addRange(range);
44746 //_this.updateToolbar(null, null, pn);
44747 _this.updateToolbar(null, null, null);
44748 _this.footDisp.dom.innerHTML = '';
44758 tb.el.on('click', function(e){
44759 e.preventDefault(); // what does this do?
44761 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
44764 // dont need to disable them... as they will get hidden
44769 buildFooter : function()
44772 var fel = this.editor.wrap.createChild();
44773 this.footer = new Roo.Toolbar(fel);
44774 // toolbar has scrolly on left / right?
44775 var footDisp= new Roo.Toolbar.Fill();
44781 handler : function() {
44782 _t.footDisp.scrollTo('left',0,true)
44786 this.footer.add( footDisp );
44791 handler : function() {
44793 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
44797 var fel = Roo.get(footDisp.el);
44798 fel.addClass('x-editor-context');
44799 this.footDispWrap = fel;
44800 this.footDispWrap.overflow = 'hidden';
44802 this.footDisp = fel.createChild();
44803 this.footDispWrap.on('click', this.onContextClick, this)
44807 onContextClick : function (ev,dom)
44809 ev.preventDefault();
44810 var cn = dom.className;
44812 if (!cn.match(/x-ed-loc-/)) {
44815 var n = cn.split('-').pop();
44816 var ans = this.footerEls;
44820 var range = this.editorcore.createRange();
44822 range.selectNodeContents(sel);
44823 //range.selectNode(sel);
44826 var selection = this.editorcore.getSelection();
44827 selection.removeAllRanges();
44828 selection.addRange(range);
44832 this.updateToolbar(null, null, sel);
44849 * Ext JS Library 1.1.1
44850 * Copyright(c) 2006-2007, Ext JS, LLC.
44852 * Originally Released Under LGPL - original licence link has changed is not relivant.
44855 * <script type="text/javascript">
44859 * @class Roo.form.BasicForm
44860 * @extends Roo.util.Observable
44861 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
44863 * @param {String/HTMLElement/Roo.Element} el The form element or its id
44864 * @param {Object} config Configuration options
44866 Roo.form.BasicForm = function(el, config){
44867 this.allItems = [];
44868 this.childForms = [];
44869 Roo.apply(this, config);
44871 * The Roo.form.Field items in this form.
44872 * @type MixedCollection
44876 this.items = new Roo.util.MixedCollection(false, function(o){
44877 return o.id || (o.id = Roo.id());
44881 * @event beforeaction
44882 * Fires before any action is performed. Return false to cancel the action.
44883 * @param {Form} this
44884 * @param {Action} action The action to be performed
44886 beforeaction: true,
44888 * @event actionfailed
44889 * Fires when an action fails.
44890 * @param {Form} this
44891 * @param {Action} action The action that failed
44893 actionfailed : true,
44895 * @event actioncomplete
44896 * Fires when an action is completed.
44897 * @param {Form} this
44898 * @param {Action} action The action that completed
44900 actioncomplete : true
44905 Roo.form.BasicForm.superclass.constructor.call(this);
44908 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
44910 * @cfg {String} method
44911 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
44914 * @cfg {DataReader} reader
44915 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
44916 * This is optional as there is built-in support for processing JSON.
44919 * @cfg {DataReader} errorReader
44920 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
44921 * This is completely optional as there is built-in support for processing JSON.
44924 * @cfg {String} url
44925 * The URL to use for form actions if one isn't supplied in the action options.
44928 * @cfg {Boolean} fileUpload
44929 * Set to true if this form is a file upload.
44933 * @cfg {Object} baseParams
44934 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
44939 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
44944 activeAction : null,
44947 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
44948 * or setValues() data instead of when the form was first created.
44950 trackResetOnLoad : false,
44954 * childForms - used for multi-tab forms
44957 childForms : false,
44960 * allItems - full list of fields.
44966 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
44967 * element by passing it or its id or mask the form itself by passing in true.
44970 waitMsgTarget : false,
44973 initEl : function(el){
44974 this.el = Roo.get(el);
44975 this.id = this.el.id || Roo.id();
44976 this.el.on('submit', this.onSubmit, this);
44977 this.el.addClass('x-form');
44981 onSubmit : function(e){
44986 * Returns true if client-side validation on the form is successful.
44989 isValid : function(){
44991 this.items.each(function(f){
45000 * Returns true if any fields in this form have changed since their original load.
45003 isDirty : function(){
45005 this.items.each(function(f){
45015 * Performs a predefined action (submit or load) or custom actions you define on this form.
45016 * @param {String} actionName The name of the action type
45017 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
45018 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
45019 * accept other config options):
45021 Property Type Description
45022 ---------------- --------------- ----------------------------------------------------------------------------------
45023 url String The url for the action (defaults to the form's url)
45024 method String The form method to use (defaults to the form's method, or POST if not defined)
45025 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
45026 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
45027 validate the form on the client (defaults to false)
45029 * @return {BasicForm} this
45031 doAction : function(action, options){
45032 if(typeof action == 'string'){
45033 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
45035 if(this.fireEvent('beforeaction', this, action) !== false){
45036 this.beforeAction(action);
45037 action.run.defer(100, action);
45043 * Shortcut to do a submit action.
45044 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45045 * @return {BasicForm} this
45047 submit : function(options){
45048 this.doAction('submit', options);
45053 * Shortcut to do a load action.
45054 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
45055 * @return {BasicForm} this
45057 load : function(options){
45058 this.doAction('load', options);
45063 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
45064 * @param {Record} record The record to edit
45065 * @return {BasicForm} this
45067 updateRecord : function(record){
45068 record.beginEdit();
45069 var fs = record.fields;
45070 fs.each(function(f){
45071 var field = this.findField(f.name);
45073 record.set(f.name, field.getValue());
45081 * Loads an Roo.data.Record into this form.
45082 * @param {Record} record The record to load
45083 * @return {BasicForm} this
45085 loadRecord : function(record){
45086 this.setValues(record.data);
45091 beforeAction : function(action){
45092 var o = action.options;
45095 if(this.waitMsgTarget === true){
45096 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
45097 }else if(this.waitMsgTarget){
45098 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
45099 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
45101 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
45107 afterAction : function(action, success){
45108 this.activeAction = null;
45109 var o = action.options;
45111 if(this.waitMsgTarget === true){
45113 }else if(this.waitMsgTarget){
45114 this.waitMsgTarget.unmask();
45116 Roo.MessageBox.updateProgress(1);
45117 Roo.MessageBox.hide();
45124 Roo.callback(o.success, o.scope, [this, action]);
45125 this.fireEvent('actioncomplete', this, action);
45129 // failure condition..
45130 // we have a scenario where updates need confirming.
45131 // eg. if a locking scenario exists..
45132 // we look for { errors : { needs_confirm : true }} in the response.
45134 (typeof(action.result) != 'undefined') &&
45135 (typeof(action.result.errors) != 'undefined') &&
45136 (typeof(action.result.errors.needs_confirm) != 'undefined')
45139 Roo.MessageBox.confirm(
45140 "Change requires confirmation",
45141 action.result.errorMsg,
45146 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
45156 Roo.callback(o.failure, o.scope, [this, action]);
45157 // show an error message if no failed handler is set..
45158 if (!this.hasListener('actionfailed')) {
45159 Roo.MessageBox.alert("Error",
45160 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
45161 action.result.errorMsg :
45162 "Saving Failed, please check your entries or try again"
45166 this.fireEvent('actionfailed', this, action);
45172 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
45173 * @param {String} id The value to search for
45176 findField : function(id){
45177 var field = this.items.get(id);
45179 this.items.each(function(f){
45180 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
45186 return field || null;
45190 * Add a secondary form to this one,
45191 * Used to provide tabbed forms. One form is primary, with hidden values
45192 * which mirror the elements from the other forms.
45194 * @param {Roo.form.Form} form to add.
45197 addForm : function(form)
45200 if (this.childForms.indexOf(form) > -1) {
45204 this.childForms.push(form);
45206 Roo.each(form.allItems, function (fe) {
45208 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
45209 if (this.findField(n)) { // already added..
45212 var add = new Roo.form.Hidden({
45215 add.render(this.el);
45222 * Mark fields in this form invalid in bulk.
45223 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
45224 * @return {BasicForm} this
45226 markInvalid : function(errors){
45227 if(errors instanceof Array){
45228 for(var i = 0, len = errors.length; i < len; i++){
45229 var fieldError = errors[i];
45230 var f = this.findField(fieldError.id);
45232 f.markInvalid(fieldError.msg);
45238 if(typeof errors[id] != 'function' && (field = this.findField(id))){
45239 field.markInvalid(errors[id]);
45243 Roo.each(this.childForms || [], function (f) {
45244 f.markInvalid(errors);
45251 * Set values for fields in this form in bulk.
45252 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
45253 * @return {BasicForm} this
45255 setValues : function(values){
45256 if(values instanceof Array){ // array of objects
45257 for(var i = 0, len = values.length; i < len; i++){
45259 var f = this.findField(v.id);
45261 f.setValue(v.value);
45262 if(this.trackResetOnLoad){
45263 f.originalValue = f.getValue();
45267 }else{ // object hash
45270 if(typeof values[id] != 'function' && (field = this.findField(id))){
45272 if (field.setFromData &&
45273 field.valueField &&
45274 field.displayField &&
45275 // combos' with local stores can
45276 // be queried via setValue()
45277 // to set their value..
45278 (field.store && !field.store.isLocal)
45282 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
45283 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
45284 field.setFromData(sd);
45287 field.setValue(values[id]);
45291 if(this.trackResetOnLoad){
45292 field.originalValue = field.getValue();
45298 Roo.each(this.childForms || [], function (f) {
45299 f.setValues(values);
45306 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
45307 * they are returned as an array.
45308 * @param {Boolean} asString
45311 getValues : function(asString){
45312 if (this.childForms) {
45313 // copy values from the child forms
45314 Roo.each(this.childForms, function (f) {
45315 this.setValues(f.getValues());
45321 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
45322 if(asString === true){
45325 return Roo.urlDecode(fs);
45329 * Returns the fields in this form as an object with key/value pairs.
45330 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
45333 getFieldValues : function(with_hidden)
45335 if (this.childForms) {
45336 // copy values from the child forms
45337 // should this call getFieldValues - probably not as we do not currently copy
45338 // hidden fields when we generate..
45339 Roo.each(this.childForms, function (f) {
45340 this.setValues(f.getValues());
45345 this.items.each(function(f){
45346 if (!f.getName()) {
45349 var v = f.getValue();
45350 if (f.inputType =='radio') {
45351 if (typeof(ret[f.getName()]) == 'undefined') {
45352 ret[f.getName()] = ''; // empty..
45355 if (!f.el.dom.checked) {
45359 v = f.el.dom.value;
45363 // not sure if this supported any more..
45364 if ((typeof(v) == 'object') && f.getRawValue) {
45365 v = f.getRawValue() ; // dates..
45367 // combo boxes where name != hiddenName...
45368 if (f.name != f.getName()) {
45369 ret[f.name] = f.getRawValue();
45371 ret[f.getName()] = v;
45378 * Clears all invalid messages in this form.
45379 * @return {BasicForm} this
45381 clearInvalid : function(){
45382 this.items.each(function(f){
45386 Roo.each(this.childForms || [], function (f) {
45395 * Resets this form.
45396 * @return {BasicForm} this
45398 reset : function(){
45399 this.items.each(function(f){
45403 Roo.each(this.childForms || [], function (f) {
45412 * Add Roo.form components to this form.
45413 * @param {Field} field1
45414 * @param {Field} field2 (optional)
45415 * @param {Field} etc (optional)
45416 * @return {BasicForm} this
45419 this.items.addAll(Array.prototype.slice.call(arguments, 0));
45425 * Removes a field from the items collection (does NOT remove its markup).
45426 * @param {Field} field
45427 * @return {BasicForm} this
45429 remove : function(field){
45430 this.items.remove(field);
45435 * Looks at the fields in this form, checks them for an id attribute,
45436 * and calls applyTo on the existing dom element with that id.
45437 * @return {BasicForm} this
45439 render : function(){
45440 this.items.each(function(f){
45441 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
45449 * Calls {@link Ext#apply} for all fields in this form with the passed object.
45450 * @param {Object} values
45451 * @return {BasicForm} this
45453 applyToFields : function(o){
45454 this.items.each(function(f){
45461 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
45462 * @param {Object} values
45463 * @return {BasicForm} this
45465 applyIfToFields : function(o){
45466 this.items.each(function(f){
45474 Roo.BasicForm = Roo.form.BasicForm;/*
45476 * Ext JS Library 1.1.1
45477 * Copyright(c) 2006-2007, Ext JS, LLC.
45479 * Originally Released Under LGPL - original licence link has changed is not relivant.
45482 * <script type="text/javascript">
45486 * @class Roo.form.Form
45487 * @extends Roo.form.BasicForm
45488 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
45490 * @param {Object} config Configuration options
45492 Roo.form.Form = function(config){
45494 if (config.items) {
45495 xitems = config.items;
45496 delete config.items;
45500 Roo.form.Form.superclass.constructor.call(this, null, config);
45501 this.url = this.url || this.action;
45503 this.root = new Roo.form.Layout(Roo.applyIf({
45507 this.active = this.root;
45509 * Array of all the buttons that have been added to this form via {@link addButton}
45513 this.allItems = [];
45516 * @event clientvalidation
45517 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
45518 * @param {Form} this
45519 * @param {Boolean} valid true if the form has passed client-side validation
45521 clientvalidation: true,
45524 * Fires when the form is rendered
45525 * @param {Roo.form.Form} form
45530 if (this.progressUrl) {
45531 // push a hidden field onto the list of fields..
45535 name : 'UPLOAD_IDENTIFIER'
45540 Roo.each(xitems, this.addxtype, this);
45546 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
45548 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
45551 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
45554 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
45556 buttonAlign:'center',
45559 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
45564 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
45565 * This property cascades to child containers if not set.
45570 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
45571 * fires a looping event with that state. This is required to bind buttons to the valid
45572 * state using the config value formBind:true on the button.
45574 monitorValid : false,
45577 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
45582 * @cfg {String} progressUrl - Url to return progress data
45585 progressUrl : false,
45588 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
45589 * fields are added and the column is closed. If no fields are passed the column remains open
45590 * until end() is called.
45591 * @param {Object} config The config to pass to the column
45592 * @param {Field} field1 (optional)
45593 * @param {Field} field2 (optional)
45594 * @param {Field} etc (optional)
45595 * @return Column The column container object
45597 column : function(c){
45598 var col = new Roo.form.Column(c);
45600 if(arguments.length > 1){ // duplicate code required because of Opera
45601 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45608 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
45609 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
45610 * until end() is called.
45611 * @param {Object} config The config to pass to the fieldset
45612 * @param {Field} field1 (optional)
45613 * @param {Field} field2 (optional)
45614 * @param {Field} etc (optional)
45615 * @return FieldSet The fieldset container object
45617 fieldset : function(c){
45618 var fs = new Roo.form.FieldSet(c);
45620 if(arguments.length > 1){ // duplicate code required because of Opera
45621 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45628 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
45629 * fields are added and the container is closed. If no fields are passed the container remains open
45630 * until end() is called.
45631 * @param {Object} config The config to pass to the Layout
45632 * @param {Field} field1 (optional)
45633 * @param {Field} field2 (optional)
45634 * @param {Field} etc (optional)
45635 * @return Layout The container object
45637 container : function(c){
45638 var l = new Roo.form.Layout(c);
45640 if(arguments.length > 1){ // duplicate code required because of Opera
45641 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
45648 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
45649 * @param {Object} container A Roo.form.Layout or subclass of Layout
45650 * @return {Form} this
45652 start : function(c){
45653 // cascade label info
45654 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
45655 this.active.stack.push(c);
45656 c.ownerCt = this.active;
45662 * Closes the current open container
45663 * @return {Form} this
45666 if(this.active == this.root){
45669 this.active = this.active.ownerCt;
45674 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
45675 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
45676 * as the label of the field.
45677 * @param {Field} field1
45678 * @param {Field} field2 (optional)
45679 * @param {Field} etc. (optional)
45680 * @return {Form} this
45683 this.active.stack.push.apply(this.active.stack, arguments);
45684 this.allItems.push.apply(this.allItems,arguments);
45686 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
45687 if(a[i].isFormField){
45692 Roo.form.Form.superclass.add.apply(this, r);
45702 * Find any element that has been added to a form, using it's ID or name
45703 * This can include framesets, columns etc. along with regular fields..
45704 * @param {String} id - id or name to find.
45706 * @return {Element} e - or false if nothing found.
45708 findbyId : function(id)
45714 Roo.each(this.allItems, function(f){
45715 if (f.id == id || f.name == id ){
45726 * Render this form into the passed container. This should only be called once!
45727 * @param {String/HTMLElement/Element} container The element this component should be rendered into
45728 * @return {Form} this
45730 render : function(ct)
45736 var o = this.autoCreate || {
45738 method : this.method || 'POST',
45739 id : this.id || Roo.id()
45741 this.initEl(ct.createChild(o));
45743 this.root.render(this.el);
45747 this.items.each(function(f){
45748 f.render('x-form-el-'+f.id);
45751 if(this.buttons.length > 0){
45752 // tables are required to maintain order and for correct IE layout
45753 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
45754 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
45755 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
45757 var tr = tb.getElementsByTagName('tr')[0];
45758 for(var i = 0, len = this.buttons.length; i < len; i++) {
45759 var b = this.buttons[i];
45760 var td = document.createElement('td');
45761 td.className = 'x-form-btn-td';
45762 b.render(tr.appendChild(td));
45765 if(this.monitorValid){ // initialize after render
45766 this.startMonitoring();
45768 this.fireEvent('rendered', this);
45773 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
45774 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
45775 * object or a valid Roo.DomHelper element config
45776 * @param {Function} handler The function called when the button is clicked
45777 * @param {Object} scope (optional) The scope of the handler function
45778 * @return {Roo.Button}
45780 addButton : function(config, handler, scope){
45784 minWidth: this.minButtonWidth,
45787 if(typeof config == "string"){
45790 Roo.apply(bc, config);
45792 var btn = new Roo.Button(null, bc);
45793 this.buttons.push(btn);
45798 * Adds a series of form elements (using the xtype property as the factory method.
45799 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
45800 * @param {Object} config
45803 addxtype : function()
45805 var ar = Array.prototype.slice.call(arguments, 0);
45807 for(var i = 0; i < ar.length; i++) {
45809 continue; // skip -- if this happends something invalid got sent, we
45810 // should ignore it, as basically that interface element will not show up
45811 // and that should be pretty obvious!!
45814 if (Roo.form[ar[i].xtype]) {
45816 var fe = Roo.factory(ar[i], Roo.form);
45822 fe.store.form = this;
45827 this.allItems.push(fe);
45828 if (fe.items && fe.addxtype) {
45829 fe.addxtype.apply(fe, fe.items);
45839 // console.log('adding ' + ar[i].xtype);
45841 if (ar[i].xtype == 'Button') {
45842 //console.log('adding button');
45843 //console.log(ar[i]);
45844 this.addButton(ar[i]);
45845 this.allItems.push(fe);
45849 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
45850 alert('end is not supported on xtype any more, use items');
45852 // //console.log('adding end');
45860 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
45861 * option "monitorValid"
45863 startMonitoring : function(){
45866 Roo.TaskMgr.start({
45867 run : this.bindHandler,
45868 interval : this.monitorPoll || 200,
45875 * Stops monitoring of the valid state of this form
45877 stopMonitoring : function(){
45878 this.bound = false;
45882 bindHandler : function(){
45884 return false; // stops binding
45887 this.items.each(function(f){
45888 if(!f.isValid(true)){
45893 for(var i = 0, len = this.buttons.length; i < len; i++){
45894 var btn = this.buttons[i];
45895 if(btn.formBind === true && btn.disabled === valid){
45896 btn.setDisabled(!valid);
45899 this.fireEvent('clientvalidation', this, valid);
45913 Roo.Form = Roo.form.Form;
45916 * Ext JS Library 1.1.1
45917 * Copyright(c) 2006-2007, Ext JS, LLC.
45919 * Originally Released Under LGPL - original licence link has changed is not relivant.
45922 * <script type="text/javascript">
45925 // as we use this in bootstrap.
45926 Roo.namespace('Roo.form');
45928 * @class Roo.form.Action
45929 * Internal Class used to handle form actions
45931 * @param {Roo.form.BasicForm} el The form element or its id
45932 * @param {Object} config Configuration options
45937 // define the action interface
45938 Roo.form.Action = function(form, options){
45940 this.options = options || {};
45943 * Client Validation Failed
45946 Roo.form.Action.CLIENT_INVALID = 'client';
45948 * Server Validation Failed
45951 Roo.form.Action.SERVER_INVALID = 'server';
45953 * Connect to Server Failed
45956 Roo.form.Action.CONNECT_FAILURE = 'connect';
45958 * Reading Data from Server Failed
45961 Roo.form.Action.LOAD_FAILURE = 'load';
45963 Roo.form.Action.prototype = {
45965 failureType : undefined,
45966 response : undefined,
45967 result : undefined,
45969 // interface method
45970 run : function(options){
45974 // interface method
45975 success : function(response){
45979 // interface method
45980 handleResponse : function(response){
45984 // default connection failure
45985 failure : function(response){
45987 this.response = response;
45988 this.failureType = Roo.form.Action.CONNECT_FAILURE;
45989 this.form.afterAction(this, false);
45992 processResponse : function(response){
45993 this.response = response;
45994 if(!response.responseText){
45997 this.result = this.handleResponse(response);
45998 return this.result;
46001 // utility functions used internally
46002 getUrl : function(appendParams){
46003 var url = this.options.url || this.form.url || this.form.el.dom.action;
46005 var p = this.getParams();
46007 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
46013 getMethod : function(){
46014 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
46017 getParams : function(){
46018 var bp = this.form.baseParams;
46019 var p = this.options.params;
46021 if(typeof p == "object"){
46022 p = Roo.urlEncode(Roo.applyIf(p, bp));
46023 }else if(typeof p == 'string' && bp){
46024 p += '&' + Roo.urlEncode(bp);
46027 p = Roo.urlEncode(bp);
46032 createCallback : function(){
46034 success: this.success,
46035 failure: this.failure,
46037 timeout: (this.form.timeout*1000),
46038 upload: this.form.fileUpload ? this.success : undefined
46043 Roo.form.Action.Submit = function(form, options){
46044 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
46047 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
46050 haveProgress : false,
46051 uploadComplete : false,
46053 // uploadProgress indicator.
46054 uploadProgress : function()
46056 if (!this.form.progressUrl) {
46060 if (!this.haveProgress) {
46061 Roo.MessageBox.progress("Uploading", "Uploading");
46063 if (this.uploadComplete) {
46064 Roo.MessageBox.hide();
46068 this.haveProgress = true;
46070 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
46072 var c = new Roo.data.Connection();
46074 url : this.form.progressUrl,
46079 success : function(req){
46080 //console.log(data);
46084 rdata = Roo.decode(req.responseText)
46086 Roo.log("Invalid data from server..");
46090 if (!rdata || !rdata.success) {
46092 Roo.MessageBox.alert(Roo.encode(rdata));
46095 var data = rdata.data;
46097 if (this.uploadComplete) {
46098 Roo.MessageBox.hide();
46103 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
46104 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
46107 this.uploadProgress.defer(2000,this);
46110 failure: function(data) {
46111 Roo.log('progress url failed ');
46122 // run get Values on the form, so it syncs any secondary forms.
46123 this.form.getValues();
46125 var o = this.options;
46126 var method = this.getMethod();
46127 var isPost = method == 'POST';
46128 if(o.clientValidation === false || this.form.isValid()){
46130 if (this.form.progressUrl) {
46131 this.form.findField('UPLOAD_IDENTIFIER').setValue(
46132 (new Date() * 1) + '' + Math.random());
46137 Roo.Ajax.request(Roo.apply(this.createCallback(), {
46138 form:this.form.el.dom,
46139 url:this.getUrl(!isPost),
46141 params:isPost ? this.getParams() : null,
46142 isUpload: this.form.fileUpload
46145 this.uploadProgress();
46147 }else if (o.clientValidation !== false){ // client validation failed
46148 this.failureType = Roo.form.Action.CLIENT_INVALID;
46149 this.form.afterAction(this, false);
46153 success : function(response)
46155 this.uploadComplete= true;
46156 if (this.haveProgress) {
46157 Roo.MessageBox.hide();
46161 var result = this.processResponse(response);
46162 if(result === true || result.success){
46163 this.form.afterAction(this, true);
46167 this.form.markInvalid(result.errors);
46168 this.failureType = Roo.form.Action.SERVER_INVALID;
46170 this.form.afterAction(this, false);
46172 failure : function(response)
46174 this.uploadComplete= true;
46175 if (this.haveProgress) {
46176 Roo.MessageBox.hide();
46179 this.response = response;
46180 this.failureType = Roo.form.Action.CONNECT_FAILURE;
46181 this.form.afterAction(this, false);
46184 handleResponse : function(response){
46185 if(this.form.errorReader){
46186 var rs = this.form.errorReader.read(response);
46189 for(var i = 0, len = rs.records.length; i < len; i++) {
46190 var r = rs.records[i];
46191 errors[i] = r.data;
46194 if(errors.length < 1){
46198 success : rs.success,
46204 ret = Roo.decode(response.responseText);
46208 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
46218 Roo.form.Action.Load = function(form, options){
46219 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
46220 this.reader = this.form.reader;
46223 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
46228 Roo.Ajax.request(Roo.apply(
46229 this.createCallback(), {
46230 method:this.getMethod(),
46231 url:this.getUrl(false),
46232 params:this.getParams()
46236 success : function(response){
46238 var result = this.processResponse(response);
46239 if(result === true || !result.success || !result.data){
46240 this.failureType = Roo.form.Action.LOAD_FAILURE;
46241 this.form.afterAction(this, false);
46244 this.form.clearInvalid();
46245 this.form.setValues(result.data);
46246 this.form.afterAction(this, true);
46249 handleResponse : function(response){
46250 if(this.form.reader){
46251 var rs = this.form.reader.read(response);
46252 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
46254 success : rs.success,
46258 return Roo.decode(response.responseText);
46262 Roo.form.Action.ACTION_TYPES = {
46263 'load' : Roo.form.Action.Load,
46264 'submit' : Roo.form.Action.Submit
46267 * Ext JS Library 1.1.1
46268 * Copyright(c) 2006-2007, Ext JS, LLC.
46270 * Originally Released Under LGPL - original licence link has changed is not relivant.
46273 * <script type="text/javascript">
46277 * @class Roo.form.Layout
46278 * @extends Roo.Component
46279 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
46281 * @param {Object} config Configuration options
46283 Roo.form.Layout = function(config){
46285 if (config.items) {
46286 xitems = config.items;
46287 delete config.items;
46289 Roo.form.Layout.superclass.constructor.call(this, config);
46291 Roo.each(xitems, this.addxtype, this);
46295 Roo.extend(Roo.form.Layout, Roo.Component, {
46297 * @cfg {String/Object} autoCreate
46298 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
46301 * @cfg {String/Object/Function} style
46302 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
46303 * a function which returns such a specification.
46306 * @cfg {String} labelAlign
46307 * Valid values are "left," "top" and "right" (defaults to "left")
46310 * @cfg {Number} labelWidth
46311 * Fixed width in pixels of all field labels (defaults to undefined)
46314 * @cfg {Boolean} clear
46315 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
46319 * @cfg {String} labelSeparator
46320 * The separator to use after field labels (defaults to ':')
46322 labelSeparator : ':',
46324 * @cfg {Boolean} hideLabels
46325 * True to suppress the display of field labels in this layout (defaults to false)
46327 hideLabels : false,
46330 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
46335 onRender : function(ct, position){
46336 if(this.el){ // from markup
46337 this.el = Roo.get(this.el);
46338 }else { // generate
46339 var cfg = this.getAutoCreate();
46340 this.el = ct.createChild(cfg, position);
46343 this.el.applyStyles(this.style);
46345 if(this.labelAlign){
46346 this.el.addClass('x-form-label-'+this.labelAlign);
46348 if(this.hideLabels){
46349 this.labelStyle = "display:none";
46350 this.elementStyle = "padding-left:0;";
46352 if(typeof this.labelWidth == 'number'){
46353 this.labelStyle = "width:"+this.labelWidth+"px;";
46354 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
46356 if(this.labelAlign == 'top'){
46357 this.labelStyle = "width:auto;";
46358 this.elementStyle = "padding-left:0;";
46361 var stack = this.stack;
46362 var slen = stack.length;
46364 if(!this.fieldTpl){
46365 var t = new Roo.Template(
46366 '<div class="x-form-item {5}">',
46367 '<label for="{0}" style="{2}">{1}{4}</label>',
46368 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46370 '</div><div class="x-form-clear-left"></div>'
46372 t.disableFormats = true;
46374 Roo.form.Layout.prototype.fieldTpl = t;
46376 for(var i = 0; i < slen; i++) {
46377 if(stack[i].isFormField){
46378 this.renderField(stack[i]);
46380 this.renderComponent(stack[i]);
46385 this.el.createChild({cls:'x-form-clear'});
46390 renderField : function(f){
46391 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
46394 f.labelStyle||this.labelStyle||'', //2
46395 this.elementStyle||'', //3
46396 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
46397 f.itemCls||this.itemCls||'' //5
46398 ], true).getPrevSibling());
46402 renderComponent : function(c){
46403 c.render(c.isLayout ? this.el : this.el.createChild());
46406 * Adds a object form elements (using the xtype property as the factory method.)
46407 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
46408 * @param {Object} config
46410 addxtype : function(o)
46412 // create the lement.
46413 o.form = this.form;
46414 var fe = Roo.factory(o, Roo.form);
46415 this.form.allItems.push(fe);
46416 this.stack.push(fe);
46418 if (fe.isFormField) {
46419 this.form.items.add(fe);
46427 * @class Roo.form.Column
46428 * @extends Roo.form.Layout
46429 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
46431 * @param {Object} config Configuration options
46433 Roo.form.Column = function(config){
46434 Roo.form.Column.superclass.constructor.call(this, config);
46437 Roo.extend(Roo.form.Column, Roo.form.Layout, {
46439 * @cfg {Number/String} width
46440 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46443 * @cfg {String/Object} autoCreate
46444 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
46448 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
46451 onRender : function(ct, position){
46452 Roo.form.Column.superclass.onRender.call(this, ct, position);
46454 this.el.setWidth(this.width);
46461 * @class Roo.form.Row
46462 * @extends Roo.form.Layout
46463 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
46465 * @param {Object} config Configuration options
46469 Roo.form.Row = function(config){
46470 Roo.form.Row.superclass.constructor.call(this, config);
46473 Roo.extend(Roo.form.Row, Roo.form.Layout, {
46475 * @cfg {Number/String} width
46476 * The fixed width of the column in pixels or CSS value (defaults to "auto")
46479 * @cfg {Number/String} height
46480 * The fixed height of the column in pixels or CSS value (defaults to "auto")
46482 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
46486 onRender : function(ct, position){
46487 //console.log('row render');
46489 var t = new Roo.Template(
46490 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
46491 '<label for="{0}" style="{2}">{1}{4}</label>',
46492 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
46496 t.disableFormats = true;
46498 Roo.form.Layout.prototype.rowTpl = t;
46500 this.fieldTpl = this.rowTpl;
46502 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
46503 var labelWidth = 100;
46505 if ((this.labelAlign != 'top')) {
46506 if (typeof this.labelWidth == 'number') {
46507 labelWidth = this.labelWidth
46509 this.padWidth = 20 + labelWidth;
46513 Roo.form.Column.superclass.onRender.call(this, ct, position);
46515 this.el.setWidth(this.width);
46518 this.el.setHeight(this.height);
46523 renderField : function(f){
46524 f.fieldEl = this.fieldTpl.append(this.el, [
46525 f.id, f.fieldLabel,
46526 f.labelStyle||this.labelStyle||'',
46527 this.elementStyle||'',
46528 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
46529 f.itemCls||this.itemCls||'',
46530 f.width ? f.width + this.padWidth : 160 + this.padWidth
46537 * @class Roo.form.FieldSet
46538 * @extends Roo.form.Layout
46539 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
46541 * @param {Object} config Configuration options
46543 Roo.form.FieldSet = function(config){
46544 Roo.form.FieldSet.superclass.constructor.call(this, config);
46547 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
46549 * @cfg {String} legend
46550 * The text to display as the legend for the FieldSet (defaults to '')
46553 * @cfg {String/Object} autoCreate
46554 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
46558 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
46561 onRender : function(ct, position){
46562 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
46564 this.setLegend(this.legend);
46569 setLegend : function(text){
46571 this.el.child('legend').update(text);
46576 * Ext JS Library 1.1.1
46577 * Copyright(c) 2006-2007, Ext JS, LLC.
46579 * Originally Released Under LGPL - original licence link has changed is not relivant.
46582 * <script type="text/javascript">
46585 * @class Roo.form.VTypes
46586 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
46589 Roo.form.VTypes = function(){
46590 // closure these in so they are only created once.
46591 var alpha = /^[a-zA-Z_]+$/;
46592 var alphanum = /^[a-zA-Z0-9_]+$/;
46593 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
46594 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
46596 // All these messages and functions are configurable
46599 * The function used to validate email addresses
46600 * @param {String} value The email address
46602 'email' : function(v){
46603 return email.test(v);
46606 * The error text to display when the email validation function returns false
46609 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
46611 * The keystroke filter mask to be applied on email input
46614 'emailMask' : /[a-z0-9_\.\-@]/i,
46617 * The function used to validate URLs
46618 * @param {String} value The URL
46620 'url' : function(v){
46621 return url.test(v);
46624 * The error text to display when the url validation function returns false
46627 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
46630 * The function used to validate alpha values
46631 * @param {String} value The value
46633 'alpha' : function(v){
46634 return alpha.test(v);
46637 * The error text to display when the alpha validation function returns false
46640 'alphaText' : 'This field should only contain letters and _',
46642 * The keystroke filter mask to be applied on alpha input
46645 'alphaMask' : /[a-z_]/i,
46648 * The function used to validate alphanumeric values
46649 * @param {String} value The value
46651 'alphanum' : function(v){
46652 return alphanum.test(v);
46655 * The error text to display when the alphanumeric validation function returns false
46658 'alphanumText' : 'This field should only contain letters, numbers and _',
46660 * The keystroke filter mask to be applied on alphanumeric input
46663 'alphanumMask' : /[a-z0-9_]/i
46665 }();//<script type="text/javascript">
46668 * @class Roo.form.FCKeditor
46669 * @extends Roo.form.TextArea
46670 * Wrapper around the FCKEditor http://www.fckeditor.net
46672 * Creates a new FCKeditor
46673 * @param {Object} config Configuration options
46675 Roo.form.FCKeditor = function(config){
46676 Roo.form.FCKeditor.superclass.constructor.call(this, config);
46679 * @event editorinit
46680 * Fired when the editor is initialized - you can add extra handlers here..
46681 * @param {FCKeditor} this
46682 * @param {Object} the FCK object.
46689 Roo.form.FCKeditor.editors = { };
46690 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
46692 //defaultAutoCreate : {
46693 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
46697 * @cfg {Object} fck options - see fck manual for details.
46702 * @cfg {Object} fck toolbar set (Basic or Default)
46704 toolbarSet : 'Basic',
46706 * @cfg {Object} fck BasePath
46708 basePath : '/fckeditor/',
46716 onRender : function(ct, position)
46719 this.defaultAutoCreate = {
46721 style:"width:300px;height:60px;",
46722 autocomplete: "new-password"
46725 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
46728 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
46729 if(this.preventScrollbars){
46730 this.el.setStyle("overflow", "hidden");
46732 this.el.setHeight(this.growMin);
46735 //console.log('onrender' + this.getId() );
46736 Roo.form.FCKeditor.editors[this.getId()] = this;
46739 this.replaceTextarea() ;
46743 getEditor : function() {
46744 return this.fckEditor;
46747 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
46748 * @param {Mixed} value The value to set
46752 setValue : function(value)
46754 //console.log('setValue: ' + value);
46756 if(typeof(value) == 'undefined') { // not sure why this is happending...
46759 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46761 //if(!this.el || !this.getEditor()) {
46762 // this.value = value;
46763 //this.setValue.defer(100,this,[value]);
46767 if(!this.getEditor()) {
46771 this.getEditor().SetData(value);
46778 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
46779 * @return {Mixed} value The field value
46781 getValue : function()
46784 if (this.frame && this.frame.dom.style.display == 'none') {
46785 return Roo.form.FCKeditor.superclass.getValue.call(this);
46788 if(!this.el || !this.getEditor()) {
46790 // this.getValue.defer(100,this);
46795 var value=this.getEditor().GetData();
46796 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
46797 return Roo.form.FCKeditor.superclass.getValue.call(this);
46803 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
46804 * @return {Mixed} value The field value
46806 getRawValue : function()
46808 if (this.frame && this.frame.dom.style.display == 'none') {
46809 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46812 if(!this.el || !this.getEditor()) {
46813 //this.getRawValue.defer(100,this);
46820 var value=this.getEditor().GetData();
46821 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
46822 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
46826 setSize : function(w,h) {
46830 //if (this.frame && this.frame.dom.style.display == 'none') {
46831 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46834 //if(!this.el || !this.getEditor()) {
46835 // this.setSize.defer(100,this, [w,h]);
46841 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
46843 this.frame.dom.setAttribute('width', w);
46844 this.frame.dom.setAttribute('height', h);
46845 this.frame.setSize(w,h);
46849 toggleSourceEdit : function(value) {
46853 this.el.dom.style.display = value ? '' : 'none';
46854 this.frame.dom.style.display = value ? 'none' : '';
46859 focus: function(tag)
46861 if (this.frame.dom.style.display == 'none') {
46862 return Roo.form.FCKeditor.superclass.focus.call(this);
46864 if(!this.el || !this.getEditor()) {
46865 this.focus.defer(100,this, [tag]);
46872 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
46873 this.getEditor().Focus();
46875 if (!this.getEditor().Selection.GetSelection()) {
46876 this.focus.defer(100,this, [tag]);
46881 var r = this.getEditor().EditorDocument.createRange();
46882 r.setStart(tgs[0],0);
46883 r.setEnd(tgs[0],0);
46884 this.getEditor().Selection.GetSelection().removeAllRanges();
46885 this.getEditor().Selection.GetSelection().addRange(r);
46886 this.getEditor().Focus();
46893 replaceTextarea : function()
46895 if ( document.getElementById( this.getId() + '___Frame' ) )
46897 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
46899 // We must check the elements firstly using the Id and then the name.
46900 var oTextarea = document.getElementById( this.getId() );
46902 var colElementsByName = document.getElementsByName( this.getId() ) ;
46904 oTextarea.style.display = 'none' ;
46906 if ( oTextarea.tabIndex ) {
46907 this.TabIndex = oTextarea.tabIndex ;
46910 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
46911 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
46912 this.frame = Roo.get(this.getId() + '___Frame')
46915 _getConfigHtml : function()
46919 for ( var o in this.fckconfig ) {
46920 sConfig += sConfig.length > 0 ? '&' : '';
46921 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
46924 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
46928 _getIFrameHtml : function()
46930 var sFile = 'fckeditor.html' ;
46931 /* no idea what this is about..
46934 if ( (/fcksource=true/i).test( window.top.location.search ) )
46935 sFile = 'fckeditor.original.html' ;
46940 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
46941 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
46944 var html = '<iframe id="' + this.getId() +
46945 '___Frame" src="' + sLink +
46946 '" width="' + this.width +
46947 '" height="' + this.height + '"' +
46948 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
46949 ' frameborder="0" scrolling="no"></iframe>' ;
46954 _insertHtmlBefore : function( html, element )
46956 if ( element.insertAdjacentHTML ) {
46958 element.insertAdjacentHTML( 'beforeBegin', html ) ;
46960 var oRange = document.createRange() ;
46961 oRange.setStartBefore( element ) ;
46962 var oFragment = oRange.createContextualFragment( html );
46963 element.parentNode.insertBefore( oFragment, element ) ;
46976 //Roo.reg('fckeditor', Roo.form.FCKeditor);
46978 function FCKeditor_OnComplete(editorInstance){
46979 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
46980 f.fckEditor = editorInstance;
46981 //console.log("loaded");
46982 f.fireEvent('editorinit', f, editorInstance);
47002 //<script type="text/javascript">
47004 * @class Roo.form.GridField
47005 * @extends Roo.form.Field
47006 * Embed a grid (or editable grid into a form)
47009 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
47011 * xgrid.store = Roo.data.Store
47012 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
47013 * xgrid.store.reader = Roo.data.JsonReader
47017 * Creates a new GridField
47018 * @param {Object} config Configuration options
47020 Roo.form.GridField = function(config){
47021 Roo.form.GridField.superclass.constructor.call(this, config);
47025 Roo.extend(Roo.form.GridField, Roo.form.Field, {
47027 * @cfg {Number} width - used to restrict width of grid..
47031 * @cfg {Number} height - used to restrict height of grid..
47035 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
47041 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47042 * {tag: "input", type: "checkbox", autocomplete: "off"})
47044 // defaultAutoCreate : { tag: 'div' },
47045 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
47047 * @cfg {String} addTitle Text to include for adding a title.
47051 onResize : function(){
47052 Roo.form.Field.superclass.onResize.apply(this, arguments);
47055 initEvents : function(){
47056 // Roo.form.Checkbox.superclass.initEvents.call(this);
47057 // has no events...
47062 getResizeEl : function(){
47066 getPositionEl : function(){
47071 onRender : function(ct, position){
47073 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
47074 var style = this.style;
47077 Roo.form.GridField.superclass.onRender.call(this, ct, position);
47078 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
47079 this.viewEl = this.wrap.createChild({ tag: 'div' });
47081 this.viewEl.applyStyles(style);
47084 this.viewEl.setWidth(this.width);
47087 this.viewEl.setHeight(this.height);
47089 //if(this.inputValue !== undefined){
47090 //this.setValue(this.value);
47093 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
47096 this.grid.render();
47097 this.grid.getDataSource().on('remove', this.refreshValue, this);
47098 this.grid.getDataSource().on('update', this.refreshValue, this);
47099 this.grid.on('afteredit', this.refreshValue, this);
47105 * Sets the value of the item.
47106 * @param {String} either an object or a string..
47108 setValue : function(v){
47110 v = v || []; // empty set..
47111 // this does not seem smart - it really only affects memoryproxy grids..
47112 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
47113 var ds = this.grid.getDataSource();
47114 // assumes a json reader..
47116 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
47117 ds.loadData( data);
47119 // clear selection so it does not get stale.
47120 if (this.grid.sm) {
47121 this.grid.sm.clearSelections();
47124 Roo.form.GridField.superclass.setValue.call(this, v);
47125 this.refreshValue();
47126 // should load data in the grid really....
47130 refreshValue: function() {
47132 this.grid.getDataSource().each(function(r) {
47135 this.el.dom.value = Roo.encode(val);
47143 * Ext JS Library 1.1.1
47144 * Copyright(c) 2006-2007, Ext JS, LLC.
47146 * Originally Released Under LGPL - original licence link has changed is not relivant.
47149 * <script type="text/javascript">
47152 * @class Roo.form.DisplayField
47153 * @extends Roo.form.Field
47154 * A generic Field to display non-editable data.
47156 * Creates a new Display Field item.
47157 * @param {Object} config Configuration options
47159 Roo.form.DisplayField = function(config){
47160 Roo.form.DisplayField.superclass.constructor.call(this, config);
47164 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
47165 inputType: 'hidden',
47171 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47173 focusClass : undefined,
47175 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47177 fieldClass: 'x-form-field',
47180 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
47182 valueRenderer: undefined,
47186 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47187 * {tag: "input", type: "checkbox", autocomplete: "off"})
47190 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
47192 onResize : function(){
47193 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
47197 initEvents : function(){
47198 // Roo.form.Checkbox.superclass.initEvents.call(this);
47199 // has no events...
47204 getResizeEl : function(){
47208 getPositionEl : function(){
47213 onRender : function(ct, position){
47215 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
47216 //if(this.inputValue !== undefined){
47217 this.wrap = this.el.wrap();
47219 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
47221 if (this.bodyStyle) {
47222 this.viewEl.applyStyles(this.bodyStyle);
47224 //this.viewEl.setStyle('padding', '2px');
47226 this.setValue(this.value);
47231 initValue : Roo.emptyFn,
47236 onClick : function(){
47241 * Sets the checked state of the checkbox.
47242 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
47244 setValue : function(v){
47246 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
47247 // this might be called before we have a dom element..
47248 if (!this.viewEl) {
47251 this.viewEl.dom.innerHTML = html;
47252 Roo.form.DisplayField.superclass.setValue.call(this, v);
47262 * @class Roo.form.DayPicker
47263 * @extends Roo.form.Field
47264 * A Day picker show [M] [T] [W] ....
47266 * Creates a new Day Picker
47267 * @param {Object} config Configuration options
47269 Roo.form.DayPicker= function(config){
47270 Roo.form.DayPicker.superclass.constructor.call(this, config);
47274 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
47276 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
47278 focusClass : undefined,
47280 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
47282 fieldClass: "x-form-field",
47285 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
47286 * {tag: "input", type: "checkbox", autocomplete: "off"})
47288 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
47291 actionMode : 'viewEl',
47295 inputType : 'hidden',
47298 inputElement: false, // real input element?
47299 basedOn: false, // ????
47301 isFormField: true, // not sure where this is needed!!!!
47303 onResize : function(){
47304 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
47305 if(!this.boxLabel){
47306 this.el.alignTo(this.wrap, 'c-c');
47310 initEvents : function(){
47311 Roo.form.Checkbox.superclass.initEvents.call(this);
47312 this.el.on("click", this.onClick, this);
47313 this.el.on("change", this.onClick, this);
47317 getResizeEl : function(){
47321 getPositionEl : function(){
47327 onRender : function(ct, position){
47328 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
47330 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
47332 var r1 = '<table><tr>';
47333 var r2 = '<tr class="x-form-daypick-icons">';
47334 for (var i=0; i < 7; i++) {
47335 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
47336 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
47339 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
47340 viewEl.select('img').on('click', this.onClick, this);
47341 this.viewEl = viewEl;
47344 // this will not work on Chrome!!!
47345 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
47346 this.el.on('propertychange', this.setFromHidden, this); //ie
47354 initValue : Roo.emptyFn,
47357 * Returns the checked state of the checkbox.
47358 * @return {Boolean} True if checked, else false
47360 getValue : function(){
47361 return this.el.dom.value;
47366 onClick : function(e){
47367 //this.setChecked(!this.checked);
47368 Roo.get(e.target).toggleClass('x-menu-item-checked');
47369 this.refreshValue();
47370 //if(this.el.dom.checked != this.checked){
47371 // this.setValue(this.el.dom.checked);
47376 refreshValue : function()
47379 this.viewEl.select('img',true).each(function(e,i,n) {
47380 val += e.is(".x-menu-item-checked") ? String(n) : '';
47382 this.setValue(val, true);
47386 * Sets the checked state of the checkbox.
47387 * On is always based on a string comparison between inputValue and the param.
47388 * @param {Boolean/String} value - the value to set
47389 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
47391 setValue : function(v,suppressEvent){
47392 if (!this.el.dom) {
47395 var old = this.el.dom.value ;
47396 this.el.dom.value = v;
47397 if (suppressEvent) {
47401 // update display..
47402 this.viewEl.select('img',true).each(function(e,i,n) {
47404 var on = e.is(".x-menu-item-checked");
47405 var newv = v.indexOf(String(n)) > -1;
47407 e.toggleClass('x-menu-item-checked');
47413 this.fireEvent('change', this, v, old);
47418 // handle setting of hidden value by some other method!!?!?
47419 setFromHidden: function()
47424 //console.log("SET FROM HIDDEN");
47425 //alert('setFrom hidden');
47426 this.setValue(this.el.dom.value);
47429 onDestroy : function()
47432 Roo.get(this.viewEl).remove();
47435 Roo.form.DayPicker.superclass.onDestroy.call(this);
47439 * RooJS Library 1.1.1
47440 * Copyright(c) 2008-2011 Alan Knowles
47447 * @class Roo.form.ComboCheck
47448 * @extends Roo.form.ComboBox
47449 * A combobox for multiple select items.
47451 * FIXME - could do with a reset button..
47454 * Create a new ComboCheck
47455 * @param {Object} config Configuration options
47457 Roo.form.ComboCheck = function(config){
47458 Roo.form.ComboCheck.superclass.constructor.call(this, config);
47459 // should verify some data...
47461 // hiddenName = required..
47462 // displayField = required
47463 // valudField == required
47464 var req= [ 'hiddenName', 'displayField', 'valueField' ];
47466 Roo.each(req, function(e) {
47467 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
47468 throw "Roo.form.ComboCheck : missing value for: " + e;
47475 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
47480 selectedClass: 'x-menu-item-checked',
47483 onRender : function(ct, position){
47489 var cls = 'x-combo-list';
47492 this.tpl = new Roo.Template({
47493 html : '<div class="'+cls+'-item x-menu-check-item">' +
47494 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
47495 '<span>{' + this.displayField + '}</span>' +
47502 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
47503 this.view.singleSelect = false;
47504 this.view.multiSelect = true;
47505 this.view.toggleSelect = true;
47506 this.pageTb.add(new Roo.Toolbar.Fill(), {
47509 handler: function()
47516 onViewOver : function(e, t){
47522 onViewClick : function(doFocus,index){
47526 select: function () {
47527 //Roo.log("SELECT CALLED");
47530 selectByValue : function(xv, scrollIntoView){
47531 var ar = this.getValueArray();
47534 Roo.each(ar, function(v) {
47535 if(v === undefined || v === null){
47538 var r = this.findRecord(this.valueField, v);
47540 sels.push(this.store.indexOf(r))
47544 this.view.select(sels);
47550 onSelect : function(record, index){
47551 // Roo.log("onselect Called");
47552 // this is only called by the clear button now..
47553 this.view.clearSelections();
47554 this.setValue('[]');
47555 if (this.value != this.valueBefore) {
47556 this.fireEvent('change', this, this.value, this.valueBefore);
47557 this.valueBefore = this.value;
47560 getValueArray : function()
47565 //Roo.log(this.value);
47566 if (typeof(this.value) == 'undefined') {
47569 var ar = Roo.decode(this.value);
47570 return ar instanceof Array ? ar : []; //?? valid?
47573 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
47578 expand : function ()
47581 Roo.form.ComboCheck.superclass.expand.call(this);
47582 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
47583 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
47588 collapse : function(){
47589 Roo.form.ComboCheck.superclass.collapse.call(this);
47590 var sl = this.view.getSelectedIndexes();
47591 var st = this.store;
47595 Roo.each(sl, function(i) {
47597 nv.push(r.get(this.valueField));
47599 this.setValue(Roo.encode(nv));
47600 if (this.value != this.valueBefore) {
47602 this.fireEvent('change', this, this.value, this.valueBefore);
47603 this.valueBefore = this.value;
47608 setValue : function(v){
47612 var vals = this.getValueArray();
47614 Roo.each(vals, function(k) {
47615 var r = this.findRecord(this.valueField, k);
47617 tv.push(r.data[this.displayField]);
47618 }else if(this.valueNotFoundText !== undefined){
47619 tv.push( this.valueNotFoundText );
47624 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
47625 this.hiddenField.value = v;
47631 * Ext JS Library 1.1.1
47632 * Copyright(c) 2006-2007, Ext JS, LLC.
47634 * Originally Released Under LGPL - original licence link has changed is not relivant.
47637 * <script type="text/javascript">
47641 * @class Roo.form.Signature
47642 * @extends Roo.form.Field
47646 * @param {Object} config Configuration options
47649 Roo.form.Signature = function(config){
47650 Roo.form.Signature.superclass.constructor.call(this, config);
47652 this.addEvents({// not in used??
47655 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
47656 * @param {Roo.form.Signature} combo This combo box
47661 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
47662 * @param {Roo.form.ComboBox} combo This combo box
47663 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
47669 Roo.extend(Roo.form.Signature, Roo.form.Field, {
47671 * @cfg {Object} labels Label to use when rendering a form.
47675 * confirm : "Confirm"
47680 confirm : "Confirm"
47683 * @cfg {Number} width The signature panel width (defaults to 300)
47687 * @cfg {Number} height The signature panel height (defaults to 100)
47691 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
47693 allowBlank : false,
47696 // {Object} signPanel The signature SVG panel element (defaults to {})
47698 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
47699 isMouseDown : false,
47700 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
47701 isConfirmed : false,
47702 // {String} signatureTmp SVG mapping string (defaults to empty string)
47706 defaultAutoCreate : { // modified by initCompnoent..
47712 onRender : function(ct, position){
47714 Roo.form.Signature.superclass.onRender.call(this, ct, position);
47716 this.wrap = this.el.wrap({
47717 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
47720 this.createToolbar(this);
47721 this.signPanel = this.wrap.createChild({
47723 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
47727 this.svgID = Roo.id();
47728 this.svgEl = this.signPanel.createChild({
47729 xmlns : 'http://www.w3.org/2000/svg',
47731 id : this.svgID + "-svg",
47733 height: this.height,
47734 viewBox: '0 0 '+this.width+' '+this.height,
47738 id: this.svgID + "-svg-r",
47740 height: this.height,
47745 id: this.svgID + "-svg-l",
47747 y1: (this.height*0.8), // start set the line in 80% of height
47748 x2: this.width, // end
47749 y2: (this.height*0.8), // end set the line in 80% of height
47751 'stroke-width': "1",
47752 'stroke-dasharray': "3",
47753 'shape-rendering': "crispEdges",
47754 'pointer-events': "none"
47758 id: this.svgID + "-svg-p",
47760 'stroke-width': "3",
47762 'pointer-events': 'none'
47767 this.svgBox = this.svgEl.dom.getScreenCTM();
47769 createSVG : function(){
47770 var svg = this.signPanel;
47771 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
47774 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
47775 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
47776 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
47777 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
47778 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
47779 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
47780 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
47783 isTouchEvent : function(e){
47784 return e.type.match(/^touch/);
47786 getCoords : function (e) {
47787 var pt = this.svgEl.dom.createSVGPoint();
47790 if (this.isTouchEvent(e)) {
47791 pt.x = e.targetTouches[0].clientX
47792 pt.y = e.targetTouches[0].clientY;
47794 var a = this.svgEl.dom.getScreenCTM();
47795 var b = a.inverse();
47796 var mx = pt.matrixTransform(b);
47797 return mx.x + ',' + mx.y;
47799 //mouse event headler
47800 down : function (e) {
47801 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
47802 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
47804 this.isMouseDown = true;
47806 e.preventDefault();
47808 move : function (e) {
47809 if (this.isMouseDown) {
47810 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
47811 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
47814 e.preventDefault();
47816 up : function (e) {
47817 this.isMouseDown = false;
47818 var sp = this.signatureTmp.split(' ');
47821 if(!sp[sp.length-2].match(/^L/)){
47825 this.signatureTmp = sp.join(" ");
47828 if(this.getValue() != this.signatureTmp){
47829 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47830 this.isConfirmed = false;
47832 e.preventDefault();
47836 * Protected method that will not generally be called directly. It
47837 * is called when the editor creates its toolbar. Override this method if you need to
47838 * add custom toolbar buttons.
47839 * @param {HtmlEditor} editor
47841 createToolbar : function(editor){
47842 function btn(id, toggle, handler){
47843 var xid = fid + '-'+ id ;
47847 cls : 'x-btn-icon x-edit-'+id,
47848 enableToggle:toggle !== false,
47849 scope: editor, // was editor...
47850 handler:handler||editor.relayBtnCmd,
47851 clickEvent:'mousedown',
47852 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47858 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47862 cls : ' x-signature-btn x-signature-'+id,
47863 scope: editor, // was editor...
47864 handler: this.reset,
47865 clickEvent:'mousedown',
47866 text: this.labels.clear
47873 cls : ' x-signature-btn x-signature-'+id,
47874 scope: editor, // was editor...
47875 handler: this.confirmHandler,
47876 clickEvent:'mousedown',
47877 text: this.labels.confirm
47884 * when user is clicked confirm then show this image.....
47886 * @return {String} Image Data URI
47888 getImageDataURI : function(){
47889 var svg = this.svgEl.dom.parentNode.innerHTML;
47890 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
47895 * @return {Boolean} this.isConfirmed
47897 getConfirmed : function(){
47898 return this.isConfirmed;
47902 * @return {Number} this.width
47904 getWidth : function(){
47909 * @return {Number} this.height
47911 getHeight : function(){
47912 return this.height;
47915 getSignature : function(){
47916 return this.signatureTmp;
47919 reset : function(){
47920 this.signatureTmp = '';
47921 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47922 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
47923 this.isConfirmed = false;
47924 Roo.form.Signature.superclass.reset.call(this);
47926 setSignature : function(s){
47927 this.signatureTmp = s;
47928 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
47929 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
47931 this.isConfirmed = false;
47932 Roo.form.Signature.superclass.reset.call(this);
47935 // Roo.log(this.signPanel.dom.contentWindow.up())
47938 setConfirmed : function(){
47942 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
47945 confirmHandler : function(){
47946 if(!this.getSignature()){
47950 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
47951 this.setValue(this.getSignature());
47952 this.isConfirmed = true;
47954 this.fireEvent('confirm', this);
47957 // Subclasses should provide the validation implementation by overriding this
47958 validateValue : function(value){
47959 if(this.allowBlank){
47963 if(this.isConfirmed){
47970 * Ext JS Library 1.1.1
47971 * Copyright(c) 2006-2007, Ext JS, LLC.
47973 * Originally Released Under LGPL - original licence link has changed is not relivant.
47976 * <script type="text/javascript">
47981 * @class Roo.form.ComboBox
47982 * @extends Roo.form.TriggerField
47983 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
47985 * Create a new ComboBox.
47986 * @param {Object} config Configuration options
47988 Roo.form.Select = function(config){
47989 Roo.form.Select.superclass.constructor.call(this, config);
47993 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
47995 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
47998 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
47999 * rendering into an Roo.Editor, defaults to false)
48002 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
48003 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
48006 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
48009 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
48010 * the dropdown list (defaults to undefined, with no header element)
48014 * @cfg {String/Roo.Template} tpl The template to use to render the output
48018 defaultAutoCreate : {tag: "select" },
48020 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
48022 listWidth: undefined,
48024 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
48025 * mode = 'remote' or 'text' if mode = 'local')
48027 displayField: undefined,
48029 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
48030 * mode = 'remote' or 'value' if mode = 'local').
48031 * Note: use of a valueField requires the user make a selection
48032 * in order for a value to be mapped.
48034 valueField: undefined,
48038 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
48039 * field's data value (defaults to the underlying DOM element's name)
48041 hiddenName: undefined,
48043 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
48047 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
48049 selectedClass: 'x-combo-selected',
48051 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
48052 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
48053 * which displays a downward arrow icon).
48055 triggerClass : 'x-form-arrow-trigger',
48057 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
48061 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
48062 * anchor positions (defaults to 'tl-bl')
48064 listAlign: 'tl-bl?',
48066 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
48070 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
48071 * query specified by the allQuery config option (defaults to 'query')
48073 triggerAction: 'query',
48075 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
48076 * (defaults to 4, does not apply if editable = false)
48080 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
48081 * delay (typeAheadDelay) if it matches a known value (defaults to false)
48085 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
48086 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
48090 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
48091 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
48095 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
48096 * when editable = true (defaults to false)
48098 selectOnFocus:false,
48100 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
48102 queryParam: 'query',
48104 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
48105 * when mode = 'remote' (defaults to 'Loading...')
48107 loadingText: 'Loading...',
48109 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
48113 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
48117 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
48118 * traditional select (defaults to true)
48122 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
48126 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
48130 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
48131 * listWidth has a higher value)
48135 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
48136 * allow the user to set arbitrary text into the field (defaults to false)
48138 forceSelection:false,
48140 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
48141 * if typeAhead = true (defaults to 250)
48143 typeAheadDelay : 250,
48145 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
48146 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
48148 valueNotFoundText : undefined,
48151 * @cfg {String} defaultValue The value displayed after loading the store.
48156 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
48158 blockFocus : false,
48161 * @cfg {Boolean} disableClear Disable showing of clear button.
48163 disableClear : false,
48165 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
48167 alwaysQuery : false,
48173 // element that contains real text value.. (when hidden is used..)
48176 onRender : function(ct, position){
48177 Roo.form.Field.prototype.onRender.call(this, ct, position);
48180 this.store.on('beforeload', this.onBeforeLoad, this);
48181 this.store.on('load', this.onLoad, this);
48182 this.store.on('loadexception', this.onLoadException, this);
48183 this.store.load({});
48191 initEvents : function(){
48192 //Roo.form.ComboBox.superclass.initEvents.call(this);
48196 onDestroy : function(){
48199 this.store.un('beforeload', this.onBeforeLoad, this);
48200 this.store.un('load', this.onLoad, this);
48201 this.store.un('loadexception', this.onLoadException, this);
48203 //Roo.form.ComboBox.superclass.onDestroy.call(this);
48207 fireKey : function(e){
48208 if(e.isNavKeyPress() && !this.list.isVisible()){
48209 this.fireEvent("specialkey", this, e);
48214 onResize: function(w, h){
48222 * Allow or prevent the user from directly editing the field text. If false is passed,
48223 * the user will only be able to select from the items defined in the dropdown list. This method
48224 * is the runtime equivalent of setting the 'editable' config option at config time.
48225 * @param {Boolean} value True to allow the user to directly edit the field text
48227 setEditable : function(value){
48232 onBeforeLoad : function(){
48234 Roo.log("Select before load");
48237 this.innerList.update(this.loadingText ?
48238 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
48239 //this.restrictHeight();
48240 this.selectedIndex = -1;
48244 onLoad : function(){
48247 var dom = this.el.dom;
48248 dom.innerHTML = '';
48249 var od = dom.ownerDocument;
48251 if (this.emptyText) {
48252 var op = od.createElement('option');
48253 op.setAttribute('value', '');
48254 op.innerHTML = String.format('{0}', this.emptyText);
48255 dom.appendChild(op);
48257 if(this.store.getCount() > 0){
48259 var vf = this.valueField;
48260 var df = this.displayField;
48261 this.store.data.each(function(r) {
48262 // which colmsn to use... testing - cdoe / title..
48263 var op = od.createElement('option');
48264 op.setAttribute('value', r.data[vf]);
48265 op.innerHTML = String.format('{0}', r.data[df]);
48266 dom.appendChild(op);
48268 if (typeof(this.defaultValue != 'undefined')) {
48269 this.setValue(this.defaultValue);
48274 //this.onEmptyResults();
48279 onLoadException : function()
48281 dom.innerHTML = '';
48283 Roo.log("Select on load exception");
48287 Roo.log(this.store.reader.jsonData);
48288 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
48289 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
48295 onTypeAhead : function(){
48300 onSelect : function(record, index){
48301 Roo.log('on select?');
48303 if(this.fireEvent('beforeselect', this, record, index) !== false){
48304 this.setFromData(index > -1 ? record.data : false);
48306 this.fireEvent('select', this, record, index);
48311 * Returns the currently selected field value or empty string if no value is set.
48312 * @return {String} value The selected value
48314 getValue : function(){
48315 var dom = this.el.dom;
48316 this.value = dom.options[dom.selectedIndex].value;
48322 * Clears any text/value currently set in the field
48324 clearValue : function(){
48326 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
48331 * Sets the specified value into the field. If the value finds a match, the corresponding record text
48332 * will be displayed in the field. If the value does not match the data value of an existing item,
48333 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
48334 * Otherwise the field will be blank (although the value will still be set).
48335 * @param {String} value The value to match
48337 setValue : function(v){
48338 var d = this.el.dom;
48339 for (var i =0; i < d.options.length;i++) {
48340 if (v == d.options[i].value) {
48341 d.selectedIndex = i;
48349 * @property {Object} the last set data for the element
48354 * Sets the value of the field based on a object which is related to the record format for the store.
48355 * @param {Object} value the value to set as. or false on reset?
48357 setFromData : function(o){
48358 Roo.log('setfrom data?');
48364 reset : function(){
48368 findRecord : function(prop, value){
48373 if(this.store.getCount() > 0){
48374 this.store.each(function(r){
48375 if(r.data[prop] == value){
48385 getName: function()
48387 // returns hidden if it's set..
48388 if (!this.rendered) {return ''};
48389 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
48397 onEmptyResults : function(){
48398 Roo.log('empty results');
48403 * Returns true if the dropdown list is expanded, else false.
48405 isExpanded : function(){
48410 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
48411 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48412 * @param {String} value The data value of the item to select
48413 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48414 * selected item if it is not currently in view (defaults to true)
48415 * @return {Boolean} True if the value matched an item in the list, else false
48417 selectByValue : function(v, scrollIntoView){
48418 Roo.log('select By Value');
48421 if(v !== undefined && v !== null){
48422 var r = this.findRecord(this.valueField || this.displayField, v);
48424 this.select(this.store.indexOf(r), scrollIntoView);
48432 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
48433 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
48434 * @param {Number} index The zero-based index of the list item to select
48435 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
48436 * selected item if it is not currently in view (defaults to true)
48438 select : function(index, scrollIntoView){
48439 Roo.log('select ');
48442 this.selectedIndex = index;
48443 this.view.select(index);
48444 if(scrollIntoView !== false){
48445 var el = this.view.getNode(index);
48447 this.innerList.scrollChildIntoView(el, false);
48455 validateBlur : function(){
48462 initQuery : function(){
48463 this.doQuery(this.getRawValue());
48467 doForce : function(){
48468 if(this.el.dom.value.length > 0){
48469 this.el.dom.value =
48470 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
48476 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
48477 * query allowing the query action to be canceled if needed.
48478 * @param {String} query The SQL query to execute
48479 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
48480 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
48481 * saved in the current store (defaults to false)
48483 doQuery : function(q, forceAll){
48485 Roo.log('doQuery?');
48486 if(q === undefined || q === null){
48491 forceAll: forceAll,
48495 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
48499 forceAll = qe.forceAll;
48500 if(forceAll === true || (q.length >= this.minChars)){
48501 if(this.lastQuery != q || this.alwaysQuery){
48502 this.lastQuery = q;
48503 if(this.mode == 'local'){
48504 this.selectedIndex = -1;
48506 this.store.clearFilter();
48508 this.store.filter(this.displayField, q);
48512 this.store.baseParams[this.queryParam] = q;
48514 params: this.getParams(q)
48519 this.selectedIndex = -1;
48526 getParams : function(q){
48528 //p[this.queryParam] = q;
48531 p.limit = this.pageSize;
48537 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
48539 collapse : function(){
48544 collapseIf : function(e){
48549 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
48551 expand : function(){
48559 * @cfg {Boolean} grow
48563 * @cfg {Number} growMin
48567 * @cfg {Number} growMax
48575 setWidth : function()
48579 getResizeEl : function(){
48582 });//<script type="text/javasscript">
48586 * @class Roo.DDView
48587 * A DnD enabled version of Roo.View.
48588 * @param {Element/String} container The Element in which to create the View.
48589 * @param {String} tpl The template string used to create the markup for each element of the View
48590 * @param {Object} config The configuration properties. These include all the config options of
48591 * {@link Roo.View} plus some specific to this class.<br>
48593 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
48594 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
48596 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
48597 .x-view-drag-insert-above {
48598 border-top:1px dotted #3366cc;
48600 .x-view-drag-insert-below {
48601 border-bottom:1px dotted #3366cc;
48607 Roo.DDView = function(container, tpl, config) {
48608 Roo.DDView.superclass.constructor.apply(this, arguments);
48609 this.getEl().setStyle("outline", "0px none");
48610 this.getEl().unselectable();
48611 if (this.dragGroup) {
48612 this.setDraggable(this.dragGroup.split(","));
48614 if (this.dropGroup) {
48615 this.setDroppable(this.dropGroup.split(","));
48617 if (this.deletable) {
48618 this.setDeletable();
48620 this.isDirtyFlag = false;
48626 Roo.extend(Roo.DDView, Roo.View, {
48627 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
48628 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
48629 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
48630 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
48634 reset: Roo.emptyFn,
48636 clearInvalid: Roo.form.Field.prototype.clearInvalid,
48638 validate: function() {
48642 destroy: function() {
48643 this.purgeListeners();
48644 this.getEl.removeAllListeners();
48645 this.getEl().remove();
48646 if (this.dragZone) {
48647 if (this.dragZone.destroy) {
48648 this.dragZone.destroy();
48651 if (this.dropZone) {
48652 if (this.dropZone.destroy) {
48653 this.dropZone.destroy();
48658 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
48659 getName: function() {
48663 /** Loads the View from a JSON string representing the Records to put into the Store. */
48664 setValue: function(v) {
48666 throw "DDView.setValue(). DDView must be constructed with a valid Store";
48669 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
48670 this.store.proxy = new Roo.data.MemoryProxy(data);
48674 /** @return {String} a parenthesised list of the ids of the Records in the View. */
48675 getValue: function() {
48677 this.store.each(function(rec) {
48678 result += rec.id + ',';
48680 return result.substr(0, result.length - 1) + ')';
48683 getIds: function() {
48684 var i = 0, result = new Array(this.store.getCount());
48685 this.store.each(function(rec) {
48686 result[i++] = rec.id;
48691 isDirty: function() {
48692 return this.isDirtyFlag;
48696 * Part of the Roo.dd.DropZone interface. If no target node is found, the
48697 * whole Element becomes the target, and this causes the drop gesture to append.
48699 getTargetFromEvent : function(e) {
48700 var target = e.getTarget();
48701 while ((target !== null) && (target.parentNode != this.el.dom)) {
48702 target = target.parentNode;
48705 target = this.el.dom.lastChild || this.el.dom;
48711 * Create the drag data which consists of an object which has the property "ddel" as
48712 * the drag proxy element.
48714 getDragData : function(e) {
48715 var target = this.findItemFromChild(e.getTarget());
48717 this.handleSelection(e);
48718 var selNodes = this.getSelectedNodes();
48721 copy: this.copy || (this.allowCopy && e.ctrlKey),
48725 var selectedIndices = this.getSelectedIndexes();
48726 for (var i = 0; i < selectedIndices.length; i++) {
48727 dragData.records.push(this.store.getAt(selectedIndices[i]));
48729 if (selNodes.length == 1) {
48730 dragData.ddel = target.cloneNode(true); // the div element
48732 var div = document.createElement('div'); // create the multi element drag "ghost"
48733 div.className = 'multi-proxy';
48734 for (var i = 0, len = selNodes.length; i < len; i++) {
48735 div.appendChild(selNodes[i].cloneNode(true));
48737 dragData.ddel = div;
48739 //console.log(dragData)
48740 //console.log(dragData.ddel.innerHTML)
48743 //console.log('nodragData')
48747 /** Specify to which ddGroup items in this DDView may be dragged. */
48748 setDraggable: function(ddGroup) {
48749 if (ddGroup instanceof Array) {
48750 Roo.each(ddGroup, this.setDraggable, this);
48753 if (this.dragZone) {
48754 this.dragZone.addToGroup(ddGroup);
48756 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
48757 containerScroll: true,
48761 // Draggability implies selection. DragZone's mousedown selects the element.
48762 if (!this.multiSelect) { this.singleSelect = true; }
48764 // Wire the DragZone's handlers up to methods in *this*
48765 this.dragZone.getDragData = this.getDragData.createDelegate(this);
48769 /** Specify from which ddGroup this DDView accepts drops. */
48770 setDroppable: function(ddGroup) {
48771 if (ddGroup instanceof Array) {
48772 Roo.each(ddGroup, this.setDroppable, this);
48775 if (this.dropZone) {
48776 this.dropZone.addToGroup(ddGroup);
48778 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
48779 containerScroll: true,
48783 // Wire the DropZone's handlers up to methods in *this*
48784 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
48785 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
48786 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
48787 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
48788 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
48792 /** Decide whether to drop above or below a View node. */
48793 getDropPoint : function(e, n, dd){
48794 if (n == this.el.dom) { return "above"; }
48795 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
48796 var c = t + (b - t) / 2;
48797 var y = Roo.lib.Event.getPageY(e);
48805 onNodeEnter : function(n, dd, e, data){
48809 onNodeOver : function(n, dd, e, data){
48810 var pt = this.getDropPoint(e, n, dd);
48811 // set the insert point style on the target node
48812 var dragElClass = this.dropNotAllowed;
48815 if (pt == "above"){
48816 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
48817 targetElClass = "x-view-drag-insert-above";
48819 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
48820 targetElClass = "x-view-drag-insert-below";
48822 if (this.lastInsertClass != targetElClass){
48823 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
48824 this.lastInsertClass = targetElClass;
48827 return dragElClass;
48830 onNodeOut : function(n, dd, e, data){
48831 this.removeDropIndicators(n);
48834 onNodeDrop : function(n, dd, e, data){
48835 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
48838 var pt = this.getDropPoint(e, n, dd);
48839 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
48840 if (pt == "below") { insertAt++; }
48841 for (var i = 0; i < data.records.length; i++) {
48842 var r = data.records[i];
48843 var dup = this.store.getById(r.id);
48844 if (dup && (dd != this.dragZone)) {
48845 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
48848 this.store.insert(insertAt++, r.copy());
48850 data.source.isDirtyFlag = true;
48852 this.store.insert(insertAt++, r);
48854 this.isDirtyFlag = true;
48857 this.dragZone.cachedTarget = null;
48861 removeDropIndicators : function(n){
48863 Roo.fly(n).removeClass([
48864 "x-view-drag-insert-above",
48865 "x-view-drag-insert-below"]);
48866 this.lastInsertClass = "_noclass";
48871 * Utility method. Add a delete option to the DDView's context menu.
48872 * @param {String} imageUrl The URL of the "delete" icon image.
48874 setDeletable: function(imageUrl) {
48875 if (!this.singleSelect && !this.multiSelect) {
48876 this.singleSelect = true;
48878 var c = this.getContextMenu();
48879 this.contextMenu.on("itemclick", function(item) {
48882 this.remove(this.getSelectedIndexes());
48886 this.contextMenu.add({
48893 /** Return the context menu for this DDView. */
48894 getContextMenu: function() {
48895 if (!this.contextMenu) {
48896 // Create the View's context menu
48897 this.contextMenu = new Roo.menu.Menu({
48898 id: this.id + "-contextmenu"
48900 this.el.on("contextmenu", this.showContextMenu, this);
48902 return this.contextMenu;
48905 disableContextMenu: function() {
48906 if (this.contextMenu) {
48907 this.el.un("contextmenu", this.showContextMenu, this);
48911 showContextMenu: function(e, item) {
48912 item = this.findItemFromChild(e.getTarget());
48915 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
48916 this.contextMenu.showAt(e.getXY());
48921 * Remove {@link Roo.data.Record}s at the specified indices.
48922 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
48924 remove: function(selectedIndices) {
48925 selectedIndices = [].concat(selectedIndices);
48926 for (var i = 0; i < selectedIndices.length; i++) {
48927 var rec = this.store.getAt(selectedIndices[i]);
48928 this.store.remove(rec);
48933 * Double click fires the event, but also, if this is draggable, and there is only one other
48934 * related DropZone, it transfers the selected node.
48936 onDblClick : function(e){
48937 var item = this.findItemFromChild(e.getTarget());
48939 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
48942 if (this.dragGroup) {
48943 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
48944 while (targets.indexOf(this.dropZone) > -1) {
48945 targets.remove(this.dropZone);
48947 if (targets.length == 1) {
48948 this.dragZone.cachedTarget = null;
48949 var el = Roo.get(targets[0].getEl());
48950 var box = el.getBox(true);
48951 targets[0].onNodeDrop(el.dom, {
48953 xy: [box.x, box.y + box.height - 1]
48954 }, null, this.getDragData(e));
48960 handleSelection: function(e) {
48961 this.dragZone.cachedTarget = null;
48962 var item = this.findItemFromChild(e.getTarget());
48964 this.clearSelections(true);
48967 if (item && (this.multiSelect || this.singleSelect)){
48968 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
48969 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
48970 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
48971 this.unselect(item);
48973 this.select(item, this.multiSelect && e.ctrlKey);
48974 this.lastSelection = item;
48979 onItemClick : function(item, index, e){
48980 if(this.fireEvent("beforeclick", this, index, item, e) === false){
48986 unselect : function(nodeInfo, suppressEvent){
48987 var node = this.getNode(nodeInfo);
48988 if(node && this.isSelected(node)){
48989 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
48990 Roo.fly(node).removeClass(this.selectedClass);
48991 this.selections.remove(node);
48992 if(!suppressEvent){
48993 this.fireEvent("selectionchange", this, this.selections);
49001 * Ext JS Library 1.1.1
49002 * Copyright(c) 2006-2007, Ext JS, LLC.
49004 * Originally Released Under LGPL - original licence link has changed is not relivant.
49007 * <script type="text/javascript">
49011 * @class Roo.LayoutManager
49012 * @extends Roo.util.Observable
49013 * Base class for layout managers.
49015 Roo.LayoutManager = function(container, config){
49016 Roo.LayoutManager.superclass.constructor.call(this);
49017 this.el = Roo.get(container);
49018 // ie scrollbar fix
49019 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
49020 document.body.scroll = "no";
49021 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
49022 this.el.position('relative');
49024 this.id = this.el.id;
49025 this.el.addClass("x-layout-container");
49026 /** false to disable window resize monitoring @type Boolean */
49027 this.monitorWindowResize = true;
49032 * Fires when a layout is performed.
49033 * @param {Roo.LayoutManager} this
49037 * @event regionresized
49038 * Fires when the user resizes a region.
49039 * @param {Roo.LayoutRegion} region The resized region
49040 * @param {Number} newSize The new size (width for east/west, height for north/south)
49042 "regionresized" : true,
49044 * @event regioncollapsed
49045 * Fires when a region is collapsed.
49046 * @param {Roo.LayoutRegion} region The collapsed region
49048 "regioncollapsed" : true,
49050 * @event regionexpanded
49051 * Fires when a region is expanded.
49052 * @param {Roo.LayoutRegion} region The expanded region
49054 "regionexpanded" : true
49056 this.updating = false;
49057 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
49060 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
49062 * Returns true if this layout is currently being updated
49063 * @return {Boolean}
49065 isUpdating : function(){
49066 return this.updating;
49070 * Suspend the LayoutManager from doing auto-layouts while
49071 * making multiple add or remove calls
49073 beginUpdate : function(){
49074 this.updating = true;
49078 * Restore auto-layouts and optionally disable the manager from performing a layout
49079 * @param {Boolean} noLayout true to disable a layout update
49081 endUpdate : function(noLayout){
49082 this.updating = false;
49088 layout: function(){
49092 onRegionResized : function(region, newSize){
49093 this.fireEvent("regionresized", region, newSize);
49097 onRegionCollapsed : function(region){
49098 this.fireEvent("regioncollapsed", region);
49101 onRegionExpanded : function(region){
49102 this.fireEvent("regionexpanded", region);
49106 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
49107 * performs box-model adjustments.
49108 * @return {Object} The size as an object {width: (the width), height: (the height)}
49110 getViewSize : function(){
49112 if(this.el.dom != document.body){
49113 size = this.el.getSize();
49115 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
49117 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
49118 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
49123 * Returns the Element this layout is bound to.
49124 * @return {Roo.Element}
49126 getEl : function(){
49131 * Returns the specified region.
49132 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
49133 * @return {Roo.LayoutRegion}
49135 getRegion : function(target){
49136 return this.regions[target.toLowerCase()];
49139 onWindowResize : function(){
49140 if(this.monitorWindowResize){
49146 * Ext JS Library 1.1.1
49147 * Copyright(c) 2006-2007, Ext JS, LLC.
49149 * Originally Released Under LGPL - original licence link has changed is not relivant.
49152 * <script type="text/javascript">
49155 * @class Roo.BorderLayout
49156 * @extends Roo.LayoutManager
49157 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
49158 * please see: <br><br>
49159 * <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>
49160 * <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>
49163 var layout = new Roo.BorderLayout(document.body, {
49197 preferredTabWidth: 150
49202 var CP = Roo.ContentPanel;
49204 layout.beginUpdate();
49205 layout.add("north", new CP("north", "North"));
49206 layout.add("south", new CP("south", {title: "South", closable: true}));
49207 layout.add("west", new CP("west", {title: "West"}));
49208 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
49209 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
49210 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
49211 layout.getRegion("center").showPanel("center1");
49212 layout.endUpdate();
49215 <b>The container the layout is rendered into can be either the body element or any other element.
49216 If it is not the body element, the container needs to either be an absolute positioned element,
49217 or you will need to add "position:relative" to the css of the container. You will also need to specify
49218 the container size if it is not the body element.</b>
49221 * Create a new BorderLayout
49222 * @param {String/HTMLElement/Element} container The container this layout is bound to
49223 * @param {Object} config Configuration options
49225 Roo.BorderLayout = function(container, config){
49226 config = config || {};
49227 Roo.BorderLayout.superclass.constructor.call(this, container, config);
49228 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
49229 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
49230 var target = this.factory.validRegions[i];
49231 if(config[target]){
49232 this.addRegion(target, config[target]);
49237 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
49239 * Creates and adds a new region if it doesn't already exist.
49240 * @param {String} target The target region key (north, south, east, west or center).
49241 * @param {Object} config The regions config object
49242 * @return {BorderLayoutRegion} The new region
49244 addRegion : function(target, config){
49245 if(!this.regions[target]){
49246 var r = this.factory.create(target, this, config);
49247 this.bindRegion(target, r);
49249 return this.regions[target];
49253 bindRegion : function(name, r){
49254 this.regions[name] = r;
49255 r.on("visibilitychange", this.layout, this);
49256 r.on("paneladded", this.layout, this);
49257 r.on("panelremoved", this.layout, this);
49258 r.on("invalidated", this.layout, this);
49259 r.on("resized", this.onRegionResized, this);
49260 r.on("collapsed", this.onRegionCollapsed, this);
49261 r.on("expanded", this.onRegionExpanded, this);
49265 * Performs a layout update.
49267 layout : function(){
49268 if(this.updating) return;
49269 var size = this.getViewSize();
49270 var w = size.width;
49271 var h = size.height;
49276 //var x = 0, y = 0;
49278 var rs = this.regions;
49279 var north = rs["north"];
49280 var south = rs["south"];
49281 var west = rs["west"];
49282 var east = rs["east"];
49283 var center = rs["center"];
49284 //if(this.hideOnLayout){ // not supported anymore
49285 //c.el.setStyle("display", "none");
49287 if(north && north.isVisible()){
49288 var b = north.getBox();
49289 var m = north.getMargins();
49290 b.width = w - (m.left+m.right);
49293 centerY = b.height + b.y + m.bottom;
49294 centerH -= centerY;
49295 north.updateBox(this.safeBox(b));
49297 if(south && south.isVisible()){
49298 var b = south.getBox();
49299 var m = south.getMargins();
49300 b.width = w - (m.left+m.right);
49302 var totalHeight = (b.height + m.top + m.bottom);
49303 b.y = h - totalHeight + m.top;
49304 centerH -= totalHeight;
49305 south.updateBox(this.safeBox(b));
49307 if(west && west.isVisible()){
49308 var b = west.getBox();
49309 var m = west.getMargins();
49310 b.height = centerH - (m.top+m.bottom);
49312 b.y = centerY + m.top;
49313 var totalWidth = (b.width + m.left + m.right);
49314 centerX += totalWidth;
49315 centerW -= totalWidth;
49316 west.updateBox(this.safeBox(b));
49318 if(east && east.isVisible()){
49319 var b = east.getBox();
49320 var m = east.getMargins();
49321 b.height = centerH - (m.top+m.bottom);
49322 var totalWidth = (b.width + m.left + m.right);
49323 b.x = w - totalWidth + m.left;
49324 b.y = centerY + m.top;
49325 centerW -= totalWidth;
49326 east.updateBox(this.safeBox(b));
49329 var m = center.getMargins();
49331 x: centerX + m.left,
49332 y: centerY + m.top,
49333 width: centerW - (m.left+m.right),
49334 height: centerH - (m.top+m.bottom)
49336 //if(this.hideOnLayout){
49337 //center.el.setStyle("display", "block");
49339 center.updateBox(this.safeBox(centerBox));
49342 this.fireEvent("layout", this);
49346 safeBox : function(box){
49347 box.width = Math.max(0, box.width);
49348 box.height = Math.max(0, box.height);
49353 * Adds a ContentPanel (or subclass) to this layout.
49354 * @param {String} target The target region key (north, south, east, west or center).
49355 * @param {Roo.ContentPanel} panel The panel to add
49356 * @return {Roo.ContentPanel} The added panel
49358 add : function(target, panel){
49360 target = target.toLowerCase();
49361 return this.regions[target].add(panel);
49365 * Remove a ContentPanel (or subclass) to this layout.
49366 * @param {String} target The target region key (north, south, east, west or center).
49367 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
49368 * @return {Roo.ContentPanel} The removed panel
49370 remove : function(target, panel){
49371 target = target.toLowerCase();
49372 return this.regions[target].remove(panel);
49376 * Searches all regions for a panel with the specified id
49377 * @param {String} panelId
49378 * @return {Roo.ContentPanel} The panel or null if it wasn't found
49380 findPanel : function(panelId){
49381 var rs = this.regions;
49382 for(var target in rs){
49383 if(typeof rs[target] != "function"){
49384 var p = rs[target].getPanel(panelId);
49394 * Searches all regions for a panel with the specified id and activates (shows) it.
49395 * @param {String/ContentPanel} panelId The panels id or the panel itself
49396 * @return {Roo.ContentPanel} The shown panel or null
49398 showPanel : function(panelId) {
49399 var rs = this.regions;
49400 for(var target in rs){
49401 var r = rs[target];
49402 if(typeof r != "function"){
49403 if(r.hasPanel(panelId)){
49404 return r.showPanel(panelId);
49412 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
49413 * @param {Roo.state.Provider} provider (optional) An alternate state provider
49415 restoreState : function(provider){
49417 provider = Roo.state.Manager;
49419 var sm = new Roo.LayoutStateManager();
49420 sm.init(this, provider);
49424 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
49425 * object should contain properties for each region to add ContentPanels to, and each property's value should be
49426 * a valid ContentPanel config object. Example:
49428 // Create the main layout
49429 var layout = new Roo.BorderLayout('main-ct', {
49440 // Create and add multiple ContentPanels at once via configs
49443 id: 'source-files',
49445 title:'Ext Source Files',
49458 * @param {Object} regions An object containing ContentPanel configs by region name
49460 batchAdd : function(regions){
49461 this.beginUpdate();
49462 for(var rname in regions){
49463 var lr = this.regions[rname];
49465 this.addTypedPanels(lr, regions[rname]);
49472 addTypedPanels : function(lr, ps){
49473 if(typeof ps == 'string'){
49474 lr.add(new Roo.ContentPanel(ps));
49476 else if(ps instanceof Array){
49477 for(var i =0, len = ps.length; i < len; i++){
49478 this.addTypedPanels(lr, ps[i]);
49481 else if(!ps.events){ // raw config?
49483 delete ps.el; // prevent conflict
49484 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
49486 else { // panel object assumed!
49491 * Adds a xtype elements to the layout.
49495 xtype : 'ContentPanel',
49502 xtype : 'NestedLayoutPanel',
49508 items : [ ... list of content panels or nested layout panels.. ]
49512 * @param {Object} cfg Xtype definition of item to add.
49514 addxtype : function(cfg)
49516 // basically accepts a pannel...
49517 // can accept a layout region..!?!?
49518 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
49520 if (!cfg.xtype.match(/Panel$/)) {
49525 if (typeof(cfg.region) == 'undefined') {
49526 Roo.log("Failed to add Panel, region was not set");
49530 var region = cfg.region;
49536 xitems = cfg.items;
49543 case 'ContentPanel': // ContentPanel (el, cfg)
49544 case 'ScrollPanel': // ContentPanel (el, cfg)
49546 if(cfg.autoCreate) {
49547 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49549 var el = this.el.createChild();
49550 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
49553 this.add(region, ret);
49557 case 'TreePanel': // our new panel!
49558 cfg.el = this.el.createChild();
49559 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49560 this.add(region, ret);
49563 case 'NestedLayoutPanel':
49564 // create a new Layout (which is a Border Layout...
49565 var el = this.el.createChild();
49566 var clayout = cfg.layout;
49568 clayout.items = clayout.items || [];
49569 // replace this exitems with the clayout ones..
49570 xitems = clayout.items;
49573 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
49574 cfg.background = false;
49576 var layout = new Roo.BorderLayout(el, clayout);
49578 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
49579 //console.log('adding nested layout panel ' + cfg.toSource());
49580 this.add(region, ret);
49581 nb = {}; /// find first...
49586 // needs grid and region
49588 //var el = this.getRegion(region).el.createChild();
49589 var el = this.el.createChild();
49590 // create the grid first...
49592 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
49594 if (region == 'center' && this.active ) {
49595 cfg.background = false;
49597 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
49599 this.add(region, ret);
49600 if (cfg.background) {
49601 ret.on('activate', function(gp) {
49602 if (!gp.grid.rendered) {
49617 if (typeof(Roo[cfg.xtype]) != 'undefined') {
49619 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
49620 this.add(region, ret);
49623 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
49627 // GridPanel (grid, cfg)
49630 this.beginUpdate();
49634 Roo.each(xitems, function(i) {
49635 region = nb && i.region ? i.region : false;
49637 var add = ret.addxtype(i);
49640 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
49641 if (!i.background) {
49642 abn[region] = nb[region] ;
49649 // make the last non-background panel active..
49650 //if (nb) { Roo.log(abn); }
49653 for(var r in abn) {
49654 region = this.getRegion(r);
49656 // tried using nb[r], but it does not work..
49658 region.showPanel(abn[r]);
49669 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
49670 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
49671 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
49672 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
49675 var CP = Roo.ContentPanel;
49677 var layout = Roo.BorderLayout.create({
49681 panels: [new CP("north", "North")]
49690 panels: [new CP("west", {title: "West"})]
49699 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
49708 panels: [new CP("south", {title: "South", closable: true})]
49715 preferredTabWidth: 150,
49717 new CP("center1", {title: "Close Me", closable: true}),
49718 new CP("center2", {title: "Center Panel", closable: false})
49723 layout.getRegion("center").showPanel("center1");
49728 Roo.BorderLayout.create = function(config, targetEl){
49729 var layout = new Roo.BorderLayout(targetEl || document.body, config);
49730 layout.beginUpdate();
49731 var regions = Roo.BorderLayout.RegionFactory.validRegions;
49732 for(var j = 0, jlen = regions.length; j < jlen; j++){
49733 var lr = regions[j];
49734 if(layout.regions[lr] && config[lr].panels){
49735 var r = layout.regions[lr];
49736 var ps = config[lr].panels;
49737 layout.addTypedPanels(r, ps);
49740 layout.endUpdate();
49745 Roo.BorderLayout.RegionFactory = {
49747 validRegions : ["north","south","east","west","center"],
49750 create : function(target, mgr, config){
49751 target = target.toLowerCase();
49752 if(config.lightweight || config.basic){
49753 return new Roo.BasicLayoutRegion(mgr, config, target);
49757 return new Roo.NorthLayoutRegion(mgr, config);
49759 return new Roo.SouthLayoutRegion(mgr, config);
49761 return new Roo.EastLayoutRegion(mgr, config);
49763 return new Roo.WestLayoutRegion(mgr, config);
49765 return new Roo.CenterLayoutRegion(mgr, config);
49767 throw 'Layout region "'+target+'" not supported.';
49771 * Ext JS Library 1.1.1
49772 * Copyright(c) 2006-2007, Ext JS, LLC.
49774 * Originally Released Under LGPL - original licence link has changed is not relivant.
49777 * <script type="text/javascript">
49781 * @class Roo.BasicLayoutRegion
49782 * @extends Roo.util.Observable
49783 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
49784 * and does not have a titlebar, tabs or any other features. All it does is size and position
49785 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
49787 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
49789 this.position = pos;
49792 * @scope Roo.BasicLayoutRegion
49796 * @event beforeremove
49797 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
49798 * @param {Roo.LayoutRegion} this
49799 * @param {Roo.ContentPanel} panel The panel
49800 * @param {Object} e The cancel event object
49802 "beforeremove" : true,
49804 * @event invalidated
49805 * Fires when the layout for this region is changed.
49806 * @param {Roo.LayoutRegion} this
49808 "invalidated" : true,
49810 * @event visibilitychange
49811 * Fires when this region is shown or hidden
49812 * @param {Roo.LayoutRegion} this
49813 * @param {Boolean} visibility true or false
49815 "visibilitychange" : true,
49817 * @event paneladded
49818 * Fires when a panel is added.
49819 * @param {Roo.LayoutRegion} this
49820 * @param {Roo.ContentPanel} panel The panel
49822 "paneladded" : true,
49824 * @event panelremoved
49825 * Fires when a panel is removed.
49826 * @param {Roo.LayoutRegion} this
49827 * @param {Roo.ContentPanel} panel The panel
49829 "panelremoved" : true,
49832 * Fires when this region is collapsed.
49833 * @param {Roo.LayoutRegion} this
49835 "collapsed" : true,
49838 * Fires when this region is expanded.
49839 * @param {Roo.LayoutRegion} this
49844 * Fires when this region is slid into view.
49845 * @param {Roo.LayoutRegion} this
49847 "slideshow" : true,
49850 * Fires when this region slides out of view.
49851 * @param {Roo.LayoutRegion} this
49853 "slidehide" : true,
49855 * @event panelactivated
49856 * Fires when a panel is activated.
49857 * @param {Roo.LayoutRegion} this
49858 * @param {Roo.ContentPanel} panel The activated panel
49860 "panelactivated" : true,
49863 * Fires when the user resizes this region.
49864 * @param {Roo.LayoutRegion} this
49865 * @param {Number} newSize The new size (width for east/west, height for north/south)
49869 /** A collection of panels in this region. @type Roo.util.MixedCollection */
49870 this.panels = new Roo.util.MixedCollection();
49871 this.panels.getKey = this.getPanelId.createDelegate(this);
49873 this.activePanel = null;
49874 // ensure listeners are added...
49876 if (config.listeners || config.events) {
49877 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
49878 listeners : config.listeners || {},
49879 events : config.events || {}
49883 if(skipConfig !== true){
49884 this.applyConfig(config);
49888 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
49889 getPanelId : function(p){
49893 applyConfig : function(config){
49894 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
49895 this.config = config;
49900 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
49901 * the width, for horizontal (north, south) the height.
49902 * @param {Number} newSize The new width or height
49904 resizeTo : function(newSize){
49905 var el = this.el ? this.el :
49906 (this.activePanel ? this.activePanel.getEl() : null);
49908 switch(this.position){
49911 el.setWidth(newSize);
49912 this.fireEvent("resized", this, newSize);
49916 el.setHeight(newSize);
49917 this.fireEvent("resized", this, newSize);
49923 getBox : function(){
49924 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
49927 getMargins : function(){
49928 return this.margins;
49931 updateBox : function(box){
49933 var el = this.activePanel.getEl();
49934 el.dom.style.left = box.x + "px";
49935 el.dom.style.top = box.y + "px";
49936 this.activePanel.setSize(box.width, box.height);
49940 * Returns the container element for this region.
49941 * @return {Roo.Element}
49943 getEl : function(){
49944 return this.activePanel;
49948 * Returns true if this region is currently visible.
49949 * @return {Boolean}
49951 isVisible : function(){
49952 return this.activePanel ? true : false;
49955 setActivePanel : function(panel){
49956 panel = this.getPanel(panel);
49957 if(this.activePanel && this.activePanel != panel){
49958 this.activePanel.setActiveState(false);
49959 this.activePanel.getEl().setLeftTop(-10000,-10000);
49961 this.activePanel = panel;
49962 panel.setActiveState(true);
49964 panel.setSize(this.box.width, this.box.height);
49966 this.fireEvent("panelactivated", this, panel);
49967 this.fireEvent("invalidated");
49971 * Show the specified panel.
49972 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
49973 * @return {Roo.ContentPanel} The shown panel or null
49975 showPanel : function(panel){
49976 if(panel = this.getPanel(panel)){
49977 this.setActivePanel(panel);
49983 * Get the active panel for this region.
49984 * @return {Roo.ContentPanel} The active panel or null
49986 getActivePanel : function(){
49987 return this.activePanel;
49991 * Add the passed ContentPanel(s)
49992 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
49993 * @return {Roo.ContentPanel} The panel added (if only one was added)
49995 add : function(panel){
49996 if(arguments.length > 1){
49997 for(var i = 0, len = arguments.length; i < len; i++) {
49998 this.add(arguments[i]);
50002 if(this.hasPanel(panel)){
50003 this.showPanel(panel);
50006 var el = panel.getEl();
50007 if(el.dom.parentNode != this.mgr.el.dom){
50008 this.mgr.el.dom.appendChild(el.dom);
50010 if(panel.setRegion){
50011 panel.setRegion(this);
50013 this.panels.add(panel);
50014 el.setStyle("position", "absolute");
50015 if(!panel.background){
50016 this.setActivePanel(panel);
50017 if(this.config.initialSize && this.panels.getCount()==1){
50018 this.resizeTo(this.config.initialSize);
50021 this.fireEvent("paneladded", this, panel);
50026 * Returns true if the panel is in this region.
50027 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50028 * @return {Boolean}
50030 hasPanel : function(panel){
50031 if(typeof panel == "object"){ // must be panel obj
50032 panel = panel.getId();
50034 return this.getPanel(panel) ? true : false;
50038 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50039 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50040 * @param {Boolean} preservePanel Overrides the config preservePanel option
50041 * @return {Roo.ContentPanel} The panel that was removed
50043 remove : function(panel, preservePanel){
50044 panel = this.getPanel(panel);
50049 this.fireEvent("beforeremove", this, panel, e);
50050 if(e.cancel === true){
50053 var panelId = panel.getId();
50054 this.panels.removeKey(panelId);
50059 * Returns the panel specified or null if it's not in this region.
50060 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
50061 * @return {Roo.ContentPanel}
50063 getPanel : function(id){
50064 if(typeof id == "object"){ // must be panel obj
50067 return this.panels.get(id);
50071 * Returns this regions position (north/south/east/west/center).
50074 getPosition: function(){
50075 return this.position;
50079 * Ext JS Library 1.1.1
50080 * Copyright(c) 2006-2007, Ext JS, LLC.
50082 * Originally Released Under LGPL - original licence link has changed is not relivant.
50085 * <script type="text/javascript">
50089 * @class Roo.LayoutRegion
50090 * @extends Roo.BasicLayoutRegion
50091 * This class represents a region in a layout manager.
50092 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
50093 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
50094 * @cfg {Boolean} floatable False to disable floating (defaults to true)
50095 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
50096 * @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})
50097 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
50098 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
50099 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
50100 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
50101 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
50102 * @cfg {String} title The title for the region (overrides panel titles)
50103 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
50104 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
50105 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
50106 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
50107 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
50108 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
50109 * the space available, similar to FireFox 1.5 tabs (defaults to false)
50110 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
50111 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
50112 * @cfg {Boolean} showPin True to show a pin button
50113 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
50114 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
50115 * @cfg {Boolean} disableTabTips True to disable tab tooltips
50116 * @cfg {Number} width For East/West panels
50117 * @cfg {Number} height For North/South panels
50118 * @cfg {Boolean} split To show the splitter
50119 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
50121 Roo.LayoutRegion = function(mgr, config, pos){
50122 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
50123 var dh = Roo.DomHelper;
50124 /** This region's container element
50125 * @type Roo.Element */
50126 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
50127 /** This region's title element
50128 * @type Roo.Element */
50130 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
50131 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
50132 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
50134 this.titleEl.enableDisplayMode();
50135 /** This region's title text element
50136 * @type HTMLElement */
50137 this.titleTextEl = this.titleEl.dom.firstChild;
50138 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
50139 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
50140 this.closeBtn.enableDisplayMode();
50141 this.closeBtn.on("click", this.closeClicked, this);
50142 this.closeBtn.hide();
50144 this.createBody(config);
50145 this.visible = true;
50146 this.collapsed = false;
50148 if(config.hideWhenEmpty){
50150 this.on("paneladded", this.validateVisibility, this);
50151 this.on("panelremoved", this.validateVisibility, this);
50153 this.applyConfig(config);
50156 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
50158 createBody : function(){
50159 /** This region's body element
50160 * @type Roo.Element */
50161 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
50164 applyConfig : function(c){
50165 if(c.collapsible && this.position != "center" && !this.collapsedEl){
50166 var dh = Roo.DomHelper;
50167 if(c.titlebar !== false){
50168 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
50169 this.collapseBtn.on("click", this.collapse, this);
50170 this.collapseBtn.enableDisplayMode();
50172 if(c.showPin === true || this.showPin){
50173 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
50174 this.stickBtn.enableDisplayMode();
50175 this.stickBtn.on("click", this.expand, this);
50176 this.stickBtn.hide();
50179 /** This region's collapsed element
50180 * @type Roo.Element */
50181 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
50182 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
50184 if(c.floatable !== false){
50185 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
50186 this.collapsedEl.on("click", this.collapseClick, this);
50189 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
50190 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
50191 id: "message", unselectable: "on", style:{"float":"left"}});
50192 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
50194 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
50195 this.expandBtn.on("click", this.expand, this);
50197 if(this.collapseBtn){
50198 this.collapseBtn.setVisible(c.collapsible == true);
50200 this.cmargins = c.cmargins || this.cmargins ||
50201 (this.position == "west" || this.position == "east" ?
50202 {top: 0, left: 2, right:2, bottom: 0} :
50203 {top: 2, left: 0, right:0, bottom: 2});
50204 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
50205 this.bottomTabs = c.tabPosition != "top";
50206 this.autoScroll = c.autoScroll || false;
50207 if(this.autoScroll){
50208 this.bodyEl.setStyle("overflow", "auto");
50210 this.bodyEl.setStyle("overflow", "hidden");
50212 //if(c.titlebar !== false){
50213 if((!c.titlebar && !c.title) || c.titlebar === false){
50214 this.titleEl.hide();
50216 this.titleEl.show();
50218 this.titleTextEl.innerHTML = c.title;
50222 this.duration = c.duration || .30;
50223 this.slideDuration = c.slideDuration || .45;
50226 this.collapse(true);
50233 * Returns true if this region is currently visible.
50234 * @return {Boolean}
50236 isVisible : function(){
50237 return this.visible;
50241 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
50242 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
50244 setCollapsedTitle : function(title){
50245 title = title || " ";
50246 if(this.collapsedTitleTextEl){
50247 this.collapsedTitleTextEl.innerHTML = title;
50251 getBox : function(){
50253 if(!this.collapsed){
50254 b = this.el.getBox(false, true);
50256 b = this.collapsedEl.getBox(false, true);
50261 getMargins : function(){
50262 return this.collapsed ? this.cmargins : this.margins;
50265 highlight : function(){
50266 this.el.addClass("x-layout-panel-dragover");
50269 unhighlight : function(){
50270 this.el.removeClass("x-layout-panel-dragover");
50273 updateBox : function(box){
50275 if(!this.collapsed){
50276 this.el.dom.style.left = box.x + "px";
50277 this.el.dom.style.top = box.y + "px";
50278 this.updateBody(box.width, box.height);
50280 this.collapsedEl.dom.style.left = box.x + "px";
50281 this.collapsedEl.dom.style.top = box.y + "px";
50282 this.collapsedEl.setSize(box.width, box.height);
50285 this.tabs.autoSizeTabs();
50289 updateBody : function(w, h){
50291 this.el.setWidth(w);
50292 w -= this.el.getBorderWidth("rl");
50293 if(this.config.adjustments){
50294 w += this.config.adjustments[0];
50298 this.el.setHeight(h);
50299 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
50300 h -= this.el.getBorderWidth("tb");
50301 if(this.config.adjustments){
50302 h += this.config.adjustments[1];
50304 this.bodyEl.setHeight(h);
50306 h = this.tabs.syncHeight(h);
50309 if(this.panelSize){
50310 w = w !== null ? w : this.panelSize.width;
50311 h = h !== null ? h : this.panelSize.height;
50313 if(this.activePanel){
50314 var el = this.activePanel.getEl();
50315 w = w !== null ? w : el.getWidth();
50316 h = h !== null ? h : el.getHeight();
50317 this.panelSize = {width: w, height: h};
50318 this.activePanel.setSize(w, h);
50320 if(Roo.isIE && this.tabs){
50321 this.tabs.el.repaint();
50326 * Returns the container element for this region.
50327 * @return {Roo.Element}
50329 getEl : function(){
50334 * Hides this region.
50337 if(!this.collapsed){
50338 this.el.dom.style.left = "-2000px";
50341 this.collapsedEl.dom.style.left = "-2000px";
50342 this.collapsedEl.hide();
50344 this.visible = false;
50345 this.fireEvent("visibilitychange", this, false);
50349 * Shows this region if it was previously hidden.
50352 if(!this.collapsed){
50355 this.collapsedEl.show();
50357 this.visible = true;
50358 this.fireEvent("visibilitychange", this, true);
50361 closeClicked : function(){
50362 if(this.activePanel){
50363 this.remove(this.activePanel);
50367 collapseClick : function(e){
50369 e.stopPropagation();
50372 e.stopPropagation();
50378 * Collapses this region.
50379 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
50381 collapse : function(skipAnim){
50382 if(this.collapsed) return;
50383 this.collapsed = true;
50385 this.split.el.hide();
50387 if(this.config.animate && skipAnim !== true){
50388 this.fireEvent("invalidated", this);
50389 this.animateCollapse();
50391 this.el.setLocation(-20000,-20000);
50393 this.collapsedEl.show();
50394 this.fireEvent("collapsed", this);
50395 this.fireEvent("invalidated", this);
50399 animateCollapse : function(){
50404 * Expands this region if it was previously collapsed.
50405 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
50406 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
50408 expand : function(e, skipAnim){
50409 if(e) e.stopPropagation();
50410 if(!this.collapsed || this.el.hasActiveFx()) return;
50412 this.afterSlideIn();
50415 this.collapsed = false;
50416 if(this.config.animate && skipAnim !== true){
50417 this.animateExpand();
50421 this.split.el.show();
50423 this.collapsedEl.setLocation(-2000,-2000);
50424 this.collapsedEl.hide();
50425 this.fireEvent("invalidated", this);
50426 this.fireEvent("expanded", this);
50430 animateExpand : function(){
50434 initTabs : function()
50436 this.bodyEl.setStyle("overflow", "hidden");
50437 var ts = new Roo.TabPanel(
50440 tabPosition: this.bottomTabs ? 'bottom' : 'top',
50441 disableTooltips: this.config.disableTabTips,
50442 toolbar : this.config.toolbar
50445 if(this.config.hideTabs){
50446 ts.stripWrap.setDisplayed(false);
50449 ts.resizeTabs = this.config.resizeTabs === true;
50450 ts.minTabWidth = this.config.minTabWidth || 40;
50451 ts.maxTabWidth = this.config.maxTabWidth || 250;
50452 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
50453 ts.monitorResize = false;
50454 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50455 ts.bodyEl.addClass('x-layout-tabs-body');
50456 this.panels.each(this.initPanelAsTab, this);
50459 initPanelAsTab : function(panel){
50460 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
50461 this.config.closeOnTab && panel.isClosable());
50462 if(panel.tabTip !== undefined){
50463 ti.setTooltip(panel.tabTip);
50465 ti.on("activate", function(){
50466 this.setActivePanel(panel);
50468 if(this.config.closeOnTab){
50469 ti.on("beforeclose", function(t, e){
50471 this.remove(panel);
50477 updatePanelTitle : function(panel, title){
50478 if(this.activePanel == panel){
50479 this.updateTitle(title);
50482 var ti = this.tabs.getTab(panel.getEl().id);
50484 if(panel.tabTip !== undefined){
50485 ti.setTooltip(panel.tabTip);
50490 updateTitle : function(title){
50491 if(this.titleTextEl && !this.config.title){
50492 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
50496 setActivePanel : function(panel){
50497 panel = this.getPanel(panel);
50498 if(this.activePanel && this.activePanel != panel){
50499 this.activePanel.setActiveState(false);
50501 this.activePanel = panel;
50502 panel.setActiveState(true);
50503 if(this.panelSize){
50504 panel.setSize(this.panelSize.width, this.panelSize.height);
50507 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
50509 this.updateTitle(panel.getTitle());
50511 this.fireEvent("invalidated", this);
50513 this.fireEvent("panelactivated", this, panel);
50517 * Shows the specified panel.
50518 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
50519 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
50521 showPanel : function(panel)
50523 panel = this.getPanel(panel);
50526 var tab = this.tabs.getTab(panel.getEl().id);
50527 if(tab.isHidden()){
50528 this.tabs.unhideTab(tab.id);
50532 this.setActivePanel(panel);
50539 * Get the active panel for this region.
50540 * @return {Roo.ContentPanel} The active panel or null
50542 getActivePanel : function(){
50543 return this.activePanel;
50546 validateVisibility : function(){
50547 if(this.panels.getCount() < 1){
50548 this.updateTitle(" ");
50549 this.closeBtn.hide();
50552 if(!this.isVisible()){
50559 * Adds the passed ContentPanel(s) to this region.
50560 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
50561 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
50563 add : function(panel){
50564 if(arguments.length > 1){
50565 for(var i = 0, len = arguments.length; i < len; i++) {
50566 this.add(arguments[i]);
50570 if(this.hasPanel(panel)){
50571 this.showPanel(panel);
50574 panel.setRegion(this);
50575 this.panels.add(panel);
50576 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
50577 this.bodyEl.dom.appendChild(panel.getEl().dom);
50578 if(panel.background !== true){
50579 this.setActivePanel(panel);
50581 this.fireEvent("paneladded", this, panel);
50587 this.initPanelAsTab(panel);
50589 if(panel.background !== true){
50590 this.tabs.activate(panel.getEl().id);
50592 this.fireEvent("paneladded", this, panel);
50597 * Hides the tab for the specified panel.
50598 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50600 hidePanel : function(panel){
50601 if(this.tabs && (panel = this.getPanel(panel))){
50602 this.tabs.hideTab(panel.getEl().id);
50607 * Unhides the tab for a previously hidden panel.
50608 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50610 unhidePanel : function(panel){
50611 if(this.tabs && (panel = this.getPanel(panel))){
50612 this.tabs.unhideTab(panel.getEl().id);
50616 clearPanels : function(){
50617 while(this.panels.getCount() > 0){
50618 this.remove(this.panels.first());
50623 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
50624 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
50625 * @param {Boolean} preservePanel Overrides the config preservePanel option
50626 * @return {Roo.ContentPanel} The panel that was removed
50628 remove : function(panel, preservePanel){
50629 panel = this.getPanel(panel);
50634 this.fireEvent("beforeremove", this, panel, e);
50635 if(e.cancel === true){
50638 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
50639 var panelId = panel.getId();
50640 this.panels.removeKey(panelId);
50642 document.body.appendChild(panel.getEl().dom);
50645 this.tabs.removeTab(panel.getEl().id);
50646 }else if (!preservePanel){
50647 this.bodyEl.dom.removeChild(panel.getEl().dom);
50649 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
50650 var p = this.panels.first();
50651 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
50652 tempEl.appendChild(p.getEl().dom);
50653 this.bodyEl.update("");
50654 this.bodyEl.dom.appendChild(p.getEl().dom);
50656 this.updateTitle(p.getTitle());
50658 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
50659 this.setActivePanel(p);
50661 panel.setRegion(null);
50662 if(this.activePanel == panel){
50663 this.activePanel = null;
50665 if(this.config.autoDestroy !== false && preservePanel !== true){
50666 try{panel.destroy();}catch(e){}
50668 this.fireEvent("panelremoved", this, panel);
50673 * Returns the TabPanel component used by this region
50674 * @return {Roo.TabPanel}
50676 getTabs : function(){
50680 createTool : function(parentEl, className){
50681 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
50682 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
50683 btn.addClassOnOver("x-layout-tools-button-over");
50688 * Ext JS Library 1.1.1
50689 * Copyright(c) 2006-2007, Ext JS, LLC.
50691 * Originally Released Under LGPL - original licence link has changed is not relivant.
50694 * <script type="text/javascript">
50700 * @class Roo.SplitLayoutRegion
50701 * @extends Roo.LayoutRegion
50702 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
50704 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
50705 this.cursor = cursor;
50706 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
50709 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
50710 splitTip : "Drag to resize.",
50711 collapsibleSplitTip : "Drag to resize. Double click to hide.",
50712 useSplitTips : false,
50714 applyConfig : function(config){
50715 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
50718 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
50719 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
50720 /** The SplitBar for this region
50721 * @type Roo.SplitBar */
50722 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
50723 this.split.on("moved", this.onSplitMove, this);
50724 this.split.useShim = config.useShim === true;
50725 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
50726 if(this.useSplitTips){
50727 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
50729 if(config.collapsible){
50730 this.split.el.on("dblclick", this.collapse, this);
50733 if(typeof config.minSize != "undefined"){
50734 this.split.minSize = config.minSize;
50736 if(typeof config.maxSize != "undefined"){
50737 this.split.maxSize = config.maxSize;
50739 if(config.hideWhenEmpty || config.hidden || config.collapsed){
50740 this.hideSplitter();
50745 getHMaxSize : function(){
50746 var cmax = this.config.maxSize || 10000;
50747 var center = this.mgr.getRegion("center");
50748 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
50751 getVMaxSize : function(){
50752 var cmax = this.config.maxSize || 10000;
50753 var center = this.mgr.getRegion("center");
50754 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
50757 onSplitMove : function(split, newSize){
50758 this.fireEvent("resized", this, newSize);
50762 * Returns the {@link Roo.SplitBar} for this region.
50763 * @return {Roo.SplitBar}
50765 getSplitBar : function(){
50770 this.hideSplitter();
50771 Roo.SplitLayoutRegion.superclass.hide.call(this);
50774 hideSplitter : function(){
50776 this.split.el.setLocation(-2000,-2000);
50777 this.split.el.hide();
50783 this.split.el.show();
50785 Roo.SplitLayoutRegion.superclass.show.call(this);
50788 beforeSlide: function(){
50789 if(Roo.isGecko){// firefox overflow auto bug workaround
50790 this.bodyEl.clip();
50791 if(this.tabs) this.tabs.bodyEl.clip();
50792 if(this.activePanel){
50793 this.activePanel.getEl().clip();
50795 if(this.activePanel.beforeSlide){
50796 this.activePanel.beforeSlide();
50802 afterSlide : function(){
50803 if(Roo.isGecko){// firefox overflow auto bug workaround
50804 this.bodyEl.unclip();
50805 if(this.tabs) this.tabs.bodyEl.unclip();
50806 if(this.activePanel){
50807 this.activePanel.getEl().unclip();
50808 if(this.activePanel.afterSlide){
50809 this.activePanel.afterSlide();
50815 initAutoHide : function(){
50816 if(this.autoHide !== false){
50817 if(!this.autoHideHd){
50818 var st = new Roo.util.DelayedTask(this.slideIn, this);
50819 this.autoHideHd = {
50820 "mouseout": function(e){
50821 if(!e.within(this.el, true)){
50825 "mouseover" : function(e){
50831 this.el.on(this.autoHideHd);
50835 clearAutoHide : function(){
50836 if(this.autoHide !== false){
50837 this.el.un("mouseout", this.autoHideHd.mouseout);
50838 this.el.un("mouseover", this.autoHideHd.mouseover);
50842 clearMonitor : function(){
50843 Roo.get(document).un("click", this.slideInIf, this);
50846 // these names are backwards but not changed for compat
50847 slideOut : function(){
50848 if(this.isSlid || this.el.hasActiveFx()){
50851 this.isSlid = true;
50852 if(this.collapseBtn){
50853 this.collapseBtn.hide();
50855 this.closeBtnState = this.closeBtn.getStyle('display');
50856 this.closeBtn.hide();
50858 this.stickBtn.show();
50861 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
50862 this.beforeSlide();
50863 this.el.setStyle("z-index", 10001);
50864 this.el.slideIn(this.getSlideAnchor(), {
50865 callback: function(){
50867 this.initAutoHide();
50868 Roo.get(document).on("click", this.slideInIf, this);
50869 this.fireEvent("slideshow", this);
50876 afterSlideIn : function(){
50877 this.clearAutoHide();
50878 this.isSlid = false;
50879 this.clearMonitor();
50880 this.el.setStyle("z-index", "");
50881 if(this.collapseBtn){
50882 this.collapseBtn.show();
50884 this.closeBtn.setStyle('display', this.closeBtnState);
50886 this.stickBtn.hide();
50888 this.fireEvent("slidehide", this);
50891 slideIn : function(cb){
50892 if(!this.isSlid || this.el.hasActiveFx()){
50896 this.isSlid = false;
50897 this.beforeSlide();
50898 this.el.slideOut(this.getSlideAnchor(), {
50899 callback: function(){
50900 this.el.setLeftTop(-10000, -10000);
50902 this.afterSlideIn();
50910 slideInIf : function(e){
50911 if(!e.within(this.el)){
50916 animateCollapse : function(){
50917 this.beforeSlide();
50918 this.el.setStyle("z-index", 20000);
50919 var anchor = this.getSlideAnchor();
50920 this.el.slideOut(anchor, {
50921 callback : function(){
50922 this.el.setStyle("z-index", "");
50923 this.collapsedEl.slideIn(anchor, {duration:.3});
50925 this.el.setLocation(-10000,-10000);
50927 this.fireEvent("collapsed", this);
50934 animateExpand : function(){
50935 this.beforeSlide();
50936 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
50937 this.el.setStyle("z-index", 20000);
50938 this.collapsedEl.hide({
50941 this.el.slideIn(this.getSlideAnchor(), {
50942 callback : function(){
50943 this.el.setStyle("z-index", "");
50946 this.split.el.show();
50948 this.fireEvent("invalidated", this);
50949 this.fireEvent("expanded", this);
50977 getAnchor : function(){
50978 return this.anchors[this.position];
50981 getCollapseAnchor : function(){
50982 return this.canchors[this.position];
50985 getSlideAnchor : function(){
50986 return this.sanchors[this.position];
50989 getAlignAdj : function(){
50990 var cm = this.cmargins;
50991 switch(this.position){
51007 getExpandAdj : function(){
51008 var c = this.collapsedEl, cm = this.cmargins;
51009 switch(this.position){
51011 return [-(cm.right+c.getWidth()+cm.left), 0];
51014 return [cm.right+c.getWidth()+cm.left, 0];
51017 return [0, -(cm.top+cm.bottom+c.getHeight())];
51020 return [0, cm.top+cm.bottom+c.getHeight()];
51026 * Ext JS Library 1.1.1
51027 * Copyright(c) 2006-2007, Ext JS, LLC.
51029 * Originally Released Under LGPL - original licence link has changed is not relivant.
51032 * <script type="text/javascript">
51035 * These classes are private internal classes
51037 Roo.CenterLayoutRegion = function(mgr, config){
51038 Roo.LayoutRegion.call(this, mgr, config, "center");
51039 this.visible = true;
51040 this.minWidth = config.minWidth || 20;
51041 this.minHeight = config.minHeight || 20;
51044 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
51046 // center panel can't be hidden
51050 // center panel can't be hidden
51053 getMinWidth: function(){
51054 return this.minWidth;
51057 getMinHeight: function(){
51058 return this.minHeight;
51063 Roo.NorthLayoutRegion = function(mgr, config){
51064 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
51066 this.split.placement = Roo.SplitBar.TOP;
51067 this.split.orientation = Roo.SplitBar.VERTICAL;
51068 this.split.el.addClass("x-layout-split-v");
51070 var size = config.initialSize || config.height;
51071 if(typeof size != "undefined"){
51072 this.el.setHeight(size);
51075 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
51076 orientation: Roo.SplitBar.VERTICAL,
51077 getBox : function(){
51078 if(this.collapsed){
51079 return this.collapsedEl.getBox();
51081 var box = this.el.getBox();
51083 box.height += this.split.el.getHeight();
51088 updateBox : function(box){
51089 if(this.split && !this.collapsed){
51090 box.height -= this.split.el.getHeight();
51091 this.split.el.setLeft(box.x);
51092 this.split.el.setTop(box.y+box.height);
51093 this.split.el.setWidth(box.width);
51095 if(this.collapsed){
51096 this.updateBody(box.width, null);
51098 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51102 Roo.SouthLayoutRegion = function(mgr, config){
51103 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
51105 this.split.placement = Roo.SplitBar.BOTTOM;
51106 this.split.orientation = Roo.SplitBar.VERTICAL;
51107 this.split.el.addClass("x-layout-split-v");
51109 var size = config.initialSize || config.height;
51110 if(typeof size != "undefined"){
51111 this.el.setHeight(size);
51114 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
51115 orientation: Roo.SplitBar.VERTICAL,
51116 getBox : function(){
51117 if(this.collapsed){
51118 return this.collapsedEl.getBox();
51120 var box = this.el.getBox();
51122 var sh = this.split.el.getHeight();
51129 updateBox : function(box){
51130 if(this.split && !this.collapsed){
51131 var sh = this.split.el.getHeight();
51134 this.split.el.setLeft(box.x);
51135 this.split.el.setTop(box.y-sh);
51136 this.split.el.setWidth(box.width);
51138 if(this.collapsed){
51139 this.updateBody(box.width, null);
51141 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51145 Roo.EastLayoutRegion = function(mgr, config){
51146 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
51148 this.split.placement = Roo.SplitBar.RIGHT;
51149 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51150 this.split.el.addClass("x-layout-split-h");
51152 var size = config.initialSize || config.width;
51153 if(typeof size != "undefined"){
51154 this.el.setWidth(size);
51157 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
51158 orientation: Roo.SplitBar.HORIZONTAL,
51159 getBox : function(){
51160 if(this.collapsed){
51161 return this.collapsedEl.getBox();
51163 var box = this.el.getBox();
51165 var sw = this.split.el.getWidth();
51172 updateBox : function(box){
51173 if(this.split && !this.collapsed){
51174 var sw = this.split.el.getWidth();
51176 this.split.el.setLeft(box.x);
51177 this.split.el.setTop(box.y);
51178 this.split.el.setHeight(box.height);
51181 if(this.collapsed){
51182 this.updateBody(null, box.height);
51184 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51188 Roo.WestLayoutRegion = function(mgr, config){
51189 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
51191 this.split.placement = Roo.SplitBar.LEFT;
51192 this.split.orientation = Roo.SplitBar.HORIZONTAL;
51193 this.split.el.addClass("x-layout-split-h");
51195 var size = config.initialSize || config.width;
51196 if(typeof size != "undefined"){
51197 this.el.setWidth(size);
51200 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
51201 orientation: Roo.SplitBar.HORIZONTAL,
51202 getBox : function(){
51203 if(this.collapsed){
51204 return this.collapsedEl.getBox();
51206 var box = this.el.getBox();
51208 box.width += this.split.el.getWidth();
51213 updateBox : function(box){
51214 if(this.split && !this.collapsed){
51215 var sw = this.split.el.getWidth();
51217 this.split.el.setLeft(box.x+box.width);
51218 this.split.el.setTop(box.y);
51219 this.split.el.setHeight(box.height);
51221 if(this.collapsed){
51222 this.updateBody(null, box.height);
51224 Roo.LayoutRegion.prototype.updateBox.call(this, box);
51229 * Ext JS Library 1.1.1
51230 * Copyright(c) 2006-2007, Ext JS, LLC.
51232 * Originally Released Under LGPL - original licence link has changed is not relivant.
51235 * <script type="text/javascript">
51240 * Private internal class for reading and applying state
51242 Roo.LayoutStateManager = function(layout){
51243 // default empty state
51252 Roo.LayoutStateManager.prototype = {
51253 init : function(layout, provider){
51254 this.provider = provider;
51255 var state = provider.get(layout.id+"-layout-state");
51257 var wasUpdating = layout.isUpdating();
51259 layout.beginUpdate();
51261 for(var key in state){
51262 if(typeof state[key] != "function"){
51263 var rstate = state[key];
51264 var r = layout.getRegion(key);
51267 r.resizeTo(rstate.size);
51269 if(rstate.collapsed == true){
51272 r.expand(null, true);
51278 layout.endUpdate();
51280 this.state = state;
51282 this.layout = layout;
51283 layout.on("regionresized", this.onRegionResized, this);
51284 layout.on("regioncollapsed", this.onRegionCollapsed, this);
51285 layout.on("regionexpanded", this.onRegionExpanded, this);
51288 storeState : function(){
51289 this.provider.set(this.layout.id+"-layout-state", this.state);
51292 onRegionResized : function(region, newSize){
51293 this.state[region.getPosition()].size = newSize;
51297 onRegionCollapsed : function(region){
51298 this.state[region.getPosition()].collapsed = true;
51302 onRegionExpanded : function(region){
51303 this.state[region.getPosition()].collapsed = false;
51308 * Ext JS Library 1.1.1
51309 * Copyright(c) 2006-2007, Ext JS, LLC.
51311 * Originally Released Under LGPL - original licence link has changed is not relivant.
51314 * <script type="text/javascript">
51317 * @class Roo.ContentPanel
51318 * @extends Roo.util.Observable
51319 * A basic ContentPanel element.
51320 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
51321 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
51322 * @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
51323 * @cfg {Boolean} closable True if the panel can be closed/removed
51324 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
51325 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
51326 * @cfg {Toolbar} toolbar A toolbar for this panel
51327 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
51328 * @cfg {String} title The title for this panel
51329 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
51330 * @cfg {String} url Calls {@link #setUrl} with this value
51331 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
51332 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
51333 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
51334 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
51337 * Create a new ContentPanel.
51338 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
51339 * @param {String/Object} config A string to set only the title or a config object
51340 * @param {String} content (optional) Set the HTML content for this panel
51341 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
51343 Roo.ContentPanel = function(el, config, content){
51347 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
51351 if (config && config.parentLayout) {
51352 el = config.parentLayout.el.createChild();
51355 if(el.autoCreate){ // xtype is available if this is called from factory
51359 this.el = Roo.get(el);
51360 if(!this.el && config && config.autoCreate){
51361 if(typeof config.autoCreate == "object"){
51362 if(!config.autoCreate.id){
51363 config.autoCreate.id = config.id||el;
51365 this.el = Roo.DomHelper.append(document.body,
51366 config.autoCreate, true);
51368 this.el = Roo.DomHelper.append(document.body,
51369 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
51372 this.closable = false;
51373 this.loaded = false;
51374 this.active = false;
51375 if(typeof config == "string"){
51376 this.title = config;
51378 Roo.apply(this, config);
51381 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
51382 this.wrapEl = this.el.wrap();
51383 this.toolbar.container = this.el.insertSibling(false, 'before');
51384 this.toolbar = new Roo.Toolbar(this.toolbar);
51387 // xtype created footer. - not sure if will work as we normally have to render first..
51388 if (this.footer && !this.footer.el && this.footer.xtype) {
51389 if (!this.wrapEl) {
51390 this.wrapEl = this.el.wrap();
51393 this.footer.container = this.wrapEl.createChild();
51395 this.footer = Roo.factory(this.footer, Roo);
51400 this.resizeEl = Roo.get(this.resizeEl, true);
51402 this.resizeEl = this.el;
51404 // handle view.xtype
51412 * Fires when this panel is activated.
51413 * @param {Roo.ContentPanel} this
51417 * @event deactivate
51418 * Fires when this panel is activated.
51419 * @param {Roo.ContentPanel} this
51421 "deactivate" : true,
51425 * Fires when this panel is resized if fitToFrame is true.
51426 * @param {Roo.ContentPanel} this
51427 * @param {Number} width The width after any component adjustments
51428 * @param {Number} height The height after any component adjustments
51434 * Fires when this tab is created
51435 * @param {Roo.ContentPanel} this
51446 if(this.autoScroll){
51447 this.resizeEl.setStyle("overflow", "auto");
51449 // fix randome scrolling
51450 this.el.on('scroll', function() {
51451 Roo.log('fix random scolling');
51452 this.scrollTo('top',0);
51455 content = content || this.content;
51457 this.setContent(content);
51459 if(config && config.url){
51460 this.setUrl(this.url, this.params, this.loadOnce);
51465 Roo.ContentPanel.superclass.constructor.call(this);
51467 if (this.view && typeof(this.view.xtype) != 'undefined') {
51468 this.view.el = this.el.appendChild(document.createElement("div"));
51469 this.view = Roo.factory(this.view);
51470 this.view.render && this.view.render(false, '');
51474 this.fireEvent('render', this);
51477 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
51479 setRegion : function(region){
51480 this.region = region;
51482 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
51484 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
51489 * Returns the toolbar for this Panel if one was configured.
51490 * @return {Roo.Toolbar}
51492 getToolbar : function(){
51493 return this.toolbar;
51496 setActiveState : function(active){
51497 this.active = active;
51499 this.fireEvent("deactivate", this);
51501 this.fireEvent("activate", this);
51505 * Updates this panel's element
51506 * @param {String} content The new content
51507 * @param {Boolean} loadScripts (optional) true to look for and process scripts
51509 setContent : function(content, loadScripts){
51510 this.el.update(content, loadScripts);
51513 ignoreResize : function(w, h){
51514 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
51517 this.lastSize = {width: w, height: h};
51522 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
51523 * @return {Roo.UpdateManager} The UpdateManager
51525 getUpdateManager : function(){
51526 return this.el.getUpdateManager();
51529 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
51530 * @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:
51533 url: "your-url.php",
51534 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
51535 callback: yourFunction,
51536 scope: yourObject, //(optional scope)
51539 text: "Loading...",
51544 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
51545 * 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.
51546 * @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}
51547 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
51548 * @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.
51549 * @return {Roo.ContentPanel} this
51552 var um = this.el.getUpdateManager();
51553 um.update.apply(um, arguments);
51559 * 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.
51560 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
51561 * @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)
51562 * @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)
51563 * @return {Roo.UpdateManager} The UpdateManager
51565 setUrl : function(url, params, loadOnce){
51566 if(this.refreshDelegate){
51567 this.removeListener("activate", this.refreshDelegate);
51569 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
51570 this.on("activate", this.refreshDelegate);
51571 return this.el.getUpdateManager();
51574 _handleRefresh : function(url, params, loadOnce){
51575 if(!loadOnce || !this.loaded){
51576 var updater = this.el.getUpdateManager();
51577 updater.update(url, params, this._setLoaded.createDelegate(this));
51581 _setLoaded : function(){
51582 this.loaded = true;
51586 * Returns this panel's id
51589 getId : function(){
51594 * Returns this panel's element - used by regiosn to add.
51595 * @return {Roo.Element}
51597 getEl : function(){
51598 return this.wrapEl || this.el;
51601 adjustForComponents : function(width, height)
51603 //Roo.log('adjustForComponents ');
51604 if(this.resizeEl != this.el){
51605 width -= this.el.getFrameWidth('lr');
51606 height -= this.el.getFrameWidth('tb');
51609 var te = this.toolbar.getEl();
51610 height -= te.getHeight();
51611 te.setWidth(width);
51614 var te = this.footer.getEl();
51615 Roo.log("footer:" + te.getHeight());
51617 height -= te.getHeight();
51618 te.setWidth(width);
51622 if(this.adjustments){
51623 width += this.adjustments[0];
51624 height += this.adjustments[1];
51626 return {"width": width, "height": height};
51629 setSize : function(width, height){
51630 if(this.fitToFrame && !this.ignoreResize(width, height)){
51631 if(this.fitContainer && this.resizeEl != this.el){
51632 this.el.setSize(width, height);
51634 var size = this.adjustForComponents(width, height);
51635 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
51636 this.fireEvent('resize', this, size.width, size.height);
51641 * Returns this panel's title
51644 getTitle : function(){
51649 * Set this panel's title
51650 * @param {String} title
51652 setTitle : function(title){
51653 this.title = title;
51655 this.region.updatePanelTitle(this, title);
51660 * Returns true is this panel was configured to be closable
51661 * @return {Boolean}
51663 isClosable : function(){
51664 return this.closable;
51667 beforeSlide : function(){
51669 this.resizeEl.clip();
51672 afterSlide : function(){
51674 this.resizeEl.unclip();
51678 * Force a content refresh from the URL specified in the {@link #setUrl} method.
51679 * Will fail silently if the {@link #setUrl} method has not been called.
51680 * This does not activate the panel, just updates its content.
51682 refresh : function(){
51683 if(this.refreshDelegate){
51684 this.loaded = false;
51685 this.refreshDelegate();
51690 * Destroys this panel
51692 destroy : function(){
51693 this.el.removeAllListeners();
51694 var tempEl = document.createElement("span");
51695 tempEl.appendChild(this.el.dom);
51696 tempEl.innerHTML = "";
51702 * form - if the content panel contains a form - this is a reference to it.
51703 * @type {Roo.form.Form}
51707 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
51708 * This contains a reference to it.
51714 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
51724 * @param {Object} cfg Xtype definition of item to add.
51727 addxtype : function(cfg) {
51729 if (cfg.xtype.match(/^Form$/)) {
51732 //if (this.footer) {
51733 // el = this.footer.container.insertSibling(false, 'before');
51735 el = this.el.createChild();
51738 this.form = new Roo.form.Form(cfg);
51741 if ( this.form.allItems.length) this.form.render(el.dom);
51744 // should only have one of theses..
51745 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
51746 // views.. should not be just added - used named prop 'view''
51748 cfg.el = this.el.appendChild(document.createElement("div"));
51751 var ret = new Roo.factory(cfg);
51753 ret.render && ret.render(false, ''); // render blank..
51762 * @class Roo.GridPanel
51763 * @extends Roo.ContentPanel
51765 * Create a new GridPanel.
51766 * @param {Roo.grid.Grid} grid The grid for this panel
51767 * @param {String/Object} config A string to set only the panel's title, or a config object
51769 Roo.GridPanel = function(grid, config){
51772 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
51773 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
51775 this.wrapper.dom.appendChild(grid.getGridEl().dom);
51777 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
51780 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
51782 // xtype created footer. - not sure if will work as we normally have to render first..
51783 if (this.footer && !this.footer.el && this.footer.xtype) {
51785 this.footer.container = this.grid.getView().getFooterPanel(true);
51786 this.footer.dataSource = this.grid.dataSource;
51787 this.footer = Roo.factory(this.footer, Roo);
51791 grid.monitorWindowResize = false; // turn off autosizing
51792 grid.autoHeight = false;
51793 grid.autoWidth = false;
51795 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
51798 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
51799 getId : function(){
51800 return this.grid.id;
51804 * Returns the grid for this panel
51805 * @return {Roo.grid.Grid}
51807 getGrid : function(){
51811 setSize : function(width, height){
51812 if(!this.ignoreResize(width, height)){
51813 var grid = this.grid;
51814 var size = this.adjustForComponents(width, height);
51815 grid.getGridEl().setSize(size.width, size.height);
51820 beforeSlide : function(){
51821 this.grid.getView().scroller.clip();
51824 afterSlide : function(){
51825 this.grid.getView().scroller.unclip();
51828 destroy : function(){
51829 this.grid.destroy();
51831 Roo.GridPanel.superclass.destroy.call(this);
51837 * @class Roo.NestedLayoutPanel
51838 * @extends Roo.ContentPanel
51840 * Create a new NestedLayoutPanel.
51843 * @param {Roo.BorderLayout} layout The layout for this panel
51844 * @param {String/Object} config A string to set only the title or a config object
51846 Roo.NestedLayoutPanel = function(layout, config)
51848 // construct with only one argument..
51849 /* FIXME - implement nicer consturctors
51850 if (layout.layout) {
51852 layout = config.layout;
51853 delete config.layout;
51855 if (layout.xtype && !layout.getEl) {
51856 // then layout needs constructing..
51857 layout = Roo.factory(layout, Roo);
51862 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
51864 layout.monitorWindowResize = false; // turn off autosizing
51865 this.layout = layout;
51866 this.layout.getEl().addClass("x-layout-nested-layout");
51873 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
51875 setSize : function(width, height){
51876 if(!this.ignoreResize(width, height)){
51877 var size = this.adjustForComponents(width, height);
51878 var el = this.layout.getEl();
51879 el.setSize(size.width, size.height);
51880 var touch = el.dom.offsetWidth;
51881 this.layout.layout();
51882 // ie requires a double layout on the first pass
51883 if(Roo.isIE && !this.initialized){
51884 this.initialized = true;
51885 this.layout.layout();
51890 // activate all subpanels if not currently active..
51892 setActiveState : function(active){
51893 this.active = active;
51895 this.fireEvent("deactivate", this);
51899 this.fireEvent("activate", this);
51900 // not sure if this should happen before or after..
51901 if (!this.layout) {
51902 return; // should not happen..
51905 for (var r in this.layout.regions) {
51906 reg = this.layout.getRegion(r);
51907 if (reg.getActivePanel()) {
51908 //reg.showPanel(reg.getActivePanel()); // force it to activate..
51909 reg.setActivePanel(reg.getActivePanel());
51912 if (!reg.panels.length) {
51915 reg.showPanel(reg.getPanel(0));
51924 * Returns the nested BorderLayout for this panel
51925 * @return {Roo.BorderLayout}
51927 getLayout : function(){
51928 return this.layout;
51932 * Adds a xtype elements to the layout of the nested panel
51936 xtype : 'ContentPanel',
51943 xtype : 'NestedLayoutPanel',
51949 items : [ ... list of content panels or nested layout panels.. ]
51953 * @param {Object} cfg Xtype definition of item to add.
51955 addxtype : function(cfg) {
51956 return this.layout.addxtype(cfg);
51961 Roo.ScrollPanel = function(el, config, content){
51962 config = config || {};
51963 config.fitToFrame = true;
51964 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
51966 this.el.dom.style.overflow = "hidden";
51967 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
51968 this.el.removeClass("x-layout-inactive-content");
51969 this.el.on("mousewheel", this.onWheel, this);
51971 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
51972 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
51973 up.unselectable(); down.unselectable();
51974 up.on("click", this.scrollUp, this);
51975 down.on("click", this.scrollDown, this);
51976 up.addClassOnOver("x-scroller-btn-over");
51977 down.addClassOnOver("x-scroller-btn-over");
51978 up.addClassOnClick("x-scroller-btn-click");
51979 down.addClassOnClick("x-scroller-btn-click");
51980 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
51982 this.resizeEl = this.el;
51983 this.el = wrap; this.up = up; this.down = down;
51986 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
51988 wheelIncrement : 5,
51989 scrollUp : function(){
51990 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
51993 scrollDown : function(){
51994 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
51997 afterScroll : function(){
51998 var el = this.resizeEl;
51999 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
52000 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52001 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
52004 setSize : function(){
52005 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
52006 this.afterScroll();
52009 onWheel : function(e){
52010 var d = e.getWheelDelta();
52011 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
52012 this.afterScroll();
52016 setContent : function(content, loadScripts){
52017 this.resizeEl.update(content, loadScripts);
52031 * @class Roo.TreePanel
52032 * @extends Roo.ContentPanel
52034 * Create a new TreePanel. - defaults to fit/scoll contents.
52035 * @param {String/Object} config A string to set only the panel's title, or a config object
52036 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
52038 Roo.TreePanel = function(config){
52039 var el = config.el;
52040 var tree = config.tree;
52041 delete config.tree;
52042 delete config.el; // hopefull!
52044 // wrapper for IE7 strict & safari scroll issue
52046 var treeEl = el.createChild();
52047 config.resizeEl = treeEl;
52051 Roo.TreePanel.superclass.constructor.call(this, el, config);
52054 this.tree = new Roo.tree.TreePanel(treeEl , tree);
52055 //console.log(tree);
52056 this.on('activate', function()
52058 if (this.tree.rendered) {
52061 //console.log('render tree');
52062 this.tree.render();
52064 // this should not be needed.. - it's actually the 'el' that resizes?
52065 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
52067 //this.on('resize', function (cp, w, h) {
52068 // this.tree.innerCt.setWidth(w);
52069 // this.tree.innerCt.setHeight(h);
52070 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
52077 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
52094 * Ext JS Library 1.1.1
52095 * Copyright(c) 2006-2007, Ext JS, LLC.
52097 * Originally Released Under LGPL - original licence link has changed is not relivant.
52100 * <script type="text/javascript">
52105 * @class Roo.ReaderLayout
52106 * @extends Roo.BorderLayout
52107 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
52108 * center region containing two nested regions (a top one for a list view and one for item preview below),
52109 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
52110 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
52111 * expedites the setup of the overall layout and regions for this common application style.
52114 var reader = new Roo.ReaderLayout();
52115 var CP = Roo.ContentPanel; // shortcut for adding
52117 reader.beginUpdate();
52118 reader.add("north", new CP("north", "North"));
52119 reader.add("west", new CP("west", {title: "West"}));
52120 reader.add("east", new CP("east", {title: "East"}));
52122 reader.regions.listView.add(new CP("listView", "List"));
52123 reader.regions.preview.add(new CP("preview", "Preview"));
52124 reader.endUpdate();
52127 * Create a new ReaderLayout
52128 * @param {Object} config Configuration options
52129 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
52130 * document.body if omitted)
52132 Roo.ReaderLayout = function(config, renderTo){
52133 var c = config || {size:{}};
52134 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
52135 north: c.north !== false ? Roo.apply({
52139 }, c.north) : false,
52140 west: c.west !== false ? Roo.apply({
52148 margins:{left:5,right:0,bottom:5,top:5},
52149 cmargins:{left:5,right:5,bottom:5,top:5}
52150 }, c.west) : false,
52151 east: c.east !== false ? Roo.apply({
52159 margins:{left:0,right:5,bottom:5,top:5},
52160 cmargins:{left:5,right:5,bottom:5,top:5}
52161 }, c.east) : false,
52162 center: Roo.apply({
52163 tabPosition: 'top',
52167 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
52171 this.el.addClass('x-reader');
52173 this.beginUpdate();
52175 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
52176 south: c.preview !== false ? Roo.apply({
52183 cmargins:{top:5,left:0, right:0, bottom:0}
52184 }, c.preview) : false,
52185 center: Roo.apply({
52191 this.add('center', new Roo.NestedLayoutPanel(inner,
52192 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
52196 this.regions.preview = inner.getRegion('south');
52197 this.regions.listView = inner.getRegion('center');
52200 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
52202 * Ext JS Library 1.1.1
52203 * Copyright(c) 2006-2007, Ext JS, LLC.
52205 * Originally Released Under LGPL - original licence link has changed is not relivant.
52208 * <script type="text/javascript">
52212 * @class Roo.grid.Grid
52213 * @extends Roo.util.Observable
52214 * This class represents the primary interface of a component based grid control.
52215 * <br><br>Usage:<pre><code>
52216 var grid = new Roo.grid.Grid("my-container-id", {
52219 selModel: mySelectionModel,
52220 autoSizeColumns: true,
52221 monitorWindowResize: false,
52222 trackMouseOver: true
52227 * <b>Common Problems:</b><br/>
52228 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
52229 * element will correct this<br/>
52230 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
52231 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
52232 * are unpredictable.<br/>
52233 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
52234 * grid to calculate dimensions/offsets.<br/>
52236 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
52237 * The container MUST have some type of size defined for the grid to fill. The container will be
52238 * automatically set to position relative if it isn't already.
52239 * @param {Object} config A config object that sets properties on this grid.
52241 Roo.grid.Grid = function(container, config){
52242 // initialize the container
52243 this.container = Roo.get(container);
52244 this.container.update("");
52245 this.container.setStyle("overflow", "hidden");
52246 this.container.addClass('x-grid-container');
52248 this.id = this.container.id;
52250 Roo.apply(this, config);
52251 // check and correct shorthanded configs
52253 this.dataSource = this.ds;
52257 this.colModel = this.cm;
52261 this.selModel = this.sm;
52265 if (this.selModel) {
52266 this.selModel = Roo.factory(this.selModel, Roo.grid);
52267 this.sm = this.selModel;
52268 this.sm.xmodule = this.xmodule || false;
52270 if (typeof(this.colModel.config) == 'undefined') {
52271 this.colModel = new Roo.grid.ColumnModel(this.colModel);
52272 this.cm = this.colModel;
52273 this.cm.xmodule = this.xmodule || false;
52275 if (this.dataSource) {
52276 this.dataSource= Roo.factory(this.dataSource, Roo.data);
52277 this.ds = this.dataSource;
52278 this.ds.xmodule = this.xmodule || false;
52285 this.container.setWidth(this.width);
52289 this.container.setHeight(this.height);
52296 * The raw click event for the entire grid.
52297 * @param {Roo.EventObject} e
52302 * The raw dblclick event for the entire grid.
52303 * @param {Roo.EventObject} e
52307 * @event contextmenu
52308 * The raw contextmenu event for the entire grid.
52309 * @param {Roo.EventObject} e
52311 "contextmenu" : true,
52314 * The raw mousedown event for the entire grid.
52315 * @param {Roo.EventObject} e
52317 "mousedown" : true,
52320 * The raw mouseup event for the entire grid.
52321 * @param {Roo.EventObject} e
52326 * The raw mouseover event for the entire grid.
52327 * @param {Roo.EventObject} e
52329 "mouseover" : true,
52332 * The raw mouseout event for the entire grid.
52333 * @param {Roo.EventObject} e
52338 * The raw keypress event for the entire grid.
52339 * @param {Roo.EventObject} e
52344 * The raw keydown event for the entire grid.
52345 * @param {Roo.EventObject} e
52353 * Fires when a cell is clicked
52354 * @param {Grid} this
52355 * @param {Number} rowIndex
52356 * @param {Number} columnIndex
52357 * @param {Roo.EventObject} e
52359 "cellclick" : true,
52361 * @event celldblclick
52362 * Fires when a cell is double clicked
52363 * @param {Grid} this
52364 * @param {Number} rowIndex
52365 * @param {Number} columnIndex
52366 * @param {Roo.EventObject} e
52368 "celldblclick" : true,
52371 * Fires when a row is clicked
52372 * @param {Grid} this
52373 * @param {Number} rowIndex
52374 * @param {Roo.EventObject} e
52378 * @event rowdblclick
52379 * Fires when a row is double clicked
52380 * @param {Grid} this
52381 * @param {Number} rowIndex
52382 * @param {Roo.EventObject} e
52384 "rowdblclick" : true,
52386 * @event headerclick
52387 * Fires when a header is clicked
52388 * @param {Grid} this
52389 * @param {Number} columnIndex
52390 * @param {Roo.EventObject} e
52392 "headerclick" : true,
52394 * @event headerdblclick
52395 * Fires when a header cell is double clicked
52396 * @param {Grid} this
52397 * @param {Number} columnIndex
52398 * @param {Roo.EventObject} e
52400 "headerdblclick" : true,
52402 * @event rowcontextmenu
52403 * Fires when a row is right clicked
52404 * @param {Grid} this
52405 * @param {Number} rowIndex
52406 * @param {Roo.EventObject} e
52408 "rowcontextmenu" : true,
52410 * @event cellcontextmenu
52411 * Fires when a cell is right clicked
52412 * @param {Grid} this
52413 * @param {Number} rowIndex
52414 * @param {Number} cellIndex
52415 * @param {Roo.EventObject} e
52417 "cellcontextmenu" : true,
52419 * @event headercontextmenu
52420 * Fires when a header is right clicked
52421 * @param {Grid} this
52422 * @param {Number} columnIndex
52423 * @param {Roo.EventObject} e
52425 "headercontextmenu" : true,
52427 * @event bodyscroll
52428 * Fires when the body element is scrolled
52429 * @param {Number} scrollLeft
52430 * @param {Number} scrollTop
52432 "bodyscroll" : true,
52434 * @event columnresize
52435 * Fires when the user resizes a column
52436 * @param {Number} columnIndex
52437 * @param {Number} newSize
52439 "columnresize" : true,
52441 * @event columnmove
52442 * Fires when the user moves a column
52443 * @param {Number} oldIndex
52444 * @param {Number} newIndex
52446 "columnmove" : true,
52449 * Fires when row(s) start being dragged
52450 * @param {Grid} this
52451 * @param {Roo.GridDD} dd The drag drop object
52452 * @param {event} e The raw browser event
52454 "startdrag" : true,
52457 * Fires when a drag operation is complete
52458 * @param {Grid} this
52459 * @param {Roo.GridDD} dd The drag drop object
52460 * @param {event} e The raw browser event
52465 * Fires when dragged row(s) are dropped on a valid DD target
52466 * @param {Grid} this
52467 * @param {Roo.GridDD} dd The drag drop object
52468 * @param {String} targetId The target drag drop object
52469 * @param {event} e The raw browser event
52474 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
52475 * @param {Grid} this
52476 * @param {Roo.GridDD} dd The drag drop object
52477 * @param {String} targetId The target drag drop object
52478 * @param {event} e The raw browser event
52483 * Fires when the dragged row(s) first cross another DD target while being dragged
52484 * @param {Grid} this
52485 * @param {Roo.GridDD} dd The drag drop object
52486 * @param {String} targetId The target drag drop object
52487 * @param {event} e The raw browser event
52489 "dragenter" : true,
52492 * Fires when the dragged row(s) leave another DD target while being dragged
52493 * @param {Grid} this
52494 * @param {Roo.GridDD} dd The drag drop object
52495 * @param {String} targetId The target drag drop object
52496 * @param {event} e The raw browser event
52501 * Fires when a row is rendered, so you can change add a style to it.
52502 * @param {GridView} gridview The grid view
52503 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
52509 * Fires when the grid is rendered
52510 * @param {Grid} grid
52515 Roo.grid.Grid.superclass.constructor.call(this);
52517 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
52520 * @cfg {String} ddGroup - drag drop group.
52524 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
52526 minColumnWidth : 25,
52529 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
52530 * <b>on initial render.</b> It is more efficient to explicitly size the columns
52531 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
52533 autoSizeColumns : false,
52536 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
52538 autoSizeHeaders : true,
52541 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
52543 monitorWindowResize : true,
52546 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
52547 * rows measured to get a columns size. Default is 0 (all rows).
52549 maxRowsToMeasure : 0,
52552 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
52554 trackMouseOver : true,
52557 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
52561 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
52563 enableDragDrop : false,
52566 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
52568 enableColumnMove : true,
52571 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
52573 enableColumnHide : true,
52576 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
52578 enableRowHeightSync : false,
52581 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
52586 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
52588 autoHeight : false,
52591 * @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.
52593 autoExpandColumn : false,
52596 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
52599 autoExpandMin : 50,
52602 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
52604 autoExpandMax : 1000,
52607 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
52612 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
52616 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
52626 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
52627 * of a fixed width. Default is false.
52630 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
52633 * Called once after all setup has been completed and the grid is ready to be rendered.
52634 * @return {Roo.grid.Grid} this
52636 render : function()
52638 var c = this.container;
52639 // try to detect autoHeight/width mode
52640 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
52641 this.autoHeight = true;
52643 var view = this.getView();
52646 c.on("click", this.onClick, this);
52647 c.on("dblclick", this.onDblClick, this);
52648 c.on("contextmenu", this.onContextMenu, this);
52649 c.on("keydown", this.onKeyDown, this);
52651 c.on("touchstart", this.onTouchStart, this);
52654 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
52656 this.getSelectionModel().init(this);
52661 this.loadMask = new Roo.LoadMask(this.container,
52662 Roo.apply({store:this.dataSource}, this.loadMask));
52666 if (this.toolbar && this.toolbar.xtype) {
52667 this.toolbar.container = this.getView().getHeaderPanel(true);
52668 this.toolbar = new Roo.Toolbar(this.toolbar);
52670 if (this.footer && this.footer.xtype) {
52671 this.footer.dataSource = this.getDataSource();
52672 this.footer.container = this.getView().getFooterPanel(true);
52673 this.footer = Roo.factory(this.footer, Roo);
52675 if (this.dropTarget && this.dropTarget.xtype) {
52676 delete this.dropTarget.xtype;
52677 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
52681 this.rendered = true;
52682 this.fireEvent('render', this);
52687 * Reconfigures the grid to use a different Store and Column Model.
52688 * The View will be bound to the new objects and refreshed.
52689 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
52690 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
52692 reconfigure : function(dataSource, colModel){
52694 this.loadMask.destroy();
52695 this.loadMask = new Roo.LoadMask(this.container,
52696 Roo.apply({store:dataSource}, this.loadMask));
52698 this.view.bind(dataSource, colModel);
52699 this.dataSource = dataSource;
52700 this.colModel = colModel;
52701 this.view.refresh(true);
52705 onKeyDown : function(e){
52706 this.fireEvent("keydown", e);
52710 * Destroy this grid.
52711 * @param {Boolean} removeEl True to remove the element
52713 destroy : function(removeEl, keepListeners){
52715 this.loadMask.destroy();
52717 var c = this.container;
52718 c.removeAllListeners();
52719 this.view.destroy();
52720 this.colModel.purgeListeners();
52721 if(!keepListeners){
52722 this.purgeListeners();
52725 if(removeEl === true){
52731 processEvent : function(name, e){
52732 // does this fire select???
52733 //Roo.log('grid:processEvent ' + name);
52735 if (name != 'touchstart' ) {
52736 this.fireEvent(name, e);
52739 var t = e.getTarget();
52741 var header = v.findHeaderIndex(t);
52742 if(header !== false){
52743 var ename = name == 'touchstart' ? 'click' : name;
52745 this.fireEvent("header" + ename, this, header, e);
52747 var row = v.findRowIndex(t);
52748 var cell = v.findCellIndex(t);
52749 if (name == 'touchstart') {
52750 // first touch is always a click.
52751 // hopefull this happens after selection is updated.?
52754 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
52755 var cs = this.selModel.getSelectedCell();
52756 if (row == cs[0] && cell == cs[1]){
52760 if (typeof(this.selModel.getSelections) != 'undefined') {
52761 var cs = this.selModel.getSelections();
52762 var ds = this.dataSource;
52763 if (cs.length == 1 && ds.getAt(row) == cs[0]){
52774 this.fireEvent("row" + name, this, row, e);
52775 if(cell !== false){
52776 this.fireEvent("cell" + name, this, row, cell, e);
52783 onClick : function(e){
52784 this.processEvent("click", e);
52787 onTouchStart : function(e){
52788 this.processEvent("touchstart", e);
52792 onContextMenu : function(e, t){
52793 this.processEvent("contextmenu", e);
52797 onDblClick : function(e){
52798 this.processEvent("dblclick", e);
52802 walkCells : function(row, col, step, fn, scope){
52803 var cm = this.colModel, clen = cm.getColumnCount();
52804 var ds = this.dataSource, rlen = ds.getCount(), first = true;
52816 if(fn.call(scope || this, row, col, cm) === true){
52834 if(fn.call(scope || this, row, col, cm) === true){
52846 getSelections : function(){
52847 return this.selModel.getSelections();
52851 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
52852 * but if manual update is required this method will initiate it.
52854 autoSize : function(){
52856 this.view.layout();
52857 if(this.view.adjustForScroll){
52858 this.view.adjustForScroll();
52864 * Returns the grid's underlying element.
52865 * @return {Element} The element
52867 getGridEl : function(){
52868 return this.container;
52871 // private for compatibility, overridden by editor grid
52872 stopEditing : function(){},
52875 * Returns the grid's SelectionModel.
52876 * @return {SelectionModel}
52878 getSelectionModel : function(){
52879 if(!this.selModel){
52880 this.selModel = new Roo.grid.RowSelectionModel();
52882 return this.selModel;
52886 * Returns the grid's DataSource.
52887 * @return {DataSource}
52889 getDataSource : function(){
52890 return this.dataSource;
52894 * Returns the grid's ColumnModel.
52895 * @return {ColumnModel}
52897 getColumnModel : function(){
52898 return this.colModel;
52902 * Returns the grid's GridView object.
52903 * @return {GridView}
52905 getView : function(){
52907 this.view = new Roo.grid.GridView(this.viewConfig);
52912 * Called to get grid's drag proxy text, by default returns this.ddText.
52915 getDragDropText : function(){
52916 var count = this.selModel.getCount();
52917 return String.format(this.ddText, count, count == 1 ? '' : 's');
52921 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
52922 * %0 is replaced with the number of selected rows.
52925 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
52927 * Ext JS Library 1.1.1
52928 * Copyright(c) 2006-2007, Ext JS, LLC.
52930 * Originally Released Under LGPL - original licence link has changed is not relivant.
52933 * <script type="text/javascript">
52936 Roo.grid.AbstractGridView = function(){
52940 "beforerowremoved" : true,
52941 "beforerowsinserted" : true,
52942 "beforerefresh" : true,
52943 "rowremoved" : true,
52944 "rowsinserted" : true,
52945 "rowupdated" : true,
52948 Roo.grid.AbstractGridView.superclass.constructor.call(this);
52951 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
52952 rowClass : "x-grid-row",
52953 cellClass : "x-grid-cell",
52954 tdClass : "x-grid-td",
52955 hdClass : "x-grid-hd",
52956 splitClass : "x-grid-hd-split",
52958 init: function(grid){
52960 var cid = this.grid.getGridEl().id;
52961 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
52962 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
52963 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
52964 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
52967 getColumnRenderers : function(){
52968 var renderers = [];
52969 var cm = this.grid.colModel;
52970 var colCount = cm.getColumnCount();
52971 for(var i = 0; i < colCount; i++){
52972 renderers[i] = cm.getRenderer(i);
52977 getColumnIds : function(){
52979 var cm = this.grid.colModel;
52980 var colCount = cm.getColumnCount();
52981 for(var i = 0; i < colCount; i++){
52982 ids[i] = cm.getColumnId(i);
52987 getDataIndexes : function(){
52988 if(!this.indexMap){
52989 this.indexMap = this.buildIndexMap();
52991 return this.indexMap.colToData;
52994 getColumnIndexByDataIndex : function(dataIndex){
52995 if(!this.indexMap){
52996 this.indexMap = this.buildIndexMap();
52998 return this.indexMap.dataToCol[dataIndex];
53002 * Set a css style for a column dynamically.
53003 * @param {Number} colIndex The index of the column
53004 * @param {String} name The css property name
53005 * @param {String} value The css value
53007 setCSSStyle : function(colIndex, name, value){
53008 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
53009 Roo.util.CSS.updateRule(selector, name, value);
53012 generateRules : function(cm){
53013 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
53014 Roo.util.CSS.removeStyleSheet(rulesId);
53015 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53016 var cid = cm.getColumnId(i);
53017 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
53018 this.tdSelector, cid, " {\n}\n",
53019 this.hdSelector, cid, " {\n}\n",
53020 this.splitSelector, cid, " {\n}\n");
53022 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53026 * Ext JS Library 1.1.1
53027 * Copyright(c) 2006-2007, Ext JS, LLC.
53029 * Originally Released Under LGPL - original licence link has changed is not relivant.
53032 * <script type="text/javascript">
53036 // This is a support class used internally by the Grid components
53037 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
53039 this.view = grid.getView();
53040 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53041 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
53043 this.setHandleElId(Roo.id(hd));
53044 this.setOuterHandleElId(Roo.id(hd2));
53046 this.scroll = false;
53048 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
53050 getDragData : function(e){
53051 var t = Roo.lib.Event.getTarget(e);
53052 var h = this.view.findHeaderCell(t);
53054 return {ddel: h.firstChild, header:h};
53059 onInitDrag : function(e){
53060 this.view.headersDisabled = true;
53061 var clone = this.dragData.ddel.cloneNode(true);
53062 clone.id = Roo.id();
53063 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
53064 this.proxy.update(clone);
53068 afterValidDrop : function(){
53070 setTimeout(function(){
53071 v.headersDisabled = false;
53075 afterInvalidDrop : function(){
53077 setTimeout(function(){
53078 v.headersDisabled = false;
53084 * Ext JS Library 1.1.1
53085 * Copyright(c) 2006-2007, Ext JS, LLC.
53087 * Originally Released Under LGPL - original licence link has changed is not relivant.
53090 * <script type="text/javascript">
53093 // This is a support class used internally by the Grid components
53094 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
53096 this.view = grid.getView();
53097 // split the proxies so they don't interfere with mouse events
53098 this.proxyTop = Roo.DomHelper.append(document.body, {
53099 cls:"col-move-top", html:" "
53101 this.proxyBottom = Roo.DomHelper.append(document.body, {
53102 cls:"col-move-bottom", html:" "
53104 this.proxyTop.hide = this.proxyBottom.hide = function(){
53105 this.setLeftTop(-100,-100);
53106 this.setStyle("visibility", "hidden");
53108 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
53109 // temporarily disabled
53110 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
53111 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
53113 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
53114 proxyOffsets : [-4, -9],
53115 fly: Roo.Element.fly,
53117 getTargetFromEvent : function(e){
53118 var t = Roo.lib.Event.getTarget(e);
53119 var cindex = this.view.findCellIndex(t);
53120 if(cindex !== false){
53121 return this.view.getHeaderCell(cindex);
53126 nextVisible : function(h){
53127 var v = this.view, cm = this.grid.colModel;
53130 if(!cm.isHidden(v.getCellIndex(h))){
53138 prevVisible : function(h){
53139 var v = this.view, cm = this.grid.colModel;
53142 if(!cm.isHidden(v.getCellIndex(h))){
53150 positionIndicator : function(h, n, e){
53151 var x = Roo.lib.Event.getPageX(e);
53152 var r = Roo.lib.Dom.getRegion(n.firstChild);
53153 var px, pt, py = r.top + this.proxyOffsets[1];
53154 if((r.right - x) <= (r.right-r.left)/2){
53155 px = r.right+this.view.borderWidth;
53161 var oldIndex = this.view.getCellIndex(h);
53162 var newIndex = this.view.getCellIndex(n);
53164 if(this.grid.colModel.isFixed(newIndex)){
53168 var locked = this.grid.colModel.isLocked(newIndex);
53173 if(oldIndex < newIndex){
53176 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
53179 px += this.proxyOffsets[0];
53180 this.proxyTop.setLeftTop(px, py);
53181 this.proxyTop.show();
53182 if(!this.bottomOffset){
53183 this.bottomOffset = this.view.mainHd.getHeight();
53185 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
53186 this.proxyBottom.show();
53190 onNodeEnter : function(n, dd, e, data){
53191 if(data.header != n){
53192 this.positionIndicator(data.header, n, e);
53196 onNodeOver : function(n, dd, e, data){
53197 var result = false;
53198 if(data.header != n){
53199 result = this.positionIndicator(data.header, n, e);
53202 this.proxyTop.hide();
53203 this.proxyBottom.hide();
53205 return result ? this.dropAllowed : this.dropNotAllowed;
53208 onNodeOut : function(n, dd, e, data){
53209 this.proxyTop.hide();
53210 this.proxyBottom.hide();
53213 onNodeDrop : function(n, dd, e, data){
53214 var h = data.header;
53216 var cm = this.grid.colModel;
53217 var x = Roo.lib.Event.getPageX(e);
53218 var r = Roo.lib.Dom.getRegion(n.firstChild);
53219 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
53220 var oldIndex = this.view.getCellIndex(h);
53221 var newIndex = this.view.getCellIndex(n);
53222 var locked = cm.isLocked(newIndex);
53226 if(oldIndex < newIndex){
53229 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
53232 cm.setLocked(oldIndex, locked, true);
53233 cm.moveColumn(oldIndex, newIndex);
53234 this.grid.fireEvent("columnmove", oldIndex, newIndex);
53242 * Ext JS Library 1.1.1
53243 * Copyright(c) 2006-2007, Ext JS, LLC.
53245 * Originally Released Under LGPL - original licence link has changed is not relivant.
53248 * <script type="text/javascript">
53252 * @class Roo.grid.GridView
53253 * @extends Roo.util.Observable
53256 * @param {Object} config
53258 Roo.grid.GridView = function(config){
53259 Roo.grid.GridView.superclass.constructor.call(this);
53262 Roo.apply(this, config);
53265 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
53267 unselectable : 'unselectable="on"',
53268 unselectableCls : 'x-unselectable',
53271 rowClass : "x-grid-row",
53273 cellClass : "x-grid-col",
53275 tdClass : "x-grid-td",
53277 hdClass : "x-grid-hd",
53279 splitClass : "x-grid-split",
53281 sortClasses : ["sort-asc", "sort-desc"],
53283 enableMoveAnim : false,
53287 dh : Roo.DomHelper,
53289 fly : Roo.Element.fly,
53291 css : Roo.util.CSS,
53297 scrollIncrement : 22,
53299 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
53301 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
53303 bind : function(ds, cm){
53305 this.ds.un("load", this.onLoad, this);
53306 this.ds.un("datachanged", this.onDataChange, this);
53307 this.ds.un("add", this.onAdd, this);
53308 this.ds.un("remove", this.onRemove, this);
53309 this.ds.un("update", this.onUpdate, this);
53310 this.ds.un("clear", this.onClear, this);
53313 ds.on("load", this.onLoad, this);
53314 ds.on("datachanged", this.onDataChange, this);
53315 ds.on("add", this.onAdd, this);
53316 ds.on("remove", this.onRemove, this);
53317 ds.on("update", this.onUpdate, this);
53318 ds.on("clear", this.onClear, this);
53323 this.cm.un("widthchange", this.onColWidthChange, this);
53324 this.cm.un("headerchange", this.onHeaderChange, this);
53325 this.cm.un("hiddenchange", this.onHiddenChange, this);
53326 this.cm.un("columnmoved", this.onColumnMove, this);
53327 this.cm.un("columnlockchange", this.onColumnLock, this);
53330 this.generateRules(cm);
53331 cm.on("widthchange", this.onColWidthChange, this);
53332 cm.on("headerchange", this.onHeaderChange, this);
53333 cm.on("hiddenchange", this.onHiddenChange, this);
53334 cm.on("columnmoved", this.onColumnMove, this);
53335 cm.on("columnlockchange", this.onColumnLock, this);
53340 init: function(grid){
53341 Roo.grid.GridView.superclass.init.call(this, grid);
53343 this.bind(grid.dataSource, grid.colModel);
53345 grid.on("headerclick", this.handleHeaderClick, this);
53347 if(grid.trackMouseOver){
53348 grid.on("mouseover", this.onRowOver, this);
53349 grid.on("mouseout", this.onRowOut, this);
53351 grid.cancelTextSelection = function(){};
53352 this.gridId = grid.id;
53354 var tpls = this.templates || {};
53357 tpls.master = new Roo.Template(
53358 '<div class="x-grid" hidefocus="true">',
53359 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
53360 '<div class="x-grid-topbar"></div>',
53361 '<div class="x-grid-scroller"><div></div></div>',
53362 '<div class="x-grid-locked">',
53363 '<div class="x-grid-header">{lockedHeader}</div>',
53364 '<div class="x-grid-body">{lockedBody}</div>',
53366 '<div class="x-grid-viewport">',
53367 '<div class="x-grid-header">{header}</div>',
53368 '<div class="x-grid-body">{body}</div>',
53370 '<div class="x-grid-bottombar"></div>',
53372 '<div class="x-grid-resize-proxy"> </div>',
53375 tpls.master.disableformats = true;
53379 tpls.header = new Roo.Template(
53380 '<table border="0" cellspacing="0" cellpadding="0">',
53381 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
53384 tpls.header.disableformats = true;
53386 tpls.header.compile();
53389 tpls.hcell = new Roo.Template(
53390 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
53391 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
53394 tpls.hcell.disableFormats = true;
53396 tpls.hcell.compile();
53399 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
53400 this.unselectableCls + '" ' + this.unselectable +'> </div>');
53401 tpls.hsplit.disableFormats = true;
53403 tpls.hsplit.compile();
53406 tpls.body = new Roo.Template(
53407 '<table border="0" cellspacing="0" cellpadding="0">',
53408 "<tbody>{rows}</tbody>",
53411 tpls.body.disableFormats = true;
53413 tpls.body.compile();
53416 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
53417 tpls.row.disableFormats = true;
53419 tpls.row.compile();
53422 tpls.cell = new Roo.Template(
53423 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
53424 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
53425 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
53428 tpls.cell.disableFormats = true;
53430 tpls.cell.compile();
53432 this.templates = tpls;
53435 // remap these for backwards compat
53436 onColWidthChange : function(){
53437 this.updateColumns.apply(this, arguments);
53439 onHeaderChange : function(){
53440 this.updateHeaders.apply(this, arguments);
53442 onHiddenChange : function(){
53443 this.handleHiddenChange.apply(this, arguments);
53445 onColumnMove : function(){
53446 this.handleColumnMove.apply(this, arguments);
53448 onColumnLock : function(){
53449 this.handleLockChange.apply(this, arguments);
53452 onDataChange : function(){
53454 this.updateHeaderSortState();
53457 onClear : function(){
53461 onUpdate : function(ds, record){
53462 this.refreshRow(record);
53465 refreshRow : function(record){
53466 var ds = this.ds, index;
53467 if(typeof record == 'number'){
53469 record = ds.getAt(index);
53471 index = ds.indexOf(record);
53473 this.insertRows(ds, index, index, true);
53474 this.onRemove(ds, record, index+1, true);
53475 this.syncRowHeights(index, index);
53477 this.fireEvent("rowupdated", this, index, record);
53480 onAdd : function(ds, records, index){
53481 this.insertRows(ds, index, index + (records.length-1));
53484 onRemove : function(ds, record, index, isUpdate){
53485 if(isUpdate !== true){
53486 this.fireEvent("beforerowremoved", this, index, record);
53488 var bt = this.getBodyTable(), lt = this.getLockedTable();
53489 if(bt.rows[index]){
53490 bt.firstChild.removeChild(bt.rows[index]);
53492 if(lt.rows[index]){
53493 lt.firstChild.removeChild(lt.rows[index]);
53495 if(isUpdate !== true){
53496 this.stripeRows(index);
53497 this.syncRowHeights(index, index);
53499 this.fireEvent("rowremoved", this, index, record);
53503 onLoad : function(){
53504 this.scrollToTop();
53508 * Scrolls the grid to the top
53510 scrollToTop : function(){
53512 this.scroller.dom.scrollTop = 0;
53518 * Gets a panel in the header of the grid that can be used for toolbars etc.
53519 * After modifying the contents of this panel a call to grid.autoSize() may be
53520 * required to register any changes in size.
53521 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
53522 * @return Roo.Element
53524 getHeaderPanel : function(doShow){
53526 this.headerPanel.show();
53528 return this.headerPanel;
53532 * Gets a panel in the footer of the grid that can be used for toolbars etc.
53533 * After modifying the contents of this panel a call to grid.autoSize() may be
53534 * required to register any changes in size.
53535 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
53536 * @return Roo.Element
53538 getFooterPanel : function(doShow){
53540 this.footerPanel.show();
53542 return this.footerPanel;
53545 initElements : function(){
53546 var E = Roo.Element;
53547 var el = this.grid.getGridEl().dom.firstChild;
53548 var cs = el.childNodes;
53550 this.el = new E(el);
53552 this.focusEl = new E(el.firstChild);
53553 this.focusEl.swallowEvent("click", true);
53555 this.headerPanel = new E(cs[1]);
53556 this.headerPanel.enableDisplayMode("block");
53558 this.scroller = new E(cs[2]);
53559 this.scrollSizer = new E(this.scroller.dom.firstChild);
53561 this.lockedWrap = new E(cs[3]);
53562 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
53563 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
53565 this.mainWrap = new E(cs[4]);
53566 this.mainHd = new E(this.mainWrap.dom.firstChild);
53567 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
53569 this.footerPanel = new E(cs[5]);
53570 this.footerPanel.enableDisplayMode("block");
53572 this.resizeProxy = new E(cs[6]);
53574 this.headerSelector = String.format(
53575 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
53576 this.lockedHd.id, this.mainHd.id
53579 this.splitterSelector = String.format(
53580 '#{0} div.x-grid-split, #{1} div.x-grid-split',
53581 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
53584 idToCssName : function(s)
53586 return s.replace(/[^a-z0-9]+/ig, '-');
53589 getHeaderCell : function(index){
53590 return Roo.DomQuery.select(this.headerSelector)[index];
53593 getHeaderCellMeasure : function(index){
53594 return this.getHeaderCell(index).firstChild;
53597 getHeaderCellText : function(index){
53598 return this.getHeaderCell(index).firstChild.firstChild;
53601 getLockedTable : function(){
53602 return this.lockedBody.dom.firstChild;
53605 getBodyTable : function(){
53606 return this.mainBody.dom.firstChild;
53609 getLockedRow : function(index){
53610 return this.getLockedTable().rows[index];
53613 getRow : function(index){
53614 return this.getBodyTable().rows[index];
53617 getRowComposite : function(index){
53619 this.rowEl = new Roo.CompositeElementLite();
53621 var els = [], lrow, mrow;
53622 if(lrow = this.getLockedRow(index)){
53625 if(mrow = this.getRow(index)){
53628 this.rowEl.elements = els;
53632 * Gets the 'td' of the cell
53634 * @param {Integer} rowIndex row to select
53635 * @param {Integer} colIndex column to select
53639 getCell : function(rowIndex, colIndex){
53640 var locked = this.cm.getLockedCount();
53642 if(colIndex < locked){
53643 source = this.lockedBody.dom.firstChild;
53645 source = this.mainBody.dom.firstChild;
53646 colIndex -= locked;
53648 return source.rows[rowIndex].childNodes[colIndex];
53651 getCellText : function(rowIndex, colIndex){
53652 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
53655 getCellBox : function(cell){
53656 var b = this.fly(cell).getBox();
53657 if(Roo.isOpera){ // opera fails to report the Y
53658 b.y = cell.offsetTop + this.mainBody.getY();
53663 getCellIndex : function(cell){
53664 var id = String(cell.className).match(this.cellRE);
53666 return parseInt(id[1], 10);
53671 findHeaderIndex : function(n){
53672 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53673 return r ? this.getCellIndex(r) : false;
53676 findHeaderCell : function(n){
53677 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
53678 return r ? r : false;
53681 findRowIndex : function(n){
53685 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
53686 return r ? r.rowIndex : false;
53689 findCellIndex : function(node){
53690 var stop = this.el.dom;
53691 while(node && node != stop){
53692 if(this.findRE.test(node.className)){
53693 return this.getCellIndex(node);
53695 node = node.parentNode;
53700 getColumnId : function(index){
53701 return this.cm.getColumnId(index);
53704 getSplitters : function()
53706 if(this.splitterSelector){
53707 return Roo.DomQuery.select(this.splitterSelector);
53713 getSplitter : function(index){
53714 return this.getSplitters()[index];
53717 onRowOver : function(e, t){
53719 if((row = this.findRowIndex(t)) !== false){
53720 this.getRowComposite(row).addClass("x-grid-row-over");
53724 onRowOut : function(e, t){
53726 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
53727 this.getRowComposite(row).removeClass("x-grid-row-over");
53731 renderHeaders : function(){
53733 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
53734 var cb = [], lb = [], sb = [], lsb = [], p = {};
53735 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53736 p.cellId = "x-grid-hd-0-" + i;
53737 p.splitId = "x-grid-csplit-0-" + i;
53738 p.id = cm.getColumnId(i);
53739 p.title = cm.getColumnTooltip(i) || "";
53740 p.value = cm.getColumnHeader(i) || "";
53741 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
53742 if(!cm.isLocked(i)){
53743 cb[cb.length] = ct.apply(p);
53744 sb[sb.length] = st.apply(p);
53746 lb[lb.length] = ct.apply(p);
53747 lsb[lsb.length] = st.apply(p);
53750 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
53751 ht.apply({cells: cb.join(""), splits:sb.join("")})];
53754 updateHeaders : function(){
53755 var html = this.renderHeaders();
53756 this.lockedHd.update(html[0]);
53757 this.mainHd.update(html[1]);
53761 * Focuses the specified row.
53762 * @param {Number} row The row index
53764 focusRow : function(row)
53766 //Roo.log('GridView.focusRow');
53767 var x = this.scroller.dom.scrollLeft;
53768 this.focusCell(row, 0, false);
53769 this.scroller.dom.scrollLeft = x;
53773 * Focuses the specified cell.
53774 * @param {Number} row The row index
53775 * @param {Number} col The column index
53776 * @param {Boolean} hscroll false to disable horizontal scrolling
53778 focusCell : function(row, col, hscroll)
53780 //Roo.log('GridView.focusCell');
53781 var el = this.ensureVisible(row, col, hscroll);
53782 this.focusEl.alignTo(el, "tl-tl");
53784 this.focusEl.focus();
53786 this.focusEl.focus.defer(1, this.focusEl);
53791 * Scrolls the specified cell into view
53792 * @param {Number} row The row index
53793 * @param {Number} col The column index
53794 * @param {Boolean} hscroll false to disable horizontal scrolling
53796 ensureVisible : function(row, col, hscroll)
53798 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
53799 //return null; //disable for testing.
53800 if(typeof row != "number"){
53801 row = row.rowIndex;
53803 if(row < 0 && row >= this.ds.getCount()){
53806 col = (col !== undefined ? col : 0);
53807 var cm = this.grid.colModel;
53808 while(cm.isHidden(col)){
53812 var el = this.getCell(row, col);
53816 var c = this.scroller.dom;
53818 var ctop = parseInt(el.offsetTop, 10);
53819 var cleft = parseInt(el.offsetLeft, 10);
53820 var cbot = ctop + el.offsetHeight;
53821 var cright = cleft + el.offsetWidth;
53823 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
53824 var stop = parseInt(c.scrollTop, 10);
53825 var sleft = parseInt(c.scrollLeft, 10);
53826 var sbot = stop + ch;
53827 var sright = sleft + c.clientWidth;
53829 Roo.log('GridView.ensureVisible:' +
53831 ' c.clientHeight:' + c.clientHeight +
53832 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
53840 c.scrollTop = ctop;
53841 //Roo.log("set scrolltop to ctop DISABLE?");
53842 }else if(cbot > sbot){
53843 //Roo.log("set scrolltop to cbot-ch");
53844 c.scrollTop = cbot-ch;
53847 if(hscroll !== false){
53849 c.scrollLeft = cleft;
53850 }else if(cright > sright){
53851 c.scrollLeft = cright-c.clientWidth;
53858 updateColumns : function(){
53859 this.grid.stopEditing();
53860 var cm = this.grid.colModel, colIds = this.getColumnIds();
53861 //var totalWidth = cm.getTotalWidth();
53863 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53864 //if(cm.isHidden(i)) continue;
53865 var w = cm.getColumnWidth(i);
53866 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53867 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
53869 this.updateSplitters();
53872 generateRules : function(cm){
53873 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
53874 Roo.util.CSS.removeStyleSheet(rulesId);
53875 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53876 var cid = cm.getColumnId(i);
53878 if(cm.config[i].align){
53879 align = 'text-align:'+cm.config[i].align+';';
53882 if(cm.isHidden(i)){
53883 hidden = 'display:none;';
53885 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
53887 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
53888 this.hdSelector, cid, " {\n", align, width, "}\n",
53889 this.tdSelector, cid, " {\n",hidden,"\n}\n",
53890 this.splitSelector, cid, " {\n", hidden , "\n}\n");
53892 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
53895 updateSplitters : function(){
53896 var cm = this.cm, s = this.getSplitters();
53897 if(s){ // splitters not created yet
53898 var pos = 0, locked = true;
53899 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
53900 if(cm.isHidden(i)) continue;
53901 var w = cm.getColumnWidth(i); // make sure it's a number
53902 if(!cm.isLocked(i) && locked){
53907 s[i].style.left = (pos-this.splitOffset) + "px";
53912 handleHiddenChange : function(colModel, colIndex, hidden){
53914 this.hideColumn(colIndex);
53916 this.unhideColumn(colIndex);
53920 hideColumn : function(colIndex){
53921 var cid = this.getColumnId(colIndex);
53922 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
53923 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
53925 this.updateHeaders();
53927 this.updateSplitters();
53931 unhideColumn : function(colIndex){
53932 var cid = this.getColumnId(colIndex);
53933 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
53934 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
53937 this.updateHeaders();
53939 this.updateSplitters();
53943 insertRows : function(dm, firstRow, lastRow, isUpdate){
53944 if(firstRow == 0 && lastRow == dm.getCount()-1){
53948 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
53950 var s = this.getScrollState();
53951 var markup = this.renderRows(firstRow, lastRow);
53952 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
53953 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
53954 this.restoreScroll(s);
53956 this.fireEvent("rowsinserted", this, firstRow, lastRow);
53957 this.syncRowHeights(firstRow, lastRow);
53958 this.stripeRows(firstRow);
53964 bufferRows : function(markup, target, index){
53965 var before = null, trows = target.rows, tbody = target.tBodies[0];
53966 if(index < trows.length){
53967 before = trows[index];
53969 var b = document.createElement("div");
53970 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
53971 var rows = b.firstChild.rows;
53972 for(var i = 0, len = rows.length; i < len; i++){
53974 tbody.insertBefore(rows[0], before);
53976 tbody.appendChild(rows[0]);
53983 deleteRows : function(dm, firstRow, lastRow){
53984 if(dm.getRowCount()<1){
53985 this.fireEvent("beforerefresh", this);
53986 this.mainBody.update("");
53987 this.lockedBody.update("");
53988 this.fireEvent("refresh", this);
53990 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
53991 var bt = this.getBodyTable();
53992 var tbody = bt.firstChild;
53993 var rows = bt.rows;
53994 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
53995 tbody.removeChild(rows[firstRow]);
53997 this.stripeRows(firstRow);
53998 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
54002 updateRows : function(dataSource, firstRow, lastRow){
54003 var s = this.getScrollState();
54005 this.restoreScroll(s);
54008 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
54012 this.updateHeaderSortState();
54015 getScrollState : function(){
54017 var sb = this.scroller.dom;
54018 return {left: sb.scrollLeft, top: sb.scrollTop};
54021 stripeRows : function(startRow){
54022 if(!this.grid.stripeRows || this.ds.getCount() < 1){
54025 startRow = startRow || 0;
54026 var rows = this.getBodyTable().rows;
54027 var lrows = this.getLockedTable().rows;
54028 var cls = ' x-grid-row-alt ';
54029 for(var i = startRow, len = rows.length; i < len; i++){
54030 var row = rows[i], lrow = lrows[i];
54031 var isAlt = ((i+1) % 2 == 0);
54032 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
54033 if(isAlt == hasAlt){
54037 row.className += " x-grid-row-alt";
54039 row.className = row.className.replace("x-grid-row-alt", "");
54042 lrow.className = row.className;
54047 restoreScroll : function(state){
54048 //Roo.log('GridView.restoreScroll');
54049 var sb = this.scroller.dom;
54050 sb.scrollLeft = state.left;
54051 sb.scrollTop = state.top;
54055 syncScroll : function(){
54056 //Roo.log('GridView.syncScroll');
54057 var sb = this.scroller.dom;
54058 var sh = this.mainHd.dom;
54059 var bs = this.mainBody.dom;
54060 var lv = this.lockedBody.dom;
54061 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
54062 lv.scrollTop = bs.scrollTop = sb.scrollTop;
54065 handleScroll : function(e){
54067 var sb = this.scroller.dom;
54068 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
54072 handleWheel : function(e){
54073 var d = e.getWheelDelta();
54074 this.scroller.dom.scrollTop -= d*22;
54075 // set this here to prevent jumpy scrolling on large tables
54076 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
54080 renderRows : function(startRow, endRow){
54081 // pull in all the crap needed to render rows
54082 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
54083 var colCount = cm.getColumnCount();
54085 if(ds.getCount() < 1){
54089 // build a map for all the columns
54091 for(var i = 0; i < colCount; i++){
54092 var name = cm.getDataIndex(i);
54094 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
54095 renderer : cm.getRenderer(i),
54096 id : cm.getColumnId(i),
54097 locked : cm.isLocked(i)
54101 startRow = startRow || 0;
54102 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
54104 // records to render
54105 var rs = ds.getRange(startRow, endRow);
54107 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
54110 // As much as I hate to duplicate code, this was branched because FireFox really hates
54111 // [].join("") on strings. The performance difference was substantial enough to
54112 // branch this function
54113 doRender : Roo.isGecko ?
54114 function(cs, rs, ds, startRow, colCount, stripe){
54115 var ts = this.templates, ct = ts.cell, rt = ts.row;
54117 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54119 var hasListener = this.grid.hasListener('rowclass');
54121 for(var j = 0, len = rs.length; j < len; j++){
54122 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
54123 for(var i = 0; i < colCount; i++){
54125 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54127 p.css = p.attr = "";
54128 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54129 if(p.value == undefined || p.value === "") p.value = " ";
54130 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54131 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54133 var markup = ct.apply(p);
54141 if(stripe && ((rowIndex+1) % 2 == 0)){
54142 alt.push("x-grid-row-alt")
54145 alt.push( " x-grid-dirty-row");
54148 if(this.getRowClass){
54149 alt.push(this.getRowClass(r, rowIndex));
54155 rowIndex : rowIndex,
54158 this.grid.fireEvent('rowclass', this, rowcfg);
54159 alt.push(rowcfg.rowClass);
54161 rp.alt = alt.join(" ");
54162 lbuf+= rt.apply(rp);
54164 buf+= rt.apply(rp);
54166 return [lbuf, buf];
54168 function(cs, rs, ds, startRow, colCount, stripe){
54169 var ts = this.templates, ct = ts.cell, rt = ts.row;
54171 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
54172 var hasListener = this.grid.hasListener('rowclass');
54175 for(var j = 0, len = rs.length; j < len; j++){
54176 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
54177 for(var i = 0; i < colCount; i++){
54179 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
54181 p.css = p.attr = "";
54182 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
54183 if(p.value == undefined || p.value === "") p.value = " ";
54184 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
54185 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
54188 var markup = ct.apply(p);
54190 cb[cb.length] = markup;
54192 lcb[lcb.length] = markup;
54196 if(stripe && ((rowIndex+1) % 2 == 0)){
54197 alt.push( "x-grid-row-alt");
54200 alt.push(" x-grid-dirty-row");
54203 if(this.getRowClass){
54204 alt.push( this.getRowClass(r, rowIndex));
54210 rowIndex : rowIndex,
54213 this.grid.fireEvent('rowclass', this, rowcfg);
54214 alt.push(rowcfg.rowClass);
54216 rp.alt = alt.join(" ");
54217 rp.cells = lcb.join("");
54218 lbuf[lbuf.length] = rt.apply(rp);
54219 rp.cells = cb.join("");
54220 buf[buf.length] = rt.apply(rp);
54222 return [lbuf.join(""), buf.join("")];
54225 renderBody : function(){
54226 var markup = this.renderRows();
54227 var bt = this.templates.body;
54228 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
54232 * Refreshes the grid
54233 * @param {Boolean} headersToo
54235 refresh : function(headersToo){
54236 this.fireEvent("beforerefresh", this);
54237 this.grid.stopEditing();
54238 var result = this.renderBody();
54239 this.lockedBody.update(result[0]);
54240 this.mainBody.update(result[1]);
54241 if(headersToo === true){
54242 this.updateHeaders();
54243 this.updateColumns();
54244 this.updateSplitters();
54245 this.updateHeaderSortState();
54247 this.syncRowHeights();
54249 this.fireEvent("refresh", this);
54252 handleColumnMove : function(cm, oldIndex, newIndex){
54253 this.indexMap = null;
54254 var s = this.getScrollState();
54255 this.refresh(true);
54256 this.restoreScroll(s);
54257 this.afterMove(newIndex);
54260 afterMove : function(colIndex){
54261 if(this.enableMoveAnim && Roo.enableFx){
54262 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
54264 // if multisort - fix sortOrder, and reload..
54265 if (this.grid.dataSource.multiSort) {
54266 // the we can call sort again..
54267 var dm = this.grid.dataSource;
54268 var cm = this.grid.colModel;
54270 for(var i = 0; i < cm.config.length; i++ ) {
54272 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
54273 continue; // dont' bother, it's not in sort list or being set.
54276 so.push(cm.config[i].dataIndex);
54279 dm.load(dm.lastOptions);
54286 updateCell : function(dm, rowIndex, dataIndex){
54287 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
54288 if(typeof colIndex == "undefined"){ // not present in grid
54291 var cm = this.grid.colModel;
54292 var cell = this.getCell(rowIndex, colIndex);
54293 var cellText = this.getCellText(rowIndex, colIndex);
54296 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
54297 id : cm.getColumnId(colIndex),
54298 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
54300 var renderer = cm.getRenderer(colIndex);
54301 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
54302 if(typeof val == "undefined" || val === "") val = " ";
54303 cellText.innerHTML = val;
54304 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
54305 this.syncRowHeights(rowIndex, rowIndex);
54308 calcColumnWidth : function(colIndex, maxRowsToMeasure){
54310 if(this.grid.autoSizeHeaders){
54311 var h = this.getHeaderCellMeasure(colIndex);
54312 maxWidth = Math.max(maxWidth, h.scrollWidth);
54315 if(this.cm.isLocked(colIndex)){
54316 tb = this.getLockedTable();
54319 tb = this.getBodyTable();
54320 index = colIndex - this.cm.getLockedCount();
54323 var rows = tb.rows;
54324 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
54325 for(var i = 0; i < stopIndex; i++){
54326 var cell = rows[i].childNodes[index].firstChild;
54327 maxWidth = Math.max(maxWidth, cell.scrollWidth);
54330 return maxWidth + /*margin for error in IE*/ 5;
54333 * Autofit a column to its content.
54334 * @param {Number} colIndex
54335 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
54337 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
54338 if(this.cm.isHidden(colIndex)){
54339 return; // can't calc a hidden column
54342 var cid = this.cm.getColumnId(colIndex);
54343 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
54344 if(this.grid.autoSizeHeaders){
54345 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
54348 var newWidth = this.calcColumnWidth(colIndex);
54349 this.cm.setColumnWidth(colIndex,
54350 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
54351 if(!suppressEvent){
54352 this.grid.fireEvent("columnresize", colIndex, newWidth);
54357 * Autofits all columns to their content and then expands to fit any extra space in the grid
54359 autoSizeColumns : function(){
54360 var cm = this.grid.colModel;
54361 var colCount = cm.getColumnCount();
54362 for(var i = 0; i < colCount; i++){
54363 this.autoSizeColumn(i, true, true);
54365 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
54368 this.updateColumns();
54374 * Autofits all columns to the grid's width proportionate with their current size
54375 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
54377 fitColumns : function(reserveScrollSpace){
54378 var cm = this.grid.colModel;
54379 var colCount = cm.getColumnCount();
54383 for (i = 0; i < colCount; i++){
54384 if(!cm.isHidden(i) && !cm.isFixed(i)){
54385 w = cm.getColumnWidth(i);
54391 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
54392 if(reserveScrollSpace){
54395 var frac = (avail - cm.getTotalWidth())/width;
54396 while (cols.length){
54399 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
54401 this.updateColumns();
54405 onRowSelect : function(rowIndex){
54406 var row = this.getRowComposite(rowIndex);
54407 row.addClass("x-grid-row-selected");
54410 onRowDeselect : function(rowIndex){
54411 var row = this.getRowComposite(rowIndex);
54412 row.removeClass("x-grid-row-selected");
54415 onCellSelect : function(row, col){
54416 var cell = this.getCell(row, col);
54418 Roo.fly(cell).addClass("x-grid-cell-selected");
54422 onCellDeselect : function(row, col){
54423 var cell = this.getCell(row, col);
54425 Roo.fly(cell).removeClass("x-grid-cell-selected");
54429 updateHeaderSortState : function(){
54431 // sort state can be single { field: xxx, direction : yyy}
54432 // or { xxx=>ASC , yyy : DESC ..... }
54435 if (!this.ds.multiSort) {
54436 var state = this.ds.getSortState();
54440 mstate[state.field] = state.direction;
54441 // FIXME... - this is not used here.. but might be elsewhere..
54442 this.sortState = state;
54445 mstate = this.ds.sortToggle;
54447 //remove existing sort classes..
54449 var sc = this.sortClasses;
54450 var hds = this.el.select(this.headerSelector).removeClass(sc);
54452 for(var f in mstate) {
54454 var sortColumn = this.cm.findColumnIndex(f);
54456 if(sortColumn != -1){
54457 var sortDir = mstate[f];
54458 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
54467 handleHeaderClick : function(g, index,e){
54469 Roo.log("header click");
54472 // touch events on header are handled by context
54473 this.handleHdCtx(g,index,e);
54478 if(this.headersDisabled){
54481 var dm = g.dataSource, cm = g.colModel;
54482 if(!cm.isSortable(index)){
54487 if (dm.multiSort) {
54488 // update the sortOrder
54490 for(var i = 0; i < cm.config.length; i++ ) {
54492 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
54493 continue; // dont' bother, it's not in sort list or being set.
54496 so.push(cm.config[i].dataIndex);
54502 dm.sort(cm.getDataIndex(index));
54506 destroy : function(){
54508 this.colMenu.removeAll();
54509 Roo.menu.MenuMgr.unregister(this.colMenu);
54510 this.colMenu.getEl().remove();
54511 delete this.colMenu;
54514 this.hmenu.removeAll();
54515 Roo.menu.MenuMgr.unregister(this.hmenu);
54516 this.hmenu.getEl().remove();
54519 if(this.grid.enableColumnMove){
54520 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54522 for(var dd in dds){
54523 if(!dds[dd].config.isTarget && dds[dd].dragElId){
54524 var elid = dds[dd].dragElId;
54526 Roo.get(elid).remove();
54527 } else if(dds[dd].config.isTarget){
54528 dds[dd].proxyTop.remove();
54529 dds[dd].proxyBottom.remove();
54532 if(Roo.dd.DDM.locationCache[dd]){
54533 delete Roo.dd.DDM.locationCache[dd];
54536 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
54539 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
54540 this.bind(null, null);
54541 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
54544 handleLockChange : function(){
54545 this.refresh(true);
54548 onDenyColumnLock : function(){
54552 onDenyColumnHide : function(){
54556 handleHdMenuClick : function(item){
54557 var index = this.hdCtxIndex;
54558 var cm = this.cm, ds = this.ds;
54561 ds.sort(cm.getDataIndex(index), "ASC");
54564 ds.sort(cm.getDataIndex(index), "DESC");
54567 var lc = cm.getLockedCount();
54568 if(cm.getColumnCount(true) <= lc+1){
54569 this.onDenyColumnLock();
54573 cm.setLocked(index, true, true);
54574 cm.moveColumn(index, lc);
54575 this.grid.fireEvent("columnmove", index, lc);
54577 cm.setLocked(index, true);
54581 var lc = cm.getLockedCount();
54582 if((lc-1) != index){
54583 cm.setLocked(index, false, true);
54584 cm.moveColumn(index, lc-1);
54585 this.grid.fireEvent("columnmove", index, lc-1);
54587 cm.setLocked(index, false);
54590 case 'wider': // used to expand cols on touch..
54592 var cw = cm.getColumnWidth(index);
54593 cw += (item.id == 'wider' ? 1 : -1) * 50;
54594 cw = Math.max(0, cw);
54595 cw = Math.min(cw,4000);
54596 cm.setColumnWidth(index, cw);
54600 index = cm.getIndexById(item.id.substr(4));
54602 if(item.checked && cm.getColumnCount(true) <= 1){
54603 this.onDenyColumnHide();
54606 cm.setHidden(index, item.checked);
54612 beforeColMenuShow : function(){
54613 var cm = this.cm, colCount = cm.getColumnCount();
54614 this.colMenu.removeAll();
54615 for(var i = 0; i < colCount; i++){
54616 this.colMenu.add(new Roo.menu.CheckItem({
54617 id: "col-"+cm.getColumnId(i),
54618 text: cm.getColumnHeader(i),
54619 checked: !cm.isHidden(i),
54625 handleHdCtx : function(g, index, e){
54627 var hd = this.getHeaderCell(index);
54628 this.hdCtxIndex = index;
54629 var ms = this.hmenu.items, cm = this.cm;
54630 ms.get("asc").setDisabled(!cm.isSortable(index));
54631 ms.get("desc").setDisabled(!cm.isSortable(index));
54632 if(this.grid.enableColLock !== false){
54633 ms.get("lock").setDisabled(cm.isLocked(index));
54634 ms.get("unlock").setDisabled(!cm.isLocked(index));
54636 this.hmenu.show(hd, "tl-bl");
54639 handleHdOver : function(e){
54640 var hd = this.findHeaderCell(e.getTarget());
54641 if(hd && !this.headersDisabled){
54642 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
54643 this.fly(hd).addClass("x-grid-hd-over");
54648 handleHdOut : function(e){
54649 var hd = this.findHeaderCell(e.getTarget());
54651 this.fly(hd).removeClass("x-grid-hd-over");
54655 handleSplitDblClick : function(e, t){
54656 var i = this.getCellIndex(t);
54657 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
54658 this.autoSizeColumn(i, true);
54663 render : function(){
54666 var colCount = cm.getColumnCount();
54668 if(this.grid.monitorWindowResize === true){
54669 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
54671 var header = this.renderHeaders();
54672 var body = this.templates.body.apply({rows:""});
54673 var html = this.templates.master.apply({
54676 lockedHeader: header[0],
54680 //this.updateColumns();
54682 this.grid.getGridEl().dom.innerHTML = html;
54684 this.initElements();
54686 // a kludge to fix the random scolling effect in webkit
54687 this.el.on("scroll", function() {
54688 this.el.dom.scrollTop=0; // hopefully not recursive..
54691 this.scroller.on("scroll", this.handleScroll, this);
54692 this.lockedBody.on("mousewheel", this.handleWheel, this);
54693 this.mainBody.on("mousewheel", this.handleWheel, this);
54695 this.mainHd.on("mouseover", this.handleHdOver, this);
54696 this.mainHd.on("mouseout", this.handleHdOut, this);
54697 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
54698 {delegate: "."+this.splitClass});
54700 this.lockedHd.on("mouseover", this.handleHdOver, this);
54701 this.lockedHd.on("mouseout", this.handleHdOut, this);
54702 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
54703 {delegate: "."+this.splitClass});
54705 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
54706 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54709 this.updateSplitters();
54711 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
54712 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54713 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
54716 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
54717 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
54719 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
54720 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
54722 if(this.grid.enableColLock !== false){
54723 this.hmenu.add('-',
54724 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
54725 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
54729 this.hmenu.add('-',
54730 {id:"wider", text: this.columnsWiderText},
54731 {id:"narrow", text: this.columnsNarrowText }
54737 if(this.grid.enableColumnHide !== false){
54739 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
54740 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
54741 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
54743 this.hmenu.add('-',
54744 {id:"columns", text: this.columnsText, menu: this.colMenu}
54747 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
54749 this.grid.on("headercontextmenu", this.handleHdCtx, this);
54752 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
54753 this.dd = new Roo.grid.GridDragZone(this.grid, {
54754 ddGroup : this.grid.ddGroup || 'GridDD'
54760 for(var i = 0; i < colCount; i++){
54761 if(cm.isHidden(i)){
54762 this.hideColumn(i);
54764 if(cm.config[i].align){
54765 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
54766 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
54770 this.updateHeaderSortState();
54772 this.beforeInitialResize();
54775 // two part rendering gives faster view to the user
54776 this.renderPhase2.defer(1, this);
54779 renderPhase2 : function(){
54780 // render the rows now
54782 if(this.grid.autoSizeColumns){
54783 this.autoSizeColumns();
54787 beforeInitialResize : function(){
54791 onColumnSplitterMoved : function(i, w){
54792 this.userResized = true;
54793 var cm = this.grid.colModel;
54794 cm.setColumnWidth(i, w, true);
54795 var cid = cm.getColumnId(i);
54796 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54797 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
54798 this.updateSplitters();
54800 this.grid.fireEvent("columnresize", i, w);
54803 syncRowHeights : function(startIndex, endIndex){
54804 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
54805 startIndex = startIndex || 0;
54806 var mrows = this.getBodyTable().rows;
54807 var lrows = this.getLockedTable().rows;
54808 var len = mrows.length-1;
54809 endIndex = Math.min(endIndex || len, len);
54810 for(var i = startIndex; i <= endIndex; i++){
54811 var m = mrows[i], l = lrows[i];
54812 var h = Math.max(m.offsetHeight, l.offsetHeight);
54813 m.style.height = l.style.height = h + "px";
54818 layout : function(initialRender, is2ndPass){
54820 var auto = g.autoHeight;
54821 var scrollOffset = 16;
54822 var c = g.getGridEl(), cm = this.cm,
54823 expandCol = g.autoExpandColumn,
54825 //c.beginMeasure();
54827 if(!c.dom.offsetWidth){ // display:none?
54829 this.lockedWrap.show();
54830 this.mainWrap.show();
54835 var hasLock = this.cm.isLocked(0);
54837 var tbh = this.headerPanel.getHeight();
54838 var bbh = this.footerPanel.getHeight();
54841 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
54842 var newHeight = ch + c.getBorderWidth("tb");
54844 newHeight = Math.min(g.maxHeight, newHeight);
54846 c.setHeight(newHeight);
54850 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
54853 var s = this.scroller;
54855 var csize = c.getSize(true);
54857 this.el.setSize(csize.width, csize.height);
54859 this.headerPanel.setWidth(csize.width);
54860 this.footerPanel.setWidth(csize.width);
54862 var hdHeight = this.mainHd.getHeight();
54863 var vw = csize.width;
54864 var vh = csize.height - (tbh + bbh);
54868 var bt = this.getBodyTable();
54869 var ltWidth = hasLock ?
54870 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
54872 var scrollHeight = bt.offsetHeight;
54873 var scrollWidth = ltWidth + bt.offsetWidth;
54874 var vscroll = false, hscroll = false;
54876 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
54878 var lw = this.lockedWrap, mw = this.mainWrap;
54879 var lb = this.lockedBody, mb = this.mainBody;
54881 setTimeout(function(){
54882 var t = s.dom.offsetTop;
54883 var w = s.dom.clientWidth,
54884 h = s.dom.clientHeight;
54887 lw.setSize(ltWidth, h);
54889 mw.setLeftTop(ltWidth, t);
54890 mw.setSize(w-ltWidth, h);
54892 lb.setHeight(h-hdHeight);
54893 mb.setHeight(h-hdHeight);
54895 if(is2ndPass !== true && !gv.userResized && expandCol){
54896 // high speed resize without full column calculation
54898 var ci = cm.getIndexById(expandCol);
54900 ci = cm.findColumnIndex(expandCol);
54902 ci = Math.max(0, ci); // make sure it's got at least the first col.
54903 var expandId = cm.getColumnId(ci);
54904 var tw = cm.getTotalWidth(false);
54905 var currentWidth = cm.getColumnWidth(ci);
54906 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
54907 if(currentWidth != cw){
54908 cm.setColumnWidth(ci, cw, true);
54909 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54910 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
54911 gv.updateSplitters();
54912 gv.layout(false, true);
54924 onWindowResize : function(){
54925 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
54931 appendFooter : function(parentEl){
54935 sortAscText : "Sort Ascending",
54936 sortDescText : "Sort Descending",
54937 lockText : "Lock Column",
54938 unlockText : "Unlock Column",
54939 columnsText : "Columns",
54941 columnsWiderText : "Wider",
54942 columnsNarrowText : "Thinner"
54946 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
54947 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
54948 this.proxy.el.addClass('x-grid3-col-dd');
54951 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
54952 handleMouseDown : function(e){
54956 callHandleMouseDown : function(e){
54957 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
54962 * Ext JS Library 1.1.1
54963 * Copyright(c) 2006-2007, Ext JS, LLC.
54965 * Originally Released Under LGPL - original licence link has changed is not relivant.
54968 * <script type="text/javascript">
54972 // This is a support class used internally by the Grid components
54973 Roo.grid.SplitDragZone = function(grid, hd, hd2){
54975 this.view = grid.getView();
54976 this.proxy = this.view.resizeProxy;
54977 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
54978 "gridSplitters" + this.grid.getGridEl().id, {
54979 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
54981 this.setHandleElId(Roo.id(hd));
54982 this.setOuterHandleElId(Roo.id(hd2));
54983 this.scroll = false;
54985 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
54986 fly: Roo.Element.fly,
54988 b4StartDrag : function(x, y){
54989 this.view.headersDisabled = true;
54990 this.proxy.setHeight(this.view.mainWrap.getHeight());
54991 var w = this.cm.getColumnWidth(this.cellIndex);
54992 var minw = Math.max(w-this.grid.minColumnWidth, 0);
54993 this.resetConstraints();
54994 this.setXConstraint(minw, 1000);
54995 this.setYConstraint(0, 0);
54996 this.minX = x - minw;
54997 this.maxX = x + 1000;
54999 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
55003 handleMouseDown : function(e){
55004 ev = Roo.EventObject.setEvent(e);
55005 var t = this.fly(ev.getTarget());
55006 if(t.hasClass("x-grid-split")){
55007 this.cellIndex = this.view.getCellIndex(t.dom);
55008 this.split = t.dom;
55009 this.cm = this.grid.colModel;
55010 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
55011 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
55016 endDrag : function(e){
55017 this.view.headersDisabled = false;
55018 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
55019 var diff = endX - this.startPos;
55020 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
55023 autoOffset : function(){
55024 this.setDelta(0,0);
55028 * Ext JS Library 1.1.1
55029 * Copyright(c) 2006-2007, Ext JS, LLC.
55031 * Originally Released Under LGPL - original licence link has changed is not relivant.
55034 * <script type="text/javascript">
55038 // This is a support class used internally by the Grid components
55039 Roo.grid.GridDragZone = function(grid, config){
55040 this.view = grid.getView();
55041 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
55042 if(this.view.lockedBody){
55043 this.setHandleElId(Roo.id(this.view.mainBody.dom));
55044 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
55046 this.scroll = false;
55048 this.ddel = document.createElement('div');
55049 this.ddel.className = 'x-grid-dd-wrap';
55052 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
55053 ddGroup : "GridDD",
55055 getDragData : function(e){
55056 var t = Roo.lib.Event.getTarget(e);
55057 var rowIndex = this.view.findRowIndex(t);
55058 var sm = this.grid.selModel;
55060 //Roo.log(rowIndex);
55062 if (sm.getSelectedCell) {
55063 // cell selection..
55064 if (!sm.getSelectedCell()) {
55067 if (rowIndex != sm.getSelectedCell()[0]) {
55073 if(rowIndex !== false){
55078 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
55080 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
55083 if (e.hasModifier()){
55084 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
55087 Roo.log("getDragData");
55092 rowIndex: rowIndex,
55093 selections:sm.getSelections ? sm.getSelections() : (
55094 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
55101 onInitDrag : function(e){
55102 var data = this.dragData;
55103 this.ddel.innerHTML = this.grid.getDragDropText();
55104 this.proxy.update(this.ddel);
55105 // fire start drag?
55108 afterRepair : function(){
55109 this.dragging = false;
55112 getRepairXY : function(e, data){
55116 onEndDrag : function(data, e){
55120 onValidDrop : function(dd, e, id){
55125 beforeInvalidDrop : function(e, id){
55130 * Ext JS Library 1.1.1
55131 * Copyright(c) 2006-2007, Ext JS, LLC.
55133 * Originally Released Under LGPL - original licence link has changed is not relivant.
55136 * <script type="text/javascript">
55141 * @class Roo.grid.ColumnModel
55142 * @extends Roo.util.Observable
55143 * This is the default implementation of a ColumnModel used by the Grid. It defines
55144 * the columns in the grid.
55147 var colModel = new Roo.grid.ColumnModel([
55148 {header: "Ticker", width: 60, sortable: true, locked: true},
55149 {header: "Company Name", width: 150, sortable: true},
55150 {header: "Market Cap.", width: 100, sortable: true},
55151 {header: "$ Sales", width: 100, sortable: true, renderer: money},
55152 {header: "Employees", width: 100, sortable: true, resizable: false}
55157 * The config options listed for this class are options which may appear in each
55158 * individual column definition.
55159 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
55161 * @param {Object} config An Array of column config objects. See this class's
55162 * config objects for details.
55164 Roo.grid.ColumnModel = function(config){
55166 * The config passed into the constructor
55168 this.config = config;
55171 // if no id, create one
55172 // if the column does not have a dataIndex mapping,
55173 // map it to the order it is in the config
55174 for(var i = 0, len = config.length; i < len; i++){
55176 if(typeof c.dataIndex == "undefined"){
55179 if(typeof c.renderer == "string"){
55180 c.renderer = Roo.util.Format[c.renderer];
55182 if(typeof c.id == "undefined"){
55185 if(c.editor && c.editor.xtype){
55186 c.editor = Roo.factory(c.editor, Roo.grid);
55188 if(c.editor && c.editor.isFormField){
55189 c.editor = new Roo.grid.GridEditor(c.editor);
55191 this.lookup[c.id] = c;
55195 * The width of columns which have no width specified (defaults to 100)
55198 this.defaultWidth = 100;
55201 * Default sortable of columns which have no sortable specified (defaults to false)
55204 this.defaultSortable = false;
55208 * @event widthchange
55209 * Fires when the width of a column changes.
55210 * @param {ColumnModel} this
55211 * @param {Number} columnIndex The column index
55212 * @param {Number} newWidth The new width
55214 "widthchange": true,
55216 * @event headerchange
55217 * Fires when the text of a header changes.
55218 * @param {ColumnModel} this
55219 * @param {Number} columnIndex The column index
55220 * @param {Number} newText The new header text
55222 "headerchange": true,
55224 * @event hiddenchange
55225 * Fires when a column is hidden or "unhidden".
55226 * @param {ColumnModel} this
55227 * @param {Number} columnIndex The column index
55228 * @param {Boolean} hidden true if hidden, false otherwise
55230 "hiddenchange": true,
55232 * @event columnmoved
55233 * Fires when a column is moved.
55234 * @param {ColumnModel} this
55235 * @param {Number} oldIndex
55236 * @param {Number} newIndex
55238 "columnmoved" : true,
55240 * @event columlockchange
55241 * Fires when a column's locked state is changed
55242 * @param {ColumnModel} this
55243 * @param {Number} colIndex
55244 * @param {Boolean} locked true if locked
55246 "columnlockchange" : true
55248 Roo.grid.ColumnModel.superclass.constructor.call(this);
55250 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
55252 * @cfg {String} header The header text to display in the Grid view.
55255 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
55256 * {@link Roo.data.Record} definition from which to draw the column's value. If not
55257 * specified, the column's index is used as an index into the Record's data Array.
55260 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
55261 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
55264 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
55265 * Defaults to the value of the {@link #defaultSortable} property.
55266 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
55269 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
55272 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
55275 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
55278 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
55281 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
55282 * given the cell's data value. See {@link #setRenderer}. If not specified, the
55283 * default renderer uses the raw data value. If an object is returned (bootstrap only)
55284 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
55287 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
55290 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
55293 * @cfg {String} cursor (Optional)
55296 * @cfg {String} tooltip (Optional)
55299 * Returns the id of the column at the specified index.
55300 * @param {Number} index The column index
55301 * @return {String} the id
55303 getColumnId : function(index){
55304 return this.config[index].id;
55308 * Returns the column for a specified id.
55309 * @param {String} id The column id
55310 * @return {Object} the column
55312 getColumnById : function(id){
55313 return this.lookup[id];
55318 * Returns the column for a specified dataIndex.
55319 * @param {String} dataIndex The column dataIndex
55320 * @return {Object|Boolean} the column or false if not found
55322 getColumnByDataIndex: function(dataIndex){
55323 var index = this.findColumnIndex(dataIndex);
55324 return index > -1 ? this.config[index] : false;
55328 * Returns the index for a specified column id.
55329 * @param {String} id The column id
55330 * @return {Number} the index, or -1 if not found
55332 getIndexById : function(id){
55333 for(var i = 0, len = this.config.length; i < len; i++){
55334 if(this.config[i].id == id){
55342 * Returns the index for a specified column dataIndex.
55343 * @param {String} dataIndex The column dataIndex
55344 * @return {Number} the index, or -1 if not found
55347 findColumnIndex : function(dataIndex){
55348 for(var i = 0, len = this.config.length; i < len; i++){
55349 if(this.config[i].dataIndex == dataIndex){
55357 moveColumn : function(oldIndex, newIndex){
55358 var c = this.config[oldIndex];
55359 this.config.splice(oldIndex, 1);
55360 this.config.splice(newIndex, 0, c);
55361 this.dataMap = null;
55362 this.fireEvent("columnmoved", this, oldIndex, newIndex);
55365 isLocked : function(colIndex){
55366 return this.config[colIndex].locked === true;
55369 setLocked : function(colIndex, value, suppressEvent){
55370 if(this.isLocked(colIndex) == value){
55373 this.config[colIndex].locked = value;
55374 if(!suppressEvent){
55375 this.fireEvent("columnlockchange", this, colIndex, value);
55379 getTotalLockedWidth : function(){
55380 var totalWidth = 0;
55381 for(var i = 0; i < this.config.length; i++){
55382 if(this.isLocked(i) && !this.isHidden(i)){
55383 this.totalWidth += this.getColumnWidth(i);
55389 getLockedCount : function(){
55390 for(var i = 0, len = this.config.length; i < len; i++){
55391 if(!this.isLocked(i)){
55398 * Returns the number of columns.
55401 getColumnCount : function(visibleOnly){
55402 if(visibleOnly === true){
55404 for(var i = 0, len = this.config.length; i < len; i++){
55405 if(!this.isHidden(i)){
55411 return this.config.length;
55415 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
55416 * @param {Function} fn
55417 * @param {Object} scope (optional)
55418 * @return {Array} result
55420 getColumnsBy : function(fn, scope){
55422 for(var i = 0, len = this.config.length; i < len; i++){
55423 var c = this.config[i];
55424 if(fn.call(scope||this, c, i) === true){
55432 * Returns true if the specified column is sortable.
55433 * @param {Number} col The column index
55434 * @return {Boolean}
55436 isSortable : function(col){
55437 if(typeof this.config[col].sortable == "undefined"){
55438 return this.defaultSortable;
55440 return this.config[col].sortable;
55444 * Returns the rendering (formatting) function defined for the column.
55445 * @param {Number} col The column index.
55446 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
55448 getRenderer : function(col){
55449 if(!this.config[col].renderer){
55450 return Roo.grid.ColumnModel.defaultRenderer;
55452 return this.config[col].renderer;
55456 * Sets the rendering (formatting) function for a column.
55457 * @param {Number} col The column index
55458 * @param {Function} fn The function to use to process the cell's raw data
55459 * to return HTML markup for the grid view. The render function is called with
55460 * the following parameters:<ul>
55461 * <li>Data value.</li>
55462 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
55463 * <li>css A CSS style string to apply to the table cell.</li>
55464 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
55465 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
55466 * <li>Row index</li>
55467 * <li>Column index</li>
55468 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
55470 setRenderer : function(col, fn){
55471 this.config[col].renderer = fn;
55475 * Returns the width for the specified column.
55476 * @param {Number} col The column index
55479 getColumnWidth : function(col){
55480 return this.config[col].width * 1 || this.defaultWidth;
55484 * Sets the width for a column.
55485 * @param {Number} col The column index
55486 * @param {Number} width The new width
55488 setColumnWidth : function(col, width, suppressEvent){
55489 this.config[col].width = width;
55490 this.totalWidth = null;
55491 if(!suppressEvent){
55492 this.fireEvent("widthchange", this, col, width);
55497 * Returns the total width of all columns.
55498 * @param {Boolean} includeHidden True to include hidden column widths
55501 getTotalWidth : function(includeHidden){
55502 if(!this.totalWidth){
55503 this.totalWidth = 0;
55504 for(var i = 0, len = this.config.length; i < len; i++){
55505 if(includeHidden || !this.isHidden(i)){
55506 this.totalWidth += this.getColumnWidth(i);
55510 return this.totalWidth;
55514 * Returns the header for the specified column.
55515 * @param {Number} col The column index
55518 getColumnHeader : function(col){
55519 return this.config[col].header;
55523 * Sets the header for a column.
55524 * @param {Number} col The column index
55525 * @param {String} header The new header
55527 setColumnHeader : function(col, header){
55528 this.config[col].header = header;
55529 this.fireEvent("headerchange", this, col, header);
55533 * Returns the tooltip for the specified column.
55534 * @param {Number} col The column index
55537 getColumnTooltip : function(col){
55538 return this.config[col].tooltip;
55541 * Sets the tooltip for a column.
55542 * @param {Number} col The column index
55543 * @param {String} tooltip The new tooltip
55545 setColumnTooltip : function(col, tooltip){
55546 this.config[col].tooltip = tooltip;
55550 * Returns the dataIndex for the specified column.
55551 * @param {Number} col The column index
55554 getDataIndex : function(col){
55555 return this.config[col].dataIndex;
55559 * Sets the dataIndex for a column.
55560 * @param {Number} col The column index
55561 * @param {Number} dataIndex The new dataIndex
55563 setDataIndex : function(col, dataIndex){
55564 this.config[col].dataIndex = dataIndex;
55570 * Returns true if the cell is editable.
55571 * @param {Number} colIndex The column index
55572 * @param {Number} rowIndex The row index
55573 * @return {Boolean}
55575 isCellEditable : function(colIndex, rowIndex){
55576 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
55580 * Returns the editor defined for the cell/column.
55581 * return false or null to disable editing.
55582 * @param {Number} colIndex The column index
55583 * @param {Number} rowIndex The row index
55586 getCellEditor : function(colIndex, rowIndex){
55587 return this.config[colIndex].editor;
55591 * Sets if a column is editable.
55592 * @param {Number} col The column index
55593 * @param {Boolean} editable True if the column is editable
55595 setEditable : function(col, editable){
55596 this.config[col].editable = editable;
55601 * Returns true if the column is hidden.
55602 * @param {Number} colIndex The column index
55603 * @return {Boolean}
55605 isHidden : function(colIndex){
55606 return this.config[colIndex].hidden;
55611 * Returns true if the column width cannot be changed
55613 isFixed : function(colIndex){
55614 return this.config[colIndex].fixed;
55618 * Returns true if the column can be resized
55619 * @return {Boolean}
55621 isResizable : function(colIndex){
55622 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
55625 * Sets if a column is hidden.
55626 * @param {Number} colIndex The column index
55627 * @param {Boolean} hidden True if the column is hidden
55629 setHidden : function(colIndex, hidden){
55630 this.config[colIndex].hidden = hidden;
55631 this.totalWidth = null;
55632 this.fireEvent("hiddenchange", this, colIndex, hidden);
55636 * Sets the editor for a column.
55637 * @param {Number} col The column index
55638 * @param {Object} editor The editor object
55640 setEditor : function(col, editor){
55641 this.config[col].editor = editor;
55645 Roo.grid.ColumnModel.defaultRenderer = function(value){
55646 if(typeof value == "string" && value.length < 1){
55652 // Alias for backwards compatibility
55653 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
55656 * Ext JS Library 1.1.1
55657 * Copyright(c) 2006-2007, Ext JS, LLC.
55659 * Originally Released Under LGPL - original licence link has changed is not relivant.
55662 * <script type="text/javascript">
55666 * @class Roo.grid.AbstractSelectionModel
55667 * @extends Roo.util.Observable
55668 * Abstract base class for grid SelectionModels. It provides the interface that should be
55669 * implemented by descendant classes. This class should not be directly instantiated.
55672 Roo.grid.AbstractSelectionModel = function(){
55673 this.locked = false;
55674 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
55677 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
55678 /** @ignore Called by the grid automatically. Do not call directly. */
55679 init : function(grid){
55685 * Locks the selections.
55688 this.locked = true;
55692 * Unlocks the selections.
55694 unlock : function(){
55695 this.locked = false;
55699 * Returns true if the selections are locked.
55700 * @return {Boolean}
55702 isLocked : function(){
55703 return this.locked;
55707 * Ext JS Library 1.1.1
55708 * Copyright(c) 2006-2007, Ext JS, LLC.
55710 * Originally Released Under LGPL - original licence link has changed is not relivant.
55713 * <script type="text/javascript">
55716 * @extends Roo.grid.AbstractSelectionModel
55717 * @class Roo.grid.RowSelectionModel
55718 * The default SelectionModel used by {@link Roo.grid.Grid}.
55719 * It supports multiple selections and keyboard selection/navigation.
55721 * @param {Object} config
55723 Roo.grid.RowSelectionModel = function(config){
55724 Roo.apply(this, config);
55725 this.selections = new Roo.util.MixedCollection(false, function(o){
55730 this.lastActive = false;
55734 * @event selectionchange
55735 * Fires when the selection changes
55736 * @param {SelectionModel} this
55738 "selectionchange" : true,
55740 * @event afterselectionchange
55741 * Fires after the selection changes (eg. by key press or clicking)
55742 * @param {SelectionModel} this
55744 "afterselectionchange" : true,
55746 * @event beforerowselect
55747 * Fires when a row is selected being selected, return false to cancel.
55748 * @param {SelectionModel} this
55749 * @param {Number} rowIndex The selected index
55750 * @param {Boolean} keepExisting False if other selections will be cleared
55752 "beforerowselect" : true,
55755 * Fires when a row is selected.
55756 * @param {SelectionModel} this
55757 * @param {Number} rowIndex The selected index
55758 * @param {Roo.data.Record} r The record
55760 "rowselect" : true,
55762 * @event rowdeselect
55763 * Fires when a row is deselected.
55764 * @param {SelectionModel} this
55765 * @param {Number} rowIndex The selected index
55767 "rowdeselect" : true
55769 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
55770 this.locked = false;
55773 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
55775 * @cfg {Boolean} singleSelect
55776 * True to allow selection of only one row at a time (defaults to false)
55778 singleSelect : false,
55781 initEvents : function(){
55783 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
55784 this.grid.on("mousedown", this.handleMouseDown, this);
55785 }else{ // allow click to work like normal
55786 this.grid.on("rowclick", this.handleDragableRowClick, this);
55789 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
55790 "up" : function(e){
55792 this.selectPrevious(e.shiftKey);
55793 }else if(this.last !== false && this.lastActive !== false){
55794 var last = this.last;
55795 this.selectRange(this.last, this.lastActive-1);
55796 this.grid.getView().focusRow(this.lastActive);
55797 if(last !== false){
55801 this.selectFirstRow();
55803 this.fireEvent("afterselectionchange", this);
55805 "down" : function(e){
55807 this.selectNext(e.shiftKey);
55808 }else if(this.last !== false && this.lastActive !== false){
55809 var last = this.last;
55810 this.selectRange(this.last, this.lastActive+1);
55811 this.grid.getView().focusRow(this.lastActive);
55812 if(last !== false){
55816 this.selectFirstRow();
55818 this.fireEvent("afterselectionchange", this);
55823 var view = this.grid.view;
55824 view.on("refresh", this.onRefresh, this);
55825 view.on("rowupdated", this.onRowUpdated, this);
55826 view.on("rowremoved", this.onRemove, this);
55830 onRefresh : function(){
55831 var ds = this.grid.dataSource, i, v = this.grid.view;
55832 var s = this.selections;
55833 s.each(function(r){
55834 if((i = ds.indexOfId(r.id)) != -1){
55843 onRemove : function(v, index, r){
55844 this.selections.remove(r);
55848 onRowUpdated : function(v, index, r){
55849 if(this.isSelected(r)){
55850 v.onRowSelect(index);
55856 * @param {Array} records The records to select
55857 * @param {Boolean} keepExisting (optional) True to keep existing selections
55859 selectRecords : function(records, keepExisting){
55861 this.clearSelections();
55863 var ds = this.grid.dataSource;
55864 for(var i = 0, len = records.length; i < len; i++){
55865 this.selectRow(ds.indexOf(records[i]), true);
55870 * Gets the number of selected rows.
55873 getCount : function(){
55874 return this.selections.length;
55878 * Selects the first row in the grid.
55880 selectFirstRow : function(){
55885 * Select the last row.
55886 * @param {Boolean} keepExisting (optional) True to keep existing selections
55888 selectLastRow : function(keepExisting){
55889 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
55893 * Selects the row immediately following the last selected row.
55894 * @param {Boolean} keepExisting (optional) True to keep existing selections
55896 selectNext : function(keepExisting){
55897 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
55898 this.selectRow(this.last+1, keepExisting);
55899 this.grid.getView().focusRow(this.last);
55904 * Selects the row that precedes the last selected row.
55905 * @param {Boolean} keepExisting (optional) True to keep existing selections
55907 selectPrevious : function(keepExisting){
55909 this.selectRow(this.last-1, keepExisting);
55910 this.grid.getView().focusRow(this.last);
55915 * Returns the selected records
55916 * @return {Array} Array of selected records
55918 getSelections : function(){
55919 return [].concat(this.selections.items);
55923 * Returns the first selected record.
55926 getSelected : function(){
55927 return this.selections.itemAt(0);
55932 * Clears all selections.
55934 clearSelections : function(fast){
55935 if(this.locked) return;
55937 var ds = this.grid.dataSource;
55938 var s = this.selections;
55939 s.each(function(r){
55940 this.deselectRow(ds.indexOfId(r.id));
55944 this.selections.clear();
55951 * Selects all rows.
55953 selectAll : function(){
55954 if(this.locked) return;
55955 this.selections.clear();
55956 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
55957 this.selectRow(i, true);
55962 * Returns True if there is a selection.
55963 * @return {Boolean}
55965 hasSelection : function(){
55966 return this.selections.length > 0;
55970 * Returns True if the specified row is selected.
55971 * @param {Number/Record} record The record or index of the record to check
55972 * @return {Boolean}
55974 isSelected : function(index){
55975 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
55976 return (r && this.selections.key(r.id) ? true : false);
55980 * Returns True if the specified record id is selected.
55981 * @param {String} id The id of record to check
55982 * @return {Boolean}
55984 isIdSelected : function(id){
55985 return (this.selections.key(id) ? true : false);
55989 handleMouseDown : function(e, t){
55990 var view = this.grid.getView(), rowIndex;
55991 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
55994 if(e.shiftKey && this.last !== false){
55995 var last = this.last;
55996 this.selectRange(last, rowIndex, e.ctrlKey);
55997 this.last = last; // reset the last
55998 view.focusRow(rowIndex);
56000 var isSelected = this.isSelected(rowIndex);
56001 if(e.button !== 0 && isSelected){
56002 view.focusRow(rowIndex);
56003 }else if(e.ctrlKey && isSelected){
56004 this.deselectRow(rowIndex);
56005 }else if(!isSelected){
56006 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
56007 view.focusRow(rowIndex);
56010 this.fireEvent("afterselectionchange", this);
56013 handleDragableRowClick : function(grid, rowIndex, e)
56015 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
56016 this.selectRow(rowIndex, false);
56017 grid.view.focusRow(rowIndex);
56018 this.fireEvent("afterselectionchange", this);
56023 * Selects multiple rows.
56024 * @param {Array} rows Array of the indexes of the row to select
56025 * @param {Boolean} keepExisting (optional) True to keep existing selections
56027 selectRows : function(rows, keepExisting){
56029 this.clearSelections();
56031 for(var i = 0, len = rows.length; i < len; i++){
56032 this.selectRow(rows[i], true);
56037 * Selects a range of rows. All rows in between startRow and endRow are also selected.
56038 * @param {Number} startRow The index of the first row in the range
56039 * @param {Number} endRow The index of the last row in the range
56040 * @param {Boolean} keepExisting (optional) True to retain existing selections
56042 selectRange : function(startRow, endRow, keepExisting){
56043 if(this.locked) return;
56045 this.clearSelections();
56047 if(startRow <= endRow){
56048 for(var i = startRow; i <= endRow; i++){
56049 this.selectRow(i, true);
56052 for(var i = startRow; i >= endRow; i--){
56053 this.selectRow(i, true);
56059 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
56060 * @param {Number} startRow The index of the first row in the range
56061 * @param {Number} endRow The index of the last row in the range
56063 deselectRange : function(startRow, endRow, preventViewNotify){
56064 if(this.locked) return;
56065 for(var i = startRow; i <= endRow; i++){
56066 this.deselectRow(i, preventViewNotify);
56072 * @param {Number} row The index of the row to select
56073 * @param {Boolean} keepExisting (optional) True to keep existing selections
56075 selectRow : function(index, keepExisting, preventViewNotify){
56076 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
56077 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
56078 if(!keepExisting || this.singleSelect){
56079 this.clearSelections();
56081 var r = this.grid.dataSource.getAt(index);
56082 this.selections.add(r);
56083 this.last = this.lastActive = index;
56084 if(!preventViewNotify){
56085 this.grid.getView().onRowSelect(index);
56087 this.fireEvent("rowselect", this, index, r);
56088 this.fireEvent("selectionchange", this);
56094 * @param {Number} row The index of the row to deselect
56096 deselectRow : function(index, preventViewNotify){
56097 if(this.locked) return;
56098 if(this.last == index){
56101 if(this.lastActive == index){
56102 this.lastActive = false;
56104 var r = this.grid.dataSource.getAt(index);
56105 this.selections.remove(r);
56106 if(!preventViewNotify){
56107 this.grid.getView().onRowDeselect(index);
56109 this.fireEvent("rowdeselect", this, index);
56110 this.fireEvent("selectionchange", this);
56114 restoreLast : function(){
56116 this.last = this._last;
56121 acceptsNav : function(row, col, cm){
56122 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56126 onEditorKey : function(field, e){
56127 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
56132 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56134 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56136 }else if(k == e.ENTER && !e.ctrlKey){
56140 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
56142 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
56144 }else if(k == e.ESC){
56148 g.startEditing(newCell[0], newCell[1]);
56153 * Ext JS Library 1.1.1
56154 * Copyright(c) 2006-2007, Ext JS, LLC.
56156 * Originally Released Under LGPL - original licence link has changed is not relivant.
56159 * <script type="text/javascript">
56162 * @class Roo.grid.CellSelectionModel
56163 * @extends Roo.grid.AbstractSelectionModel
56164 * This class provides the basic implementation for cell selection in a grid.
56166 * @param {Object} config The object containing the configuration of this model.
56167 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
56169 Roo.grid.CellSelectionModel = function(config){
56170 Roo.apply(this, config);
56172 this.selection = null;
56176 * @event beforerowselect
56177 * Fires before a cell is selected.
56178 * @param {SelectionModel} this
56179 * @param {Number} rowIndex The selected row index
56180 * @param {Number} colIndex The selected cell index
56182 "beforecellselect" : true,
56184 * @event cellselect
56185 * Fires when a cell is selected.
56186 * @param {SelectionModel} this
56187 * @param {Number} rowIndex The selected row index
56188 * @param {Number} colIndex The selected cell index
56190 "cellselect" : true,
56192 * @event selectionchange
56193 * Fires when the active selection changes.
56194 * @param {SelectionModel} this
56195 * @param {Object} selection null for no selection or an object (o) with two properties
56197 <li>o.record: the record object for the row the selection is in</li>
56198 <li>o.cell: An array of [rowIndex, columnIndex]</li>
56201 "selectionchange" : true,
56204 * Fires when the tab (or enter) was pressed on the last editable cell
56205 * You can use this to trigger add new row.
56206 * @param {SelectionModel} this
56210 * @event beforeeditnext
56211 * Fires before the next editable sell is made active
56212 * You can use this to skip to another cell or fire the tabend
56213 * if you set cell to false
56214 * @param {Object} eventdata object : { cell : [ row, col ] }
56216 "beforeeditnext" : true
56218 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
56221 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
56223 enter_is_tab: false,
56226 initEvents : function(){
56227 this.grid.on("mousedown", this.handleMouseDown, this);
56228 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
56229 var view = this.grid.view;
56230 view.on("refresh", this.onViewChange, this);
56231 view.on("rowupdated", this.onRowUpdated, this);
56232 view.on("beforerowremoved", this.clearSelections, this);
56233 view.on("beforerowsinserted", this.clearSelections, this);
56234 if(this.grid.isEditor){
56235 this.grid.on("beforeedit", this.beforeEdit, this);
56240 beforeEdit : function(e){
56241 this.select(e.row, e.column, false, true, e.record);
56245 onRowUpdated : function(v, index, r){
56246 if(this.selection && this.selection.record == r){
56247 v.onCellSelect(index, this.selection.cell[1]);
56252 onViewChange : function(){
56253 this.clearSelections(true);
56257 * Returns the currently selected cell,.
56258 * @return {Array} The selected cell (row, column) or null if none selected.
56260 getSelectedCell : function(){
56261 return this.selection ? this.selection.cell : null;
56265 * Clears all selections.
56266 * @param {Boolean} true to prevent the gridview from being notified about the change.
56268 clearSelections : function(preventNotify){
56269 var s = this.selection;
56271 if(preventNotify !== true){
56272 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
56274 this.selection = null;
56275 this.fireEvent("selectionchange", this, null);
56280 * Returns true if there is a selection.
56281 * @return {Boolean}
56283 hasSelection : function(){
56284 return this.selection ? true : false;
56288 handleMouseDown : function(e, t){
56289 var v = this.grid.getView();
56290 if(this.isLocked()){
56293 var row = v.findRowIndex(t);
56294 var cell = v.findCellIndex(t);
56295 if(row !== false && cell !== false){
56296 this.select(row, cell);
56302 * @param {Number} rowIndex
56303 * @param {Number} collIndex
56305 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
56306 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
56307 this.clearSelections();
56308 r = r || this.grid.dataSource.getAt(rowIndex);
56311 cell : [rowIndex, colIndex]
56313 if(!preventViewNotify){
56314 var v = this.grid.getView();
56315 v.onCellSelect(rowIndex, colIndex);
56316 if(preventFocus !== true){
56317 v.focusCell(rowIndex, colIndex);
56320 this.fireEvent("cellselect", this, rowIndex, colIndex);
56321 this.fireEvent("selectionchange", this, this.selection);
56326 isSelectable : function(rowIndex, colIndex, cm){
56327 return !cm.isHidden(colIndex);
56331 handleKeyDown : function(e){
56332 //Roo.log('Cell Sel Model handleKeyDown');
56333 if(!e.isNavKeyPress()){
56336 var g = this.grid, s = this.selection;
56339 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
56341 this.select(cell[0], cell[1]);
56346 var walk = function(row, col, step){
56347 return g.walkCells(row, col, step, sm.isSelectable, sm);
56349 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
56356 // handled by onEditorKey
56357 if (g.isEditor && g.editing) {
56361 newCell = walk(r, c-1, -1);
56363 newCell = walk(r, c+1, 1);
56368 newCell = walk(r+1, c, 1);
56372 newCell = walk(r-1, c, -1);
56376 newCell = walk(r, c+1, 1);
56380 newCell = walk(r, c-1, -1);
56385 if(g.isEditor && !g.editing){
56386 g.startEditing(r, c);
56395 this.select(newCell[0], newCell[1]);
56401 acceptsNav : function(row, col, cm){
56402 return !cm.isHidden(col) && cm.isCellEditable(col, row);
56406 * @param {Number} field (not used) - as it's normally used as a listener
56407 * @param {Number} e - event - fake it by using
56409 * var e = Roo.EventObjectImpl.prototype;
56410 * e.keyCode = e.TAB
56414 onEditorKey : function(field, e){
56416 var k = e.getKey(),
56419 ed = g.activeEditor,
56421 ///Roo.log('onEditorKey' + k);
56424 if (this.enter_is_tab && k == e.ENTER) {
56430 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
56432 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56438 } else if(k == e.ENTER && !e.ctrlKey){
56441 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
56443 } else if(k == e.ESC){
56448 var ecall = { cell : newCell, forward : forward };
56449 this.fireEvent('beforeeditnext', ecall );
56450 newCell = ecall.cell;
56451 forward = ecall.forward;
56455 //Roo.log('next cell after edit');
56456 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
56457 } else if (forward) {
56458 // tabbed past last
56459 this.fireEvent.defer(100, this, ['tabend',this]);
56464 * Ext JS Library 1.1.1
56465 * Copyright(c) 2006-2007, Ext JS, LLC.
56467 * Originally Released Under LGPL - original licence link has changed is not relivant.
56470 * <script type="text/javascript">
56474 * @class Roo.grid.EditorGrid
56475 * @extends Roo.grid.Grid
56476 * Class for creating and editable grid.
56477 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56478 * The container MUST have some type of size defined for the grid to fill. The container will be
56479 * automatically set to position relative if it isn't already.
56480 * @param {Object} dataSource The data model to bind to
56481 * @param {Object} colModel The column model with info about this grid's columns
56483 Roo.grid.EditorGrid = function(container, config){
56484 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
56485 this.getGridEl().addClass("xedit-grid");
56487 if(!this.selModel){
56488 this.selModel = new Roo.grid.CellSelectionModel();
56491 this.activeEditor = null;
56495 * @event beforeedit
56496 * Fires before cell editing is triggered. The edit event object has the following properties <br />
56497 * <ul style="padding:5px;padding-left:16px;">
56498 * <li>grid - This grid</li>
56499 * <li>record - The record being edited</li>
56500 * <li>field - The field name being edited</li>
56501 * <li>value - The value for the field being edited.</li>
56502 * <li>row - The grid row index</li>
56503 * <li>column - The grid column index</li>
56504 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56506 * @param {Object} e An edit event (see above for description)
56508 "beforeedit" : true,
56511 * Fires after a cell is edited. <br />
56512 * <ul style="padding:5px;padding-left:16px;">
56513 * <li>grid - This grid</li>
56514 * <li>record - The record being edited</li>
56515 * <li>field - The field name being edited</li>
56516 * <li>value - The value being set</li>
56517 * <li>originalValue - The original value for the field, before the edit.</li>
56518 * <li>row - The grid row index</li>
56519 * <li>column - The grid column index</li>
56521 * @param {Object} e An edit event (see above for description)
56523 "afteredit" : true,
56525 * @event validateedit
56526 * Fires after a cell is edited, but before the value is set in the record.
56527 * You can use this to modify the value being set in the field, Return false
56528 * to cancel the change. The edit event object has the following properties <br />
56529 * <ul style="padding:5px;padding-left:16px;">
56530 * <li>editor - This editor</li>
56531 * <li>grid - This grid</li>
56532 * <li>record - The record being edited</li>
56533 * <li>field - The field name being edited</li>
56534 * <li>value - The value being set</li>
56535 * <li>originalValue - The original value for the field, before the edit.</li>
56536 * <li>row - The grid row index</li>
56537 * <li>column - The grid column index</li>
56538 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
56540 * @param {Object} e An edit event (see above for description)
56542 "validateedit" : true
56544 this.on("bodyscroll", this.stopEditing, this);
56545 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
56548 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
56550 * @cfg {Number} clicksToEdit
56551 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
56558 trackMouseOver: false, // causes very odd FF errors
56560 onCellDblClick : function(g, row, col){
56561 this.startEditing(row, col);
56564 onEditComplete : function(ed, value, startValue){
56565 this.editing = false;
56566 this.activeEditor = null;
56567 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
56569 var field = this.colModel.getDataIndex(ed.col);
56574 originalValue: startValue,
56581 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
56584 if(String(value) !== String(startValue)){
56586 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
56587 r.set(field, e.value);
56588 // if we are dealing with a combo box..
56589 // then we also set the 'name' colum to be the displayField
56590 if (ed.field.displayField && ed.field.name) {
56591 r.set(ed.field.name, ed.field.el.dom.value);
56594 delete e.cancel; //?? why!!!
56595 this.fireEvent("afteredit", e);
56598 this.fireEvent("afteredit", e); // always fire it!
56600 this.view.focusCell(ed.row, ed.col);
56604 * Starts editing the specified for the specified row/column
56605 * @param {Number} rowIndex
56606 * @param {Number} colIndex
56608 startEditing : function(row, col){
56609 this.stopEditing();
56610 if(this.colModel.isCellEditable(col, row)){
56611 this.view.ensureVisible(row, col, true);
56613 var r = this.dataSource.getAt(row);
56614 var field = this.colModel.getDataIndex(col);
56615 var cell = Roo.get(this.view.getCell(row,col));
56620 value: r.data[field],
56625 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
56626 this.editing = true;
56627 var ed = this.colModel.getCellEditor(col, row);
56633 ed.render(ed.parentEl || document.body);
56639 (function(){ // complex but required for focus issues in safari, ie and opera
56643 ed.on("complete", this.onEditComplete, this, {single: true});
56644 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
56645 this.activeEditor = ed;
56646 var v = r.data[field];
56647 ed.startEdit(this.view.getCell(row, col), v);
56648 // combo's with 'displayField and name set
56649 if (ed.field.displayField && ed.field.name) {
56650 ed.field.el.dom.value = r.data[ed.field.name];
56654 }).defer(50, this);
56660 * Stops any active editing
56662 stopEditing : function(){
56663 if(this.activeEditor){
56664 this.activeEditor.completeEdit();
56666 this.activeEditor = null;
56670 * Called to get grid's drag proxy text, by default returns this.ddText.
56673 getDragDropText : function(){
56674 var count = this.selModel.getSelectedCell() ? 1 : 0;
56675 return String.format(this.ddText, count, count == 1 ? '' : 's');
56680 * Ext JS Library 1.1.1
56681 * Copyright(c) 2006-2007, Ext JS, LLC.
56683 * Originally Released Under LGPL - original licence link has changed is not relivant.
56686 * <script type="text/javascript">
56689 // private - not really -- you end up using it !
56690 // This is a support class used internally by the Grid components
56693 * @class Roo.grid.GridEditor
56694 * @extends Roo.Editor
56695 * Class for creating and editable grid elements.
56696 * @param {Object} config any settings (must include field)
56698 Roo.grid.GridEditor = function(field, config){
56699 if (!config && field.field) {
56701 field = Roo.factory(config.field, Roo.form);
56703 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
56704 field.monitorTab = false;
56707 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
56710 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
56713 alignment: "tl-tl",
56716 cls: "x-small-editor x-grid-editor",
56721 * Ext JS Library 1.1.1
56722 * Copyright(c) 2006-2007, Ext JS, LLC.
56724 * Originally Released Under LGPL - original licence link has changed is not relivant.
56727 * <script type="text/javascript">
56732 Roo.grid.PropertyRecord = Roo.data.Record.create([
56733 {name:'name',type:'string'}, 'value'
56737 Roo.grid.PropertyStore = function(grid, source){
56739 this.store = new Roo.data.Store({
56740 recordType : Roo.grid.PropertyRecord
56742 this.store.on('update', this.onUpdate, this);
56744 this.setSource(source);
56746 Roo.grid.PropertyStore.superclass.constructor.call(this);
56751 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
56752 setSource : function(o){
56754 this.store.removeAll();
56757 if(this.isEditableValue(o[k])){
56758 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
56761 this.store.loadRecords({records: data}, {}, true);
56764 onUpdate : function(ds, record, type){
56765 if(type == Roo.data.Record.EDIT){
56766 var v = record.data['value'];
56767 var oldValue = record.modified['value'];
56768 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
56769 this.source[record.id] = v;
56771 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
56778 getProperty : function(row){
56779 return this.store.getAt(row);
56782 isEditableValue: function(val){
56783 if(val && val instanceof Date){
56785 }else if(typeof val == 'object' || typeof val == 'function'){
56791 setValue : function(prop, value){
56792 this.source[prop] = value;
56793 this.store.getById(prop).set('value', value);
56796 getSource : function(){
56797 return this.source;
56801 Roo.grid.PropertyColumnModel = function(grid, store){
56804 g.PropertyColumnModel.superclass.constructor.call(this, [
56805 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
56806 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
56808 this.store = store;
56809 this.bselect = Roo.DomHelper.append(document.body, {
56810 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
56811 {tag: 'option', value: 'true', html: 'true'},
56812 {tag: 'option', value: 'false', html: 'false'}
56815 Roo.id(this.bselect);
56818 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
56819 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
56820 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
56821 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
56822 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
56824 this.renderCellDelegate = this.renderCell.createDelegate(this);
56825 this.renderPropDelegate = this.renderProp.createDelegate(this);
56828 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
56832 valueText : 'Value',
56834 dateFormat : 'm/j/Y',
56837 renderDate : function(dateVal){
56838 return dateVal.dateFormat(this.dateFormat);
56841 renderBool : function(bVal){
56842 return bVal ? 'true' : 'false';
56845 isCellEditable : function(colIndex, rowIndex){
56846 return colIndex == 1;
56849 getRenderer : function(col){
56851 this.renderCellDelegate : this.renderPropDelegate;
56854 renderProp : function(v){
56855 return this.getPropertyName(v);
56858 renderCell : function(val){
56860 if(val instanceof Date){
56861 rv = this.renderDate(val);
56862 }else if(typeof val == 'boolean'){
56863 rv = this.renderBool(val);
56865 return Roo.util.Format.htmlEncode(rv);
56868 getPropertyName : function(name){
56869 var pn = this.grid.propertyNames;
56870 return pn && pn[name] ? pn[name] : name;
56873 getCellEditor : function(colIndex, rowIndex){
56874 var p = this.store.getProperty(rowIndex);
56875 var n = p.data['name'], val = p.data['value'];
56877 if(typeof(this.grid.customEditors[n]) == 'string'){
56878 return this.editors[this.grid.customEditors[n]];
56880 if(typeof(this.grid.customEditors[n]) != 'undefined'){
56881 return this.grid.customEditors[n];
56883 if(val instanceof Date){
56884 return this.editors['date'];
56885 }else if(typeof val == 'number'){
56886 return this.editors['number'];
56887 }else if(typeof val == 'boolean'){
56888 return this.editors['boolean'];
56890 return this.editors['string'];
56896 * @class Roo.grid.PropertyGrid
56897 * @extends Roo.grid.EditorGrid
56898 * This class represents the interface of a component based property grid control.
56899 * <br><br>Usage:<pre><code>
56900 var grid = new Roo.grid.PropertyGrid("my-container-id", {
56908 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56909 * The container MUST have some type of size defined for the grid to fill. The container will be
56910 * automatically set to position relative if it isn't already.
56911 * @param {Object} config A config object that sets properties on this grid.
56913 Roo.grid.PropertyGrid = function(container, config){
56914 config = config || {};
56915 var store = new Roo.grid.PropertyStore(this);
56916 this.store = store;
56917 var cm = new Roo.grid.PropertyColumnModel(this, store);
56918 store.store.sort('name', 'ASC');
56919 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
56922 enableColLock:false,
56923 enableColumnMove:false,
56925 trackMouseOver: false,
56928 this.getGridEl().addClass('x-props-grid');
56929 this.lastEditRow = null;
56930 this.on('columnresize', this.onColumnResize, this);
56933 * @event beforepropertychange
56934 * Fires before a property changes (return false to stop?)
56935 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56936 * @param {String} id Record Id
56937 * @param {String} newval New Value
56938 * @param {String} oldval Old Value
56940 "beforepropertychange": true,
56942 * @event propertychange
56943 * Fires after a property changes
56944 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
56945 * @param {String} id Record Id
56946 * @param {String} newval New Value
56947 * @param {String} oldval Old Value
56949 "propertychange": true
56951 this.customEditors = this.customEditors || {};
56953 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
56956 * @cfg {Object} customEditors map of colnames=> custom editors.
56957 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
56958 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
56959 * false disables editing of the field.
56963 * @cfg {Object} propertyNames map of property Names to their displayed value
56966 render : function(){
56967 Roo.grid.PropertyGrid.superclass.render.call(this);
56968 this.autoSize.defer(100, this);
56971 autoSize : function(){
56972 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
56974 this.view.fitColumns();
56978 onColumnResize : function(){
56979 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
56983 * Sets the data for the Grid
56984 * accepts a Key => Value object of all the elements avaiable.
56985 * @param {Object} data to appear in grid.
56987 setSource : function(source){
56988 this.store.setSource(source);
56992 * Gets all the data from the grid.
56993 * @return {Object} data data stored in grid
56995 getSource : function(){
56996 return this.store.getSource();
57005 * @class Roo.grid.Calendar
57006 * @extends Roo.util.Grid
57007 * This class extends the Grid to provide a calendar widget
57008 * <br><br>Usage:<pre><code>
57009 var grid = new Roo.grid.Calendar("my-container-id", {
57012 selModel: mySelectionModel,
57013 autoSizeColumns: true,
57014 monitorWindowResize: false,
57015 trackMouseOver: true
57016 eventstore : real data store..
57022 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
57023 * The container MUST have some type of size defined for the grid to fill. The container will be
57024 * automatically set to position relative if it isn't already.
57025 * @param {Object} config A config object that sets properties on this grid.
57027 Roo.grid.Calendar = function(container, config){
57028 // initialize the container
57029 this.container = Roo.get(container);
57030 this.container.update("");
57031 this.container.setStyle("overflow", "hidden");
57032 this.container.addClass('x-grid-container');
57034 this.id = this.container.id;
57036 Roo.apply(this, config);
57037 // check and correct shorthanded configs
57041 for (var r = 0;r < 6;r++) {
57044 for (var c =0;c < 7;c++) {
57048 if (this.eventStore) {
57049 this.eventStore= Roo.factory(this.eventStore, Roo.data);
57050 this.eventStore.on('load',this.onLoad, this);
57051 this.eventStore.on('beforeload',this.clearEvents, this);
57055 this.dataSource = new Roo.data.Store({
57056 proxy: new Roo.data.MemoryProxy(rows),
57057 reader: new Roo.data.ArrayReader({}, [
57058 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
57061 this.dataSource.load();
57062 this.ds = this.dataSource;
57063 this.ds.xmodule = this.xmodule || false;
57066 var cellRender = function(v,x,r)
57068 return String.format(
57069 '<div class="fc-day fc-widget-content"><div>' +
57070 '<div class="fc-event-container"></div>' +
57071 '<div class="fc-day-number">{0}</div>'+
57073 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
57074 '</div></div>', v);
57079 this.colModel = new Roo.grid.ColumnModel( [
57081 xtype: 'ColumnModel',
57083 dataIndex : 'weekday0',
57085 renderer : cellRender
57088 xtype: 'ColumnModel',
57090 dataIndex : 'weekday1',
57092 renderer : cellRender
57095 xtype: 'ColumnModel',
57097 dataIndex : 'weekday2',
57098 header : 'Tuesday',
57099 renderer : cellRender
57102 xtype: 'ColumnModel',
57104 dataIndex : 'weekday3',
57105 header : 'Wednesday',
57106 renderer : cellRender
57109 xtype: 'ColumnModel',
57111 dataIndex : 'weekday4',
57112 header : 'Thursday',
57113 renderer : cellRender
57116 xtype: 'ColumnModel',
57118 dataIndex : 'weekday5',
57120 renderer : cellRender
57123 xtype: 'ColumnModel',
57125 dataIndex : 'weekday6',
57126 header : 'Saturday',
57127 renderer : cellRender
57130 this.cm = this.colModel;
57131 this.cm.xmodule = this.xmodule || false;
57135 //this.selModel = new Roo.grid.CellSelectionModel();
57136 //this.sm = this.selModel;
57137 //this.selModel.init(this);
57141 this.container.setWidth(this.width);
57145 this.container.setHeight(this.height);
57152 * The raw click event for the entire grid.
57153 * @param {Roo.EventObject} e
57158 * The raw dblclick event for the entire grid.
57159 * @param {Roo.EventObject} e
57163 * @event contextmenu
57164 * The raw contextmenu event for the entire grid.
57165 * @param {Roo.EventObject} e
57167 "contextmenu" : true,
57170 * The raw mousedown event for the entire grid.
57171 * @param {Roo.EventObject} e
57173 "mousedown" : true,
57176 * The raw mouseup event for the entire grid.
57177 * @param {Roo.EventObject} e
57182 * The raw mouseover event for the entire grid.
57183 * @param {Roo.EventObject} e
57185 "mouseover" : true,
57188 * The raw mouseout event for the entire grid.
57189 * @param {Roo.EventObject} e
57194 * The raw keypress event for the entire grid.
57195 * @param {Roo.EventObject} e
57200 * The raw keydown event for the entire grid.
57201 * @param {Roo.EventObject} e
57209 * Fires when a cell is clicked
57210 * @param {Grid} this
57211 * @param {Number} rowIndex
57212 * @param {Number} columnIndex
57213 * @param {Roo.EventObject} e
57215 "cellclick" : true,
57217 * @event celldblclick
57218 * Fires when a cell is double clicked
57219 * @param {Grid} this
57220 * @param {Number} rowIndex
57221 * @param {Number} columnIndex
57222 * @param {Roo.EventObject} e
57224 "celldblclick" : true,
57227 * Fires when a row is clicked
57228 * @param {Grid} this
57229 * @param {Number} rowIndex
57230 * @param {Roo.EventObject} e
57234 * @event rowdblclick
57235 * Fires when a row is double clicked
57236 * @param {Grid} this
57237 * @param {Number} rowIndex
57238 * @param {Roo.EventObject} e
57240 "rowdblclick" : true,
57242 * @event headerclick
57243 * Fires when a header is clicked
57244 * @param {Grid} this
57245 * @param {Number} columnIndex
57246 * @param {Roo.EventObject} e
57248 "headerclick" : true,
57250 * @event headerdblclick
57251 * Fires when a header cell is double clicked
57252 * @param {Grid} this
57253 * @param {Number} columnIndex
57254 * @param {Roo.EventObject} e
57256 "headerdblclick" : true,
57258 * @event rowcontextmenu
57259 * Fires when a row is right clicked
57260 * @param {Grid} this
57261 * @param {Number} rowIndex
57262 * @param {Roo.EventObject} e
57264 "rowcontextmenu" : true,
57266 * @event cellcontextmenu
57267 * Fires when a cell is right clicked
57268 * @param {Grid} this
57269 * @param {Number} rowIndex
57270 * @param {Number} cellIndex
57271 * @param {Roo.EventObject} e
57273 "cellcontextmenu" : true,
57275 * @event headercontextmenu
57276 * Fires when a header is right clicked
57277 * @param {Grid} this
57278 * @param {Number} columnIndex
57279 * @param {Roo.EventObject} e
57281 "headercontextmenu" : true,
57283 * @event bodyscroll
57284 * Fires when the body element is scrolled
57285 * @param {Number} scrollLeft
57286 * @param {Number} scrollTop
57288 "bodyscroll" : true,
57290 * @event columnresize
57291 * Fires when the user resizes a column
57292 * @param {Number} columnIndex
57293 * @param {Number} newSize
57295 "columnresize" : true,
57297 * @event columnmove
57298 * Fires when the user moves a column
57299 * @param {Number} oldIndex
57300 * @param {Number} newIndex
57302 "columnmove" : true,
57305 * Fires when row(s) start being dragged
57306 * @param {Grid} this
57307 * @param {Roo.GridDD} dd The drag drop object
57308 * @param {event} e The raw browser event
57310 "startdrag" : true,
57313 * Fires when a drag operation is complete
57314 * @param {Grid} this
57315 * @param {Roo.GridDD} dd The drag drop object
57316 * @param {event} e The raw browser event
57321 * Fires when dragged row(s) are dropped on a valid DD target
57322 * @param {Grid} this
57323 * @param {Roo.GridDD} dd The drag drop object
57324 * @param {String} targetId The target drag drop object
57325 * @param {event} e The raw browser event
57330 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57331 * @param {Grid} this
57332 * @param {Roo.GridDD} dd The drag drop object
57333 * @param {String} targetId The target drag drop object
57334 * @param {event} e The raw browser event
57339 * Fires when the dragged row(s) first cross another DD target while being dragged
57340 * @param {Grid} this
57341 * @param {Roo.GridDD} dd The drag drop object
57342 * @param {String} targetId The target drag drop object
57343 * @param {event} e The raw browser event
57345 "dragenter" : true,
57348 * Fires when the dragged row(s) leave another DD target while being dragged
57349 * @param {Grid} this
57350 * @param {Roo.GridDD} dd The drag drop object
57351 * @param {String} targetId The target drag drop object
57352 * @param {event} e The raw browser event
57357 * Fires when a row is rendered, so you can change add a style to it.
57358 * @param {GridView} gridview The grid view
57359 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57365 * Fires when the grid is rendered
57366 * @param {Grid} grid
57371 * Fires when a date is selected
57372 * @param {DatePicker} this
57373 * @param {Date} date The selected date
57377 * @event monthchange
57378 * Fires when the displayed month changes
57379 * @param {DatePicker} this
57380 * @param {Date} date The selected month
57382 'monthchange': true,
57384 * @event evententer
57385 * Fires when mouse over an event
57386 * @param {Calendar} this
57387 * @param {event} Event
57389 'evententer': true,
57391 * @event eventleave
57392 * Fires when the mouse leaves an
57393 * @param {Calendar} this
57396 'eventleave': true,
57398 * @event eventclick
57399 * Fires when the mouse click an
57400 * @param {Calendar} this
57403 'eventclick': true,
57405 * @event eventrender
57406 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
57407 * @param {Calendar} this
57408 * @param {data} data to be modified
57410 'eventrender': true
57414 Roo.grid.Grid.superclass.constructor.call(this);
57415 this.on('render', function() {
57416 this.view.el.addClass('x-grid-cal');
57418 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
57422 if (!Roo.grid.Calendar.style) {
57423 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
57426 '.x-grid-cal .x-grid-col' : {
57427 height: 'auto !important',
57428 'vertical-align': 'top'
57430 '.x-grid-cal .fc-event-hori' : {
57441 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
57443 * @cfg {Store} eventStore The store that loads events.
57448 activeDate : false,
57451 monitorWindowResize : false,
57454 resizeColumns : function() {
57455 var col = (this.view.el.getWidth() / 7) - 3;
57456 // loop through cols, and setWidth
57457 for(var i =0 ; i < 7 ; i++){
57458 this.cm.setColumnWidth(i, col);
57461 setDate :function(date) {
57463 Roo.log('setDate?');
57465 this.resizeColumns();
57466 var vd = this.activeDate;
57467 this.activeDate = date;
57468 // if(vd && this.el){
57469 // var t = date.getTime();
57470 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
57471 // Roo.log('using add remove');
57473 // this.fireEvent('monthchange', this, date);
57475 // this.cells.removeClass("fc-state-highlight");
57476 // this.cells.each(function(c){
57477 // if(c.dateValue == t){
57478 // c.addClass("fc-state-highlight");
57479 // setTimeout(function(){
57480 // try{c.dom.firstChild.focus();}catch(e){}
57490 var days = date.getDaysInMonth();
57492 var firstOfMonth = date.getFirstDateOfMonth();
57493 var startingPos = firstOfMonth.getDay()-this.startDay;
57495 if(startingPos < this.startDay){
57499 var pm = date.add(Date.MONTH, -1);
57500 var prevStart = pm.getDaysInMonth()-startingPos;
57504 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57506 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
57507 //this.cells.addClassOnOver('fc-state-hover');
57509 var cells = this.cells.elements;
57510 var textEls = this.textNodes;
57512 //Roo.each(cells, function(cell){
57513 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
57516 days += startingPos;
57518 // convert everything to numbers so it's fast
57519 var day = 86400000;
57520 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
57523 //Roo.log(prevStart);
57525 var today = new Date().clearTime().getTime();
57526 var sel = date.clearTime().getTime();
57527 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
57528 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
57529 var ddMatch = this.disabledDatesRE;
57530 var ddText = this.disabledDatesText;
57531 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
57532 var ddaysText = this.disabledDaysText;
57533 var format = this.format;
57535 var setCellClass = function(cal, cell){
57537 //Roo.log('set Cell Class');
57539 var t = d.getTime();
57544 cell.dateValue = t;
57546 cell.className += " fc-today";
57547 cell.className += " fc-state-highlight";
57548 cell.title = cal.todayText;
57551 // disable highlight in other month..
57552 cell.className += " fc-state-highlight";
57557 //cell.className = " fc-state-disabled";
57558 cell.title = cal.minText;
57562 //cell.className = " fc-state-disabled";
57563 cell.title = cal.maxText;
57567 if(ddays.indexOf(d.getDay()) != -1){
57568 // cell.title = ddaysText;
57569 // cell.className = " fc-state-disabled";
57572 if(ddMatch && format){
57573 var fvalue = d.dateFormat(format);
57574 if(ddMatch.test(fvalue)){
57575 cell.title = ddText.replace("%0", fvalue);
57576 cell.className = " fc-state-disabled";
57580 if (!cell.initialClassName) {
57581 cell.initialClassName = cell.dom.className;
57584 cell.dom.className = cell.initialClassName + ' ' + cell.className;
57589 for(; i < startingPos; i++) {
57590 cells[i].dayName = (++prevStart);
57591 Roo.log(textEls[i]);
57592 d.setDate(d.getDate()+1);
57594 //cells[i].className = "fc-past fc-other-month";
57595 setCellClass(this, cells[i]);
57600 for(; i < days; i++){
57601 intDay = i - startingPos + 1;
57602 cells[i].dayName = (intDay);
57603 d.setDate(d.getDate()+1);
57605 cells[i].className = ''; // "x-date-active";
57606 setCellClass(this, cells[i]);
57610 for(; i < 42; i++) {
57611 //textEls[i].innerHTML = (++extraDays);
57613 d.setDate(d.getDate()+1);
57614 cells[i].dayName = (++extraDays);
57615 cells[i].className = "fc-future fc-other-month";
57616 setCellClass(this, cells[i]);
57619 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
57621 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
57623 // this will cause all the cells to mis
57626 for (var r = 0;r < 6;r++) {
57627 for (var c =0;c < 7;c++) {
57628 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
57632 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
57633 for(i=0;i<cells.length;i++) {
57635 this.cells.elements[i].dayName = cells[i].dayName ;
57636 this.cells.elements[i].className = cells[i].className;
57637 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
57638 this.cells.elements[i].title = cells[i].title ;
57639 this.cells.elements[i].dateValue = cells[i].dateValue ;
57645 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
57646 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
57648 ////if(totalRows != 6){
57649 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
57650 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
57653 this.fireEvent('monthchange', this, date);
57658 * Returns the grid's SelectionModel.
57659 * @return {SelectionModel}
57661 getSelectionModel : function(){
57662 if(!this.selModel){
57663 this.selModel = new Roo.grid.CellSelectionModel();
57665 return this.selModel;
57669 this.eventStore.load()
57675 findCell : function(dt) {
57676 dt = dt.clearTime().getTime();
57678 this.cells.each(function(c){
57679 //Roo.log("check " +c.dateValue + '?=' + dt);
57680 if(c.dateValue == dt){
57690 findCells : function(rec) {
57691 var s = rec.data.start_dt.clone().clearTime().getTime();
57693 var e= rec.data.end_dt.clone().clearTime().getTime();
57696 this.cells.each(function(c){
57697 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
57699 if(c.dateValue > e){
57702 if(c.dateValue < s){
57711 findBestRow: function(cells)
57715 for (var i =0 ; i < cells.length;i++) {
57716 ret = Math.max(cells[i].rows || 0,ret);
57723 addItem : function(rec)
57725 // look for vertical location slot in
57726 var cells = this.findCells(rec);
57728 rec.row = this.findBestRow(cells);
57730 // work out the location.
57734 for(var i =0; i < cells.length; i++) {
57742 if (crow.start.getY() == cells[i].getY()) {
57744 crow.end = cells[i];
57760 for (var i = 0; i < cells.length;i++) {
57761 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
57768 clearEvents: function() {
57770 if (!this.eventStore.getCount()) {
57773 // reset number of rows in cells.
57774 Roo.each(this.cells.elements, function(c){
57778 this.eventStore.each(function(e) {
57779 this.clearEvent(e);
57784 clearEvent : function(ev)
57787 Roo.each(ev.els, function(el) {
57788 el.un('mouseenter' ,this.onEventEnter, this);
57789 el.un('mouseleave' ,this.onEventLeave, this);
57797 renderEvent : function(ev,ctr) {
57799 ctr = this.view.el.select('.fc-event-container',true).first();
57803 this.clearEvent(ev);
57809 var cells = ev.cells;
57810 var rows = ev.rows;
57811 this.fireEvent('eventrender', this, ev);
57813 for(var i =0; i < rows.length; i++) {
57817 cls += ' fc-event-start';
57819 if ((i+1) == rows.length) {
57820 cls += ' fc-event-end';
57823 //Roo.log(ev.data);
57824 // how many rows should it span..
57825 var cg = this.eventTmpl.append(ctr,Roo.apply({
57828 }, ev.data) , true);
57831 cg.on('mouseenter' ,this.onEventEnter, this, ev);
57832 cg.on('mouseleave' ,this.onEventLeave, this, ev);
57833 cg.on('click', this.onEventClick, this, ev);
57837 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
57838 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
57841 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
57842 cg.setWidth(ebox.right - sbox.x -2);
57846 renderEvents: function()
57848 // first make sure there is enough space..
57850 if (!this.eventTmpl) {
57851 this.eventTmpl = new Roo.Template(
57852 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
57853 '<div class="fc-event-inner">' +
57854 '<span class="fc-event-time">{time}</span>' +
57855 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
57857 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
57865 this.cells.each(function(c) {
57866 //Roo.log(c.select('.fc-day-content div',true).first());
57867 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
57870 var ctr = this.view.el.select('.fc-event-container',true).first();
57873 this.eventStore.each(function(ev){
57875 this.renderEvent(ev);
57879 this.view.layout();
57883 onEventEnter: function (e, el,event,d) {
57884 this.fireEvent('evententer', this, el, event);
57887 onEventLeave: function (e, el,event,d) {
57888 this.fireEvent('eventleave', this, el, event);
57891 onEventClick: function (e, el,event,d) {
57892 this.fireEvent('eventclick', this, el, event);
57895 onMonthChange: function () {
57899 onLoad: function () {
57901 //Roo.log('calendar onload');
57903 if(this.eventStore.getCount() > 0){
57907 this.eventStore.each(function(d){
57912 if (typeof(add.end_dt) == 'undefined') {
57913 Roo.log("Missing End time in calendar data: ");
57917 if (typeof(add.start_dt) == 'undefined') {
57918 Roo.log("Missing Start time in calendar data: ");
57922 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
57923 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
57924 add.id = add.id || d.id;
57925 add.title = add.title || '??';
57933 this.renderEvents();
57943 render : function ()
57947 if (!this.view.el.hasClass('course-timesheet')) {
57948 this.view.el.addClass('course-timesheet');
57950 if (this.tsStyle) {
57955 Roo.log(_this.grid.view.el.getWidth());
57958 this.tsStyle = Roo.util.CSS.createStyleSheet({
57959 '.course-timesheet .x-grid-row' : {
57962 '.x-grid-row td' : {
57963 'vertical-align' : 0
57965 '.course-edit-link' : {
57967 'text-overflow' : 'ellipsis',
57968 'overflow' : 'hidden',
57969 'white-space' : 'nowrap',
57970 'cursor' : 'pointer'
57975 '.de-act-sup-link' : {
57976 'color' : 'purple',
57977 'text-decoration' : 'line-through'
57981 'text-decoration' : 'line-through'
57983 '.course-timesheet .course-highlight' : {
57984 'border-top-style': 'dashed !important',
57985 'border-bottom-bottom': 'dashed !important'
57987 '.course-timesheet .course-item' : {
57988 'font-family' : 'tahoma, arial, helvetica',
57989 'font-size' : '11px',
57990 'overflow' : 'hidden',
57991 'padding-left' : '10px',
57992 'padding-right' : '10px',
57993 'padding-top' : '10px'
58001 monitorWindowResize : false,
58002 cellrenderer : function(v,x,r)
58007 xtype: 'CellSelectionModel',
58014 beforeload : function (_self, options)
58016 options.params = options.params || {};
58017 options.params._month = _this.monthField.getValue();
58018 options.params.limit = 9999;
58019 options.params['sort'] = 'when_dt';
58020 options.params['dir'] = 'ASC';
58021 this.proxy.loadResponse = this.loadResponse;
58023 //this.addColumns();
58025 load : function (_self, records, options)
58027 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
58028 // if you click on the translation.. you can edit it...
58029 var el = Roo.get(this);
58030 var id = el.dom.getAttribute('data-id');
58031 var d = el.dom.getAttribute('data-date');
58032 var t = el.dom.getAttribute('data-time');
58033 //var id = this.child('span').dom.textContent;
58036 Pman.Dialog.CourseCalendar.show({
58040 productitem_active : id ? 1 : 0
58042 _this.grid.ds.load({});
58047 _this.panel.fireEvent('resize', [ '', '' ]);
58050 loadResponse : function(o, success, response){
58051 // this is overridden on before load..
58053 Roo.log("our code?");
58054 //Roo.log(success);
58055 //Roo.log(response)
58056 delete this.activeRequest;
58058 this.fireEvent("loadexception", this, o, response);
58059 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58064 result = o.reader.read(response);
58066 Roo.log("load exception?");
58067 this.fireEvent("loadexception", this, o, response, e);
58068 o.request.callback.call(o.request.scope, null, o.request.arg, false);
58071 Roo.log("ready...");
58072 // loop through result.records;
58073 // and set this.tdate[date] = [] << array of records..
58075 Roo.each(result.records, function(r){
58077 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
58078 _this.tdata[r.data.when_dt.format('j')] = [];
58080 _this.tdata[r.data.when_dt.format('j')].push(r.data);
58083 //Roo.log(_this.tdata);
58085 result.records = [];
58086 result.totalRecords = 6;
58088 // let's generate some duumy records for the rows.
58089 //var st = _this.dateField.getValue();
58091 // work out monday..
58092 //st = st.add(Date.DAY, -1 * st.format('w'));
58094 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58096 var firstOfMonth = date.getFirstDayOfMonth();
58097 var days = date.getDaysInMonth();
58099 var firstAdded = false;
58100 for (var i = 0; i < result.totalRecords ; i++) {
58101 //var d= st.add(Date.DAY, i);
58104 for(var w = 0 ; w < 7 ; w++){
58105 if(!firstAdded && firstOfMonth != w){
58112 var dd = (d > 0 && d < 10) ? "0"+d : d;
58113 row['weekday'+w] = String.format(
58114 '<span style="font-size: 16px;"><b>{0}</b></span>'+
58115 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
58117 date.format('Y-m-')+dd
58120 if(typeof(_this.tdata[d]) != 'undefined'){
58121 Roo.each(_this.tdata[d], function(r){
58125 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
58126 if(r.parent_id*1>0){
58127 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
58130 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
58131 deactive = 'de-act-link';
58134 row['weekday'+w] += String.format(
58135 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
58137 r.product_id_name, //1
58138 r.when_dt.format('h:ia'), //2
58148 // only do this if something added..
58150 result.records.push(_this.grid.dataSource.reader.newRow(row));
58154 // push it twice. (second one with an hour..
58158 this.fireEvent("load", this, o, o.request.arg);
58159 o.request.callback.call(o.request.scope, result, o.request.arg, true);
58161 sortInfo : {field: 'when_dt', direction : 'ASC' },
58163 xtype: 'HttpProxy',
58166 url : baseURL + '/Roo/Shop_course.php'
58169 xtype: 'JsonReader',
58186 'name': 'parent_id',
58190 'name': 'product_id',
58194 'name': 'productitem_id',
58212 click : function (_self, e)
58214 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58215 sd.setMonth(sd.getMonth()-1);
58216 _this.monthField.setValue(sd.format('Y-m-d'));
58217 _this.grid.ds.load({});
58223 xtype: 'Separator',
58227 xtype: 'MonthField',
58230 render : function (_self)
58232 _this.monthField = _self;
58233 // _this.monthField.set today
58235 select : function (combo, date)
58237 _this.grid.ds.load({});
58240 value : (function() { return new Date(); })()
58243 xtype: 'Separator',
58249 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
58259 click : function (_self, e)
58261 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
58262 sd.setMonth(sd.getMonth()+1);
58263 _this.monthField.setValue(sd.format('Y-m-d'));
58264 _this.grid.ds.load({});
58277 * Ext JS Library 1.1.1
58278 * Copyright(c) 2006-2007, Ext JS, LLC.
58280 * Originally Released Under LGPL - original licence link has changed is not relivant.
58283 * <script type="text/javascript">
58287 * @class Roo.LoadMask
58288 * A simple utility class for generically masking elements while loading data. If the element being masked has
58289 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
58290 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
58291 * element's UpdateManager load indicator and will be destroyed after the initial load.
58293 * Create a new LoadMask
58294 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
58295 * @param {Object} config The config object
58297 Roo.LoadMask = function(el, config){
58298 this.el = Roo.get(el);
58299 Roo.apply(this, config);
58301 this.store.on('beforeload', this.onBeforeLoad, this);
58302 this.store.on('load', this.onLoad, this);
58303 this.store.on('loadexception', this.onLoadException, this);
58304 this.removeMask = false;
58306 var um = this.el.getUpdateManager();
58307 um.showLoadIndicator = false; // disable the default indicator
58308 um.on('beforeupdate', this.onBeforeLoad, this);
58309 um.on('update', this.onLoad, this);
58310 um.on('failure', this.onLoad, this);
58311 this.removeMask = true;
58315 Roo.LoadMask.prototype = {
58317 * @cfg {Boolean} removeMask
58318 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
58319 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
58322 * @cfg {String} msg
58323 * The text to display in a centered loading message box (defaults to 'Loading...')
58325 msg : 'Loading...',
58327 * @cfg {String} msgCls
58328 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
58330 msgCls : 'x-mask-loading',
58333 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
58339 * Disables the mask to prevent it from being displayed
58341 disable : function(){
58342 this.disabled = true;
58346 * Enables the mask so that it can be displayed
58348 enable : function(){
58349 this.disabled = false;
58352 onLoadException : function()
58354 Roo.log(arguments);
58356 if (typeof(arguments[3]) != 'undefined') {
58357 Roo.MessageBox.alert("Error loading",arguments[3]);
58361 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
58362 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
58371 this.el.unmask(this.removeMask);
58374 onLoad : function()
58376 this.el.unmask(this.removeMask);
58380 onBeforeLoad : function(){
58381 if(!this.disabled){
58382 this.el.mask(this.msg, this.msgCls);
58387 destroy : function(){
58389 this.store.un('beforeload', this.onBeforeLoad, this);
58390 this.store.un('load', this.onLoad, this);
58391 this.store.un('loadexception', this.onLoadException, this);
58393 var um = this.el.getUpdateManager();
58394 um.un('beforeupdate', this.onBeforeLoad, this);
58395 um.un('update', this.onLoad, this);
58396 um.un('failure', this.onLoad, this);
58401 * Ext JS Library 1.1.1
58402 * Copyright(c) 2006-2007, Ext JS, LLC.
58404 * Originally Released Under LGPL - original licence link has changed is not relivant.
58407 * <script type="text/javascript">
58412 * @class Roo.XTemplate
58413 * @extends Roo.Template
58414 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
58416 var t = new Roo.XTemplate(
58417 '<select name="{name}">',
58418 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
58422 // then append, applying the master template values
58425 * Supported features:
58430 {a_variable} - output encoded.
58431 {a_variable.format:("Y-m-d")} - call a method on the variable
58432 {a_variable:raw} - unencoded output
58433 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
58434 {a_variable:this.method_on_template(...)} - call a method on the template object.
58439 <tpl for="a_variable or condition.."></tpl>
58440 <tpl if="a_variable or condition"></tpl>
58441 <tpl exec="some javascript"></tpl>
58442 <tpl name="named_template"></tpl> (experimental)
58444 <tpl for="."></tpl> - just iterate the property..
58445 <tpl for=".."></tpl> - iterates with the parent (probably the template)
58449 Roo.XTemplate = function()
58451 Roo.XTemplate.superclass.constructor.apply(this, arguments);
58458 Roo.extend(Roo.XTemplate, Roo.Template, {
58461 * The various sub templates
58466 * basic tag replacing syntax
58469 * // you can fake an object call by doing this
58473 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
58476 * compile the template
58478 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
58481 compile: function()
58485 s = ['<tpl>', s, '</tpl>'].join('');
58487 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
58488 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
58489 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
58490 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
58491 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
58496 while(true == !!(m = s.match(re))){
58497 var forMatch = m[0].match(nameRe),
58498 ifMatch = m[0].match(ifRe),
58499 execMatch = m[0].match(execRe),
58500 namedMatch = m[0].match(namedRe),
58505 name = forMatch && forMatch[1] ? forMatch[1] : '';
58508 // if - puts fn into test..
58509 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
58511 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
58516 // exec - calls a function... returns empty if true is returned.
58517 exp = execMatch && execMatch[1] ? execMatch[1] : null;
58519 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
58527 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
58528 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
58529 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
58532 var uid = namedMatch ? namedMatch[1] : id;
58536 id: namedMatch ? namedMatch[1] : id,
58543 s = s.replace(m[0], '');
58545 s = s.replace(m[0], '{xtpl'+ id + '}');
58550 for(var i = tpls.length-1; i >= 0; --i){
58551 this.compileTpl(tpls[i]);
58552 this.tpls[tpls[i].id] = tpls[i];
58554 this.master = tpls[tpls.length-1];
58558 * same as applyTemplate, except it's done to one of the subTemplates
58559 * when using named templates, you can do:
58561 * var str = pl.applySubTemplate('your-name', values);
58564 * @param {Number} id of the template
58565 * @param {Object} values to apply to template
58566 * @param {Object} parent (normaly the instance of this object)
58568 applySubTemplate : function(id, values, parent)
58572 var t = this.tpls[id];
58576 if(t.test && !t.test.call(this, values, parent)){
58580 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
58581 Roo.log(e.toString());
58587 if(t.exec && t.exec.call(this, values, parent)){
58591 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
58592 Roo.log(e.toString());
58597 var vs = t.target ? t.target.call(this, values, parent) : values;
58598 parent = t.target ? values : parent;
58599 if(t.target && vs instanceof Array){
58601 for(var i = 0, len = vs.length; i < len; i++){
58602 buf[buf.length] = t.compiled.call(this, vs[i], parent);
58604 return buf.join('');
58606 return t.compiled.call(this, vs, parent);
58608 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
58609 Roo.log(e.toString());
58610 Roo.log(t.compiled);
58615 compileTpl : function(tpl)
58617 var fm = Roo.util.Format;
58618 var useF = this.disableFormats !== true;
58619 var sep = Roo.isGecko ? "+" : ",";
58620 var undef = function(str) {
58621 Roo.log("Property not found :" + str);
58625 var fn = function(m, name, format, args)
58627 //Roo.log(arguments);
58628 args = args ? args.replace(/\\'/g,"'") : args;
58629 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
58630 if (typeof(format) == 'undefined') {
58631 format= 'htmlEncode';
58633 if (format == 'raw' ) {
58637 if(name.substr(0, 4) == 'xtpl'){
58638 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
58641 // build an array of options to determine if value is undefined..
58643 // basically get 'xxxx.yyyy' then do
58644 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
58645 // (function () { Roo.log("Property not found"); return ''; })() :
58650 Roo.each(name.split('.'), function(st) {
58651 lookfor += (lookfor.length ? '.': '') + st;
58652 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
58655 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
58658 if(format && useF){
58660 args = args ? ',' + args : "";
58662 if(format.substr(0, 5) != "this."){
58663 format = "fm." + format + '(';
58665 format = 'this.call("'+ format.substr(5) + '", ';
58669 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
58673 // called with xxyx.yuu:(test,test)
58675 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
58677 // raw.. - :raw modifier..
58678 return "'"+ sep + udef_st + name + ")"+sep+"'";
58682 // branched to use + in gecko and [].join() in others
58684 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
58685 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
58688 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
58689 body.push(tpl.body.replace(/(\r\n|\n)/g,
58690 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
58691 body.push("'].join('');};};");
58692 body = body.join('');
58695 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
58697 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
58703 applyTemplate : function(values){
58704 return this.master.compiled.call(this, values, {});
58705 //var s = this.subs;
58708 apply : function(){
58709 return this.applyTemplate.apply(this, arguments);
58714 Roo.XTemplate.from = function(el){
58715 el = Roo.getDom(el);
58716 return new Roo.XTemplate(el.value || el.innerHTML);